135 votes

Comment renvoyer la réponse d'un appel Observable / http / async en angulaire?

J'ai un service qui renvoie un observable qui envoie une requête http à mon serveur et récupère les données. Je veux utiliser ces données mais je finis toujours par obtenir undefined . Quel est le problème?

Service :

 @Injectable()
export class EventService {

  constructor(private http: Http) { }

  getEventList(): Observable<any>{
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });

    return this.http.get("http://localhost:9999/events/get", options)
                .map((res)=> res.json())
                .catch((err)=> err)
  }
}
 

Composant:

 @Component({...})
export class EventComponent {

  myEvents: any;

  constructor( private es: EventService ) { }

  ngOnInit(){
    this.es.getEventList()
        .subscribe((response)=>{
            this.myEvents = response;
        });

    console.log(this.myEvents); //This prints undefined!
  }
}
 

135voto

echonax Points 2077

Raison:

La raison pour laquelle il est undefined , c'est que vous faites une opération asynchrone. Sens ça va prendre un certain temps pour terminer l' getEventList méthode (notamment en fonction de la vitesse du réseau).

Donc, permet de regarder le http appel.

this.es.getEventList()

Après vous avez réellement faire ("feu") de votre requête http avec subscribe vous sera d'attente pour la réponse. En attendant, javascript, exécuter les lignes en dessous de ce code et si elle rencontre synchrone/missions opérations, il va les exécuter immédiatement.

Ainsi, après l'abonnement à l' getEventList() et l'attente de la réponse,

console.log(this.myEvents);

la ligne sera exécuté immédiatement. Et la valeur est undefined avant que la réponse arrive sur le serveur (ou à tout ce que vous avez initialisé en premier lieu).

Il est similaire à faire:

ngOnInit(){
    setTimeout(()=>{
        this.myEvents = response;
    }, 5000);

    console.log(this.myEvents); //This prints undefined!
}


Solution:

Alors, comment pouvons-nous surmonter ce problème? Nous allons utiliser la fonction de callback qui est l' subscribe méthode. Parce que lorsque les données arrivent à partir du serveur, il va être à l'intérieur de l' subscribe de la réponse.

Modification du code pour:

this.es.getEventList()
    .subscribe((response)=>{
        this.myEvents = response;
        console.log(this.myEvents); //<-- not undefined anymore
    });

imprime la réponse.. après un certain temps.


Ce que vous devez faire:

Il pourrait y avoir beaucoup de choses à faire avec votre réponse autre que de simplement leur enregistrement; vous devez faire toutes ces opérations à l'intérieur de la fonction de rappel (à l'intérieur de l' subscribe de la fonction), lorsque les données arrivent.

Une autre chose à mentionner est que si vous venez d'un Promise d'arrière-plan, l' then de rappel correspond à subscribe avec observables.


Ce que vous ne devriez pas le faire:

Vous ne devriez pas essayer de changer une opération asynchrone à une opération de synchronisation (non pas que vous le pouvez). L'une des raisons pour lesquelles nous avons des opérations asynchrones est de ne pas permettre à l'utilisateur d'attente pour une opération se termine alors qu'ils peuvent faire d'autres choses dans cette période de temps. Supposons que l'un de vos opérations asynchrones prend 3 minutes pour le remplir, si nous n'avions pas les opérations asynchrones l'interface serait gelé pendant 3 minutes.


Suggestions De Lecture:

L'original de crédit à cette réponse va à l': Comment puis-je retourner la réponse d'un appel asynchrone?

Mais avec le angular2 de presse, on nous a présenté tapuscrit et observables donc cette réponse espérons-le, couvre les bases de la gestion d'une requête asynchrone avec observables.

15voto

RAVI PATEL Points 257

Faire un appel http en angulaire / javascript est une opération asynchrone. Ainsi, lorsque vous passez un appel http, il assignera un nouveau thread pour terminer cet appel et lancer l'exécution à la ligne suivante avec un autre thread. C'est pourquoi vous obtenez une valeur indéfinie. alors faites ci-dessous le changement pour résoudre ce problème

 this.es.getEventList()  
      .subscribe((response)=>{  
       this.myEvents = response;  
        console.log(this.myEvents); //<-this become synchronous now  
    });
 

7voto

Kliment Ru Points 575

Vous pouvez utiliser asyncPype si vous utilisez myEvents uniquement dans un modèle.

Voici un exemple avec asyncPype et Angular4 HttpClient https://stackblitz.com/edit/angular-rhioqt?file=app%2Fevent.service.ts

3voto

Suneet Bansal Points 1895

Ici, le problème est que vous initialisez this.myEvents en subscribe() qui est un bloc asynchrone alors que vous effectuez un console.log() juste en dehors du bloc subscribe() . Donc, console.log() appelé avant this.myEvents est initialisé.

Veuillez déplacer votre code console.log () aussi à l'intérieur de subscribe () et vous avez terminé.

 ngOnInit(){
    this.es.getEventList()
        .subscribe((response)=>{
            this.myEvents = response;
            console.log(this.myEvents);
        });
  }
 

2voto

luukgruijs Points 61

Assurez-vous également de mapper votre réponse sur une sortie JSON. Sinon, le texte brut sera renvoyé. Vous le faites comme ceci:

 getEventList(): Observable<any> {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });

return this.http.get("http://localhost:9999/events/get", options)
            .map((res)=>{ return res.json();}) <!-- add call to json here
            .catch((err)=>{return err;})
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X