0

Observables are a stream and will execute and complete when they are done. Fair enough. In one component with multiple API calls using a service, can anything be done to ensure that one observable completes before another starts?

So in the below example, what can be done to make sure that getOptions completes before getReport is started. getReport relies on data being obtained by getOptions.

  ngOnChanges() {
    if (this.treeResult != null) {              
      for (var index = 0; index < this.treeResult.length; index++) {        
        var element = this.treeResult[index];               
          this.thumbnailView = null;

          this.getOptions(element.id);            

          this.getReport(element.id, this.a, this.b, element.c);              
      }
    }
  }

  getOptions(id: number) {
    this._Service.GetOptions(id)
      .subscribe(options => { this.select = options[0].Options1, this.num = options[0].Options1[0].optionId,
                              error => this.errorMessage = <any>error)
  }  

  getReport(id: number, a: number, b: number, c: string) {
    this._Service.GetReport(id, a, b, c)
      .subscribe(data => { this.data = data }, error => this.errorMessage = <any>error);
  }

Happy to supply more info if needed

Maximilian Riegler
  • 22,720
  • 4
  • 62
  • 71
Daniel
  • 139
  • 1
  • 13
  • Possible duplicate of [Angular 2: Two backend service calls on success of first service](http://stackoverflow.com/questions/36712659/angular-2-two-backend-service-calls-on-success-of-first-service) – eko Jul 18 '16 at 10:26

2 Answers2

0

Yes. Call the second observable within the done() method of the first observable :

 ngOnChanges() {
    if (this.treeResult != null) {              
      for (var index = 0; index < this.treeResult.length; index++) {        
        var element = this.treeResult[index];               
          this.thumbnailView = null;

          this.getOptions(element.id, element.c);                       
      }
    }
  }

  getOptions(id: number, c : any) {
    this._Service.GetOptions(id)
      .subscribe(options => { 
              this.select = options[0].Options1;
              this.num = options[0].Options1[0].optionId;
          }, error => {
              this.errorMessage = <any>error;
          }, () => {
              // done
              this.getReport(id, this.a, this.b, c);
          });
  }  

  getReport(id: number, a: number, b: number, c: string) {
    this._Service.GetReport(id, a, b, c)
      .subscribe(data => { 
               this.data = data;
          }, error => {
              this.errorMessage = <any>error;
          }, () => {
              // done
          });
  }
Colum
  • 996
  • 2
  • 8
  • 23
0

You could leverage the flatMap operator to execute observables in series.

Here is the way to use it in your case:

  ngOnChanges() {
    if (this.treeResult != null) {              
      this.treeResult.forEach(element => {
        this.thumbnailView = null;

        this.getOptions(element.id).flatMap(() => { // <------
          this.getReport(element.id, this.a, this.b, element.c);
        }).subscribe();
      });
    }
  }

  getOptions(id: number) {
    return this._Service.GetOptions(id)
      .map(options => { // <-----
        this.select = options[0].Options1;
        this.num = options[0].Options1[0].optionId
      })
      .catch(error => this.errorMessage = <any>error);
  }  

  getReport(id: number, a: number, b: number, c: string) {
    return this._Service.GetReport(id, a, b, c)
      .map(data => {
        this.data = data;
      })
      .catch(error => this.errorMessage = <any>error);
  }
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360