简体   繁体   English

Angular-从Promise同步获取

[英]Angular - get synchronously from Promise

I want to print history of products. 我想打印产品的历史记录。 I have an id of product in ActivatedRoute.params. 我在ActivatedRoute.params中有一个产品ID。 In ngOnInit method I have to get all history of product and assign to variable. 在ngOnInit方法中,我必须获取产品的所有历史记录并分配给变量。 Then I want to map product to productHistory, because I want to have last version with history toghether. 然后,我想将产品映射到productHistory,因为我想要具有历史记录的最新版本。 But the problem is with getting history. 但是问题在于获取历史记录。 Method to getting history return Promise and I cannot get length of productsHistory when I use this property and I get undefined. 获取历史记录的方法返回Promise,当我使用此属性且未定义时,我无法获得productHistory的长度。 How can I get this property after loading from service? 从服务加载后如何获得此属性?

I want to execute method after execution getHistory(). 我想在执行getHistory()之后执行方法。

My code: 我的代码:

ProductService.ts: ProductService.ts:

import { Injectable } from '@angular/core';
import { Headers, Http } from '@angular/http';

import 'rxjs/add/operator/toPromise';

// rest imports

@Injectable()
export class ProductService {

    // URL to web api
    private projectsUrl = 'http://localhost:8080/products';

    private headers = new Headers({'Content-Type': 'application/json'});

    constructor(private http: Http) {}

    getHistory(id: number): Promise<ProductHistory[]> {
        const url = `${this.projectsUrl}/projectId/${id}`;
        return this.http.get(url)
            .toPromise()
            .then(response => response.json() as ProductHistory[])
            .catch(this.handleError);
    }

    handleError() {
        //...
        // implementation is irrelevant
    }
}

ProductHistoryComponent.ts: ProductHistoryComponent.ts:

import { Component, Input, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { Location } from '@angular/common';

import { ProductService } from './product.service';

import { ProductHistory } from './product-history';
import { Product } from './model/product';

import 'rxjs/add/operator/switchMap';

@Component({
    selector: 'product-history',
    templateUrl: './product-history.component.html',
    styleUrls: [ './product-history.component.css' ]
})
export class ProductHistoryComponent implements OnInit {

    auditProducts: ProductHistory[] = new Array<ProductHistory[]>();    
    selectedProduct: ProductHistory;

    constructor(
        private route: ActivatedRoute,
        private location: Location,
        private productService: ProductService
    ) {}

    ngOnInit(): void {
        let id: number = this.route.snapshot.params['id'];

        this.productService.getHistory(id)
            .then(history => this.historyProducts = history);

        this.productService.getProduct(id)
            .then(product => {
                let lastVersion: ProductHistory = this.createLastVersion(product);
                this.auditProducts.push(lastVersion);
            });
    }

    onSelect(ProductHistory: ProductHistory): void {
        this.selectedProduct = ProductHistory;
        this.compare(this.selectedProduct);
    }

    goBack(): void {
        this.location.back();
    }

    compare(history: ProductHistory): void {
        let previous: ProductHistory;
        if (history.changeNumber != null && history.changeNumber > 1) {
            previous = this.historyProducts[history.changeNumber - 2];
            if (typeof previous != 'undefined') {
                this.setPreviousDiffsFalse(previous);
                if (previous.name !== history.name) {
                    history.nameDiff = true;
                }
                if (previous.price !== history.price) {
                    history.priceDiff = true;
                }
            }
        }
    }

    createLastVersion(product: Product): ProductHistory {
        let lastVersionProduct: ProductHistory = new ProductHistory();
        lastVersionProduct.id = this.historyProducts.length + 1;
        lastVersionProduct.name = product.name;
        lastVersionProduct.price = product.price;
        lastVersionProduct.changeNumber = this.historyProducts[this.historyProducts.length - 1].changeNumber + 1;
        return lastVersionProduct;
    }

    setPreviousDiffsFalse(previous: ProductHistory): void {
        previous.nameDiff = false;
        previous.priceDiff = false;
    }

}

I would suggest using observables instead of promises ... but to answer your question, you just need to perform the second request after the first is received. 我建议使用observables代替promise ...但是要回答您的问题,您只需要收到第一个请求执行第二个请求即可。 Something like this: 像这样:

ngOnInit(): void {
    let id: number = this.route.snapshot.params['id'];

    this.productService.getHistory(id)
        .then(history => {
               this.historyProducts = history);

               this.productService.getProduct(id)
                     .then(product => {
                         let lastVersion: ProductHistory = this.createLastVersion(product);
                         this.auditProducts.push(lastVersion);
        });
     }
}

I just moved the second request within the then of the first request. 我刚搬到 ,则第一个请求的第二请求。 NOTE: I did not syntax check this. 注意:我没有语法检查此。

You can't run it synchronously, you have to wait for each promise to return a result before you can do something with that result. 您不能同步运行它,您必须等待每个promise返回一个结果,然后才能对该结果执行某些操作。 The normal way to do this is to nest code inside then blocks when using promises. 通常的方法是在使用promise时将代码嵌套在then块中。 Alternatively you can also use async/await with the latest version of typescript and you only have to change your component code as you are already returning the Promise type from your service. 另外,您也可以将async/await与最新版本的Typescript一起使用,并且只需要更改component代码,因为您已经从服务中返回Promise类型。 This makes code easier to read (IMO) although the emitted javascript code will still use function/callback nesting ( unless you are targeting es7 I believe, maybe someone will correct or confirm this ). 尽管发出的javascript代码仍将使用函数/回调嵌套,这使代码更易于阅读(IMO)( 除非我相信您以es7为目标,否则也许有人会对此进行纠正或确认 )。

// note the use of async and await which gives the appearance of synchronous execution
async ngOnInit() {
    let id: number = this.route.snapshot.params['id'];

    const history = await this.productService.getHistory(id);
    this.historyProducts = history;

    const product = await this.productService.getProduct(id);
    let lastVersion: ProductHistory = this.createLastVersion(product);
    this.auditProducts.push(lastVersion);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM