S. Beliadsi
S. Beliadsi

Reputation: 43

Angular 5 combining and chaining parallel calls with forkJoin not working

I am looking for a way to do some action after all controls on a page are loaded. These controls are loaded in parallel by calling http get.

I tried code similar to the one below but it doesn't seem to do the trick. If it worked correctly, the sometext should display 'done'. It doesn't. I am not sure I understand correctly how the forkJoin works. I used to do this kind of chaining in Angular 1.x using promises. Any help in understanding the problem and a solution is appreciated.

The solution I am looking for is similar to this question for Angular 1.x: Angular combining parallel and chained requests with $http.then() and $q.all()

Complete code is at http://plnkr.co/edit/xH6VJo

Source is src/dash.ts

This is Angular 5 and typescript.

export class dash implements OnInit {
  sometext = 'Some text ...';
  private httpOptions = {
    headers: new HttpHeaders({ 'Content-Type': 'application/json' })
  };
  constructor(private http: HttpClient) {}
  click_me(): void {
    this.sometext = '';
    forkJoin([
      of(this.first_()),
      of(this.second_())
      ]).subscribe(val => {
        this.sometext = 'done...';
      })
  }
  first_(): void {
    this.http.get<any>('data/sampledata.json',this.httpOptions).subscribe(val=> {
    this.sometext = val.items[0].value;
    });
  }
  second_(): void {
    this.http.get<item[]>('data/sampledata.json',this.httpOptions).subscribe(val=> {
    this.sometext = val.items[1].value;
    });
  }
}

Upvotes: 1

Views: 2844

Answers (1)

CozyAzure
CozyAzure

Reputation: 8478

The main reason is because your first() and second() doesn't return an Observable. .forkJoin() can only take in an array of Observables, fire them in parallel, and then it has to wait for all observables to complete before it starts to emit the resultant values. The main reason your complete() handler never gets executed is because there is no Observables in the .forkJoin() in the first place, hence none of them can complete, and your .forkJoin() will never emit.

Here's what you should do. For first() and second(), have them return an observable. If you want to change the this.sometext when both of them executes, use the operator .do():

first_(): Observable<any> {
    this.http.get<any>('data/sampledata.json', this.httpOptions)
        .do(val => {
            this.sometext = val.items[0].value;
        });
}

second_(): Observable<any> {
    this.http.get<item[]>('data/sampledata.json', this.httpOptions)
        .do(val => {
            this.sometext = val.items[1].value;
        });
}

Now your click_me() should be working fine:

click_me(): void {
    this.sometext = '';
    forkJoin([
        of(this.first_()),
        of(this.second_())
    ]).subscribe(val => {
        this.sometext = 'done...';
    })
}

Note that since Observable.forkJoin() fires their requests in parallel, there is NO GUARANTEE that your first() will be executed before your second().

Upvotes: 5

Related Questions