2
votes

Comment synchroniser les requêtes http.get dans Angular, lorsque la seconde requête dépend de la première?

Je dois effectuer une séquence de requêtes http vers ma base de données depuis Angular. Dans la première étape, j'obtiens un tableau d'objets. Cela fonctionne bien. Dans un deuxième temps, je souhaite remplir chaque objet avec des données supplémentaires. Je dois donc attendre la fin du premier http.request. Je ne veux pas non plus revenir avant que mes données aient été récupérées.

Ma fonction getData () devrait renvoyer un Observable, car l'interface / signature n'est pas censée changer (car elle est utilisé dans d'autres parties du programme et un observable a un sens pour la logique du programme).

// Returns an array with objects, that have an id, that is needed for the second call 

data[] : Object = new Array(); 
populatedData[] : Object = new Array();


getData(): Observable<Object[]>{
  this.http.get<Object[]>("http://localhost:3000/data").subscribe(data => this.data = data);

// This needs the data from the first call 
 for(int i = 0; i < data.length; i++){
this.http.get<Object>("http://localhost:3000/data/"+data[i].id).subscribe(data => populatedData.push(data)); 
}


return of(populatedData); 

}


0 commentaires

4 Réponses :


0
votes

Vous devriez mettre le code qui nécessite le premier appel dans le deuxième

data: Array<any> = []; 
populatedData: Array<any> = []; 



getData(): Observable<Object[]> {
    this.http.get<Object[]>('http://localhost:3000/data').subscribe(data => {
        this.data = data;
        for (let i = 0; i < data.length; i++) {
            this.http
                .get<Object>('http://localhost:3000/data/' + data[i].id)
                .subscribe(data => populatedData.push(data));
        }
    });

    return of(populatedData);
}


3 commentaires

Le type de retour d'une fonction asynchrone doit être une promesse.


L'observable getData renvoyé est résolu avant même que la première requête ne soit terminée, et encore moins la dernière.


Non. Il devrait émettre une fois les demandes terminées, pas avant leur envoi. L'abonné de getData recevra - immédiatement - un tableau vide.



2
votes

La promesse est une option, mais une autre option peut être,

// Returns an array with objects, that have an id, that is needed for the second call 
   data[] : Object = new Array(); 
   populatedData[] : Object = new Array();

  getData(): Observable<Object[]>{
     this.http.get<Object[]>("http://localhost:3000/data").subscribe((data)=>{
      this.data = data;
             for(int i = 0; i < data.length; i++){
                  this.http.get<Object>("http://localhost:3000/data/"+data[i].id).subscribe((response)=> {
                          populatedData.push(response)
                   }); 
             }
         });
      return of(populatedData); 
    }


0 commentaires

3
votes

Vous pouvez utiliser switchMap (une fois le GET initial terminé, effectuer les autres requêtes) et forkJoin (faire plusieurs requêtes et émettre lorsque tout est terminé). Quelque chose comme ceci:

    getSingleEntry = ({ id }) => this.http.get<Object[]>("http://localhost:3000/data/" + id);

    getData = () => this.http.get<Object[]>("http://localhost:3000/data")
        .pipe(
            tap(data => this.data = data),
            switchMap(data => forkJoin(data.map(this.getSingleEntry)));


0 commentaires

0
votes

Je pense que la meilleure idée est d'utiliser l'opérateur switchMap RXJS et zip . Lors des seconds appels, vous avez accès aux données du premier. Ensuite, vous pouvez renvoyer un tableau de valeurs lorsque tous les appels sont terminés.

En savoir plus sur switchMap vous pouvez lire ici . À propos de zip ici .

Voici un exemple à quoi ressembleront les données https://rxviz.com/v/Mogdv96O

Ensuite, votre code sera refactorisé comme suit:

  getData(): Observable<Object[]> {
    this.http.get<Object[]>("http://localhost:3000/data")
      .pipe(switchMap((data) =>
              zip(...data.map(item => this.http.get<Object>("http://localhost:3000/data/" + item.id)))
            )
      );
  }


0 commentaires