Meik Vtune
Meik Vtune

Reputation: 490

Angular: Right way to wait for Async data to be loaded

I have to make multiple API calls(http-requests) to get all the data I need.

Since I have to make 2 independent API calls that both should be finished with retrieving data, I am trying to sync to that.

I have nearly 0 experience in typescript/angular and couldn't find a solution via google.

Here are the API calls I'm making(signatures):

public supportedLanguages(observe?: 'body', reportProgress?: boolean): Observable<Array<string>>;
public getAllFilters(acceptLanguage?: string, observe?: 'body', reportProgress?: boolean): Observable<Array<Filter>>;

Here is the code I am currently using to fill Array<Type>:

this.langService.supportedLanguages().subscribe(langs => setTimeout(() =>
  this.langs.push(...langs), 1000));
this.categorieService.getAllFilters('de').subscribe(categories => setTimeout(() => {
  this.categories.push(...categories), 1000));

I am guessing that this is not the right approach to retrieving the data, but I haven't found a better way(I am very new to typescript/angular).

What are the right steps to take to wait for said data to be loaded?

Upvotes: 2

Views: 4464

Answers (5)

Kingsley
Kingsley

Reputation: 805

You could also just use a combination of async, await and promises.
First you'd have to append .toPromise() to your service methods. Then in your component.ts file add the following method...

private async fetchData() {
  return await Promise.all([
    this.langService.supportedLanguages();
    this.categoryService.getAllFilters();
  ]).then(res => {
    this.langs.push(res[0]);   //res[0] is data returned by API supportedLanguages
    this.categories.push(res[1]); //res[1] is data returned by API getAllFilters
    this.status = true; // Confirms that now you have all your data back
  }
}

Call this.fetchData() inside ngOnInit()

Then maybe you'd have a status variable that you'd initialize to false and then set to true once all the data has been returned.

Upvotes: 1

Kevin
Kevin

Reputation: 302

You can use

(I am using "rxjs": "^5.5.11").

forkJoin

import 'rxjs/add/observable/forkJoin';
import { Observable } from 'rxjs';
import { Subscription } from 'rxjs/Subscription';


/* Multiple Service calls are asynchronism. use forkJoin to group service calls */  
Observable.forkJoin(
  this.supportedLanguages();
  this.getAllFilters()
).subscribe(
    response =>{
      //response[0] is data returned by API supportedLanguages
      //response[1] is data returned by API getAllFilters
    }
    error => console.log("Error: ", error),
    () =>{
      //All the API calls are completed here. Put your code here
      //codes should be executed after the completion of all API calls
    }
)

Upvotes: 4

Muhammad Al Faris
Muhammad Al Faris

Reputation: 346

If you want call the API in same times and return in same times, you could use ForkJoin from rxjs, see about the documentation

forkJoin(
    this.langService.supportedLanguages(),
    this.categorieService.getAllFilters('de'))
).subscribe(x => 
console.log(x[0]); //result from api call 1
console.log(x[1]); //result from api call 2
 )

but if you want call first api, then after first api finish, you want call the second api. you could use concatMap, see about documentation here, concat map used maybe when your second api, need parameter from first

this.langService.supportedLanguages().pipe( 
 concatMap(resultFromApi1 => this.categorieService.getAllFilters('de'))
).subscribe(x => console.log(x)) //x = result from api 2;

I have nearly 0 experience in typescript/angular and couldn't find a solution via google.

you must try different way, cause angular not only angular. like 'rxjs' and other.. you need know what library js you used. and carefully with version, cause the angular really - really confusing about version and have different because the structure writing is a little different

Upvotes: 0

veben
veben

Reputation: 22262

You can use ForkJoin from Rxjs 6:

import {forkJoin} from 'rxjs';

// ...

forkJoin(
    this.langService.supportedLanguages(),
    this.categorieService.getAllFilters('de'))
).subscribe([langs, categories] => {
  // ...
})

OR, you can put the 2 API calls in a Promise:

function recoverData() {
    return new Promise((resolve, reject) => {
        this.langService.supportedLanguages().subscribe(langs => this.langs.push(...langs), 1000);
        this.categorieService.getAllFilters('de').subscribe(categories => this.categories.push(...categories), 1000);

        resolve();
    });
}

And then you use it like that:

recoverData().then(() => {
    // Some code
});

Upvotes: 0

ABOS
ABOS

Reputation: 3823

you can try forkJoin from rxjs:

forkJoin(
    this.langService.supportedLanguages(),
    this.categorieService.getAllFilters('de'))
)
.subscribe([langs, categories]=>{
  ...
})

Upvotes: 1

Related Questions