简体   繁体   中英

TypeScript: Send multiple HTTP requests sequentially Angular2

I am sending a request to Web API and sending again another request to the same API based on the return value from first API return. Then I am trying to map the Web API components to a class, but map method doesn't wait for second call to return. Please help that how can i map after successful return of both calls?

Below is my code

getOrderDetail(orderId: string): Observable<OrderHeader> {

return this.svc.wCWebClientServiceGetOrderDetails({ _orderId: orderId })
  .do(order => {
    order.SalesLines.forEach(saleLine => {
      if (saleLine.RelatedOrders !== undefined && saleLine.RelatedOrders.length > 0) {
        saleLine.RelatedOrders.forEach(relatedOrder => {
          this.svc.wCWebClientServiceGetOrderDetails({ _orderId: relatedOrder.TransId })
            .subscribe(relOrder => {
              //debugger;
              relOrder.SalesLines.forEach(relLine => {
                order.SalesLines.push(relLine);
              });
            })
        });
      }
    })
  })
  //.do(order => console.log('Received order', order))
  .map(order => this.transformOrder(order));

}

You can use an RxJs operator called MergeMap also known as flatMap to map/iterate over the Observable values.

import { Component } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { mergeMap } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  templateUrl: 'app/app.component.html'
})
export class AppComponent {
  homeworld: Observable<{}>;
  constructor(private http: HttpClient) { }

  ngOnInit() {
    this.homeworld = this.http.get('/api/people/1').pipe(
      mergeMap(character => this.http.get(character.homeworld))
    );
  }
}

So in our example when we get the homeworld, we are getting back an Observable inside our character Observable stream. This creates a nested Observable in an Observable. The mergeMap operator helps us by subscribing and pulling the value out of the inner Observable and passing it back to the parent stream.

For more you can checkout this blog: Angular Multiple HTTP Requests with RxJS

This flatMap operator, in conjunction with forkJoin should do the trick..

getOrderDetail(orderId: string): Observable<OrderHeader> {
    return this.svc.wCWebClientServiceGetOrderDetails({ _orderId: orderId })
    .flatMap(order => {
        order.SalesLines.forEach(saleLine => {
            let observables:Array<Observable<any>> = [];

            if ( /* Your predicate */ ) {
                saleLine.RelatedOrders.forEach(relatedOrder => {
                    observables.push(this.svc.wCWebClientServiceGetOrderDetails({ _orderId: relatedOrder.TransId }));
                });
            }

            // Perform the calls to retrieve order details asynchronously
            return Observable.forkJoin(observables).map((results:Array<any>) => {
                 results.forEach(relOrder => {
                    relOrder.SalesLines.forEach(relLine => {
                        order.SalesLines.push(relLine);
                    });
                 });
            });
        });
    })
    // Perform your final transformation on the results
    .map(order => this.transformOrder(order));
}

I believe what you're looking for is the expand method.

Here's an example of my own:

VA7B(params: VA7B, accountList: any, balanceSequenceList: string[], docNumber: string) {
        const sequenceList = [...balanceSequenceList];

        // Função que define o código do balanço financeiro para a conta atual
        const setBalanceCode = () => {
            params.balance.accountNumberRecalled = StringFormat.padLeft('', 7);
            params.balance.demoAccountNumber = sequenceList[0];
            sequenceList.shift();
        };

        const total = accountList.reduce((acc: any, curr: any) => acc + curr.length, 0);

        // Função que realiza a requisição RESTFUL ao servidor.
        const post = (account: string): Observable<VA7BResponse> => {
            const payload: PayLoad<VA7B> = new PayLoad<VA7B>();

            params.balance.document.number = docNumber;
            payload.obj = params;
            payload.obj.balance.accountData = account;

            payload.url = 'url_VA7B';
            payload.result = VA7BResponse;
            payload.hasCripto = this.hasCripto;
            payload.criptoFields = [{ balance: Object, document: Object, number: String }];
            payload.decriptoFields = [];

            return this.baseService.POST<VA7B>(payload);
        };

        setBalanceCode();

        // O método 'expand' é responsável por chamar a função REST recursivamente, caso ainda hajam contas a ser importadas.
        return post(accountList[0][0])
            .expand((res: VA7BResponse) => {
                params.balance.accountNumberRecalled = accountList[0][0].substr(-25, 7);
                accountList[0].shift(); // Após ser importado, o primeiro item é removido da lista.

                // Caso a primeira lista esteja vazia, remove a lista e passa para o próximo demonstrativo.
                if (accountList[0].length === 0) {
                    accountList.shift();
                    setBalanceCode();

                    // Caso não hajam mais balanços, encerra o processo e retorna.
                    if (accountList.length === 0) {
                        return Observable.empty();
                    }
                }

                return post(accountList[0][0]);
            }).take(total);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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