Angular2 http.get (), map (), subscribe () und beobachtbares Muster - Grundverständnis

170

Jetzt habe ich eine erste Seite, auf der ich drei Links habe. Sobald Sie auf den letzten Link "Freunde" klicken, wird die entsprechende Freundeskomponente initiiert. Dort möchte ich eine Liste meiner Freunde abrufen / abrufen, die in der Datei friends.json gespeichert ist. Bis jetzt funktioniert alles gut. Aber ich bin immer noch ein Neuling für den HTTP-Dienst von angle2, der das Observable-, Map- und Subscribe-Konzept von RxJs verwendet. Ich habe versucht, es zu verstehen und einige Artikel zu lesen, aber bis ich in die praktische Arbeit komme, werde ich diese Konzepte nicht richtig verstehen.

Hier habe ich bereits plnkr gemacht, das außer HTTP-bezogene Arbeit funktioniert.

Plnkr

myfriends.ts

 import {Component,View,CORE_DIRECTIVES} from 'angular2/core';
 import {Http, Response,HTTP_PROVIDERS} from 'angular2/http';
 import 'rxjs/Rx';
 @Component({
    template: `
    <h1>My Friends</h1>
    <ul>
      <li *ngFor="#frnd of result">
          {{frnd.name}} is {{frnd.age}} years old.
      </li>
    </ul>
    `,
    directive:[CORE_DIRECTIVES]
  })

  export class FriendsList{

      result:Array<Object>; 
      constructor(http: Http) { 
        console.log("Friends are being called");

       // below code is new for me. So please show me correct way how to do it and please explain about .map and .subscribe functions and observable pattern.

        this.result = http.get('friends.json')
                      .map(response => response.json())
                      .subscribe(result => this.result =result.json());

        //Note : I want to fetch data into result object and display it through ngFor.

       }
  }

Bitte führen und erklären Sie richtig. Ich weiß, dass es für viele neue Entwickler von großem Nutzen sein wird.

Nyks
quelle

Antworten:

205

Hier haben Sie sich geirrt:

this.result = http.get('friends.json')
                  .map(response => response.json())
                  .subscribe(result => this.result =result.json());

es sollte sein:

http.get('friends.json')
                  .map(response => response.json())
                  .subscribe(result => this.result =result);

oder

http.get('friends.json')
                  .subscribe(result => this.result =result.json());

Sie haben zwei Fehler gemacht:

1- Sie haben das Observable selbst zugewiesen this.result. Wenn Sie die Liste der Freunde tatsächlich zuweisen wollten this.result. Der richtige Weg, dies zu tun, ist:

  • Sie abonnieren das Observable. .subscribeist die Funktion, die das Observable tatsächlich ausführt. Es werden drei Rückrufparameter wie folgt benötigt:

    .subscribe(success, failure, complete);

beispielsweise:

.subscribe(
    function(response) { console.log("Success Response" + response)},
    function(error) { console.log("Error happened" + error)},
    function() { console.log("the subscription is completed")}
);

Normalerweise nehmen Sie die Ergebnisse aus dem Erfolgsrückruf und weisen sie Ihrer Variablen zu. Der Fehlerrückruf ist selbsterklärend. Der vollständige Rückruf wird verwendet, um festzustellen, ob Sie die letzten Ergebnisse fehlerfrei erhalten haben. Auf Ihrem Plunker wird der vollständige Rückruf immer entweder nach dem erfolgreichen oder dem fehlerhaften Rückruf aufgerufen.

2- Der zweite Fehler, genannt Sie .json()auf .map(res => res.json()), dann sind Sie es wieder auf den Erfolg Rückruf des beobachtbaren genannt. .map()ist ein Transformator, der das Ergebnis in alles umwandelt, was Sie (in Ihrem Fall .json()) zurückgeben, bevor es an den Erfolgsrückruf übergeben wird. Sie sollten es einmal auf einem von beiden aufrufen.

Abdulrahman Alsoghayer
quelle
2
Hier gehst du dein Plunker . Ich habe die Zeilen geändert: 21, 23 auf myfriends.ts
Abdulrahman Alsoghayer
1
Was ich nicht verstanden habe ist, warum hier überhaupt die "Map" -Funktion verwendet wird? Wir könnten einfach die .json für das Ergebnis aufrufen. Was ist der Vorteil davon?
Rubmz
5
Sie haben Recht @rubmz. Sie könnten das tun, wie ich in meiner Antwort erwähnt habe. Ein großer Vorteil ist jedoch die Trennung der Logik. In Ihrem Dienst haben Sie beispielsweise eine Funktion getFriends(){return http.get('friends.json').map(r => r.json());}. Jetzt können Sie anrufen, getFriends().subscribe(...)ohne .json()jedes Mal anrufen zu müssen .
Abdulrahman Alsoghayer
2
Ja, das ist für Neulinge nur ein bisschen verwirrend. Was diese geheimnisvolle Karte () macht und was nicht ... Aber schließlich habe ich das auch :)
rubmz
1
@Abdulrahman, vielleicht interessiert Sie auch diese Frage: stackoverflow.com/questions/40505691/…
nyluje
138

Konzepte

Observables in kurzen Abschnitten befasst sich mit asynchroner Verarbeitung und Ereignissen. Im Vergleich zu Versprechungen könnte dies als Observables = Versprechungen + Ereignisse beschrieben werden.

Was bei Observablen großartig ist, ist, dass sie faul sind, abgebrochen werden können und Sie einige Operatoren in ihnen anwenden können (wie map...). Dies ermöglicht es, asynchrone Dinge auf sehr flexible Weise zu handhaben.

Ein großartiges Beispiel, das die Leistung von Observablen am besten beschreibt, ist die Möglichkeit, einen Filtereingang mit einer entsprechenden gefilterten Liste zu verbinden. Wenn der Benutzer Zeichen eingibt, wird die Liste aktualisiert. Observables verarbeiten entsprechende AJAX-Anforderungen und brechen frühere laufende Anforderungen ab, wenn eine andere durch einen neuen Wert in der Eingabe ausgelöst wird. Hier ist der entsprechende Code:

this.textValue.valueChanges
    .debounceTime(500)
    .switchMap(data => this.httpService.getListValues(data))
    .subscribe(data => console.log('new list values', data));

( textValueist die dem Filtereingang zugeordnete Steuerung).

Hier ist eine breitere Beschreibung eines solchen Anwendungsfalls: Wie kann man in Angular 2 auf Formänderungen achten? .

Auf AngularConnect 2015 und EggHead gibt es zwei großartige Präsentationen:

Christoph Burgdorf hat auch einige großartige Blog-Beiträge zu diesem Thema geschrieben:

In Aktion

In Bezug auf Ihren Code haben Sie zwei Ansätze gemischt ;-) Hier sind sie:

  • Verwalten Sie das Beobachtbare selbst . In diesem Fall sind Sie dafür verantwortlich, die subscribeMethode für das Observable aufzurufen und das Ergebnis einem Attribut der Komponente zuzuweisen. Sie können dieses Attribut dann in der Ansicht verwenden, um die Sammlung zu durchlaufen:

    @Component({
      template: `
        <h1>My Friends</h1>
        <ul>
          <li *ngFor="#frnd of result">
            {{frnd.name}} is {{frnd.age}} years old.
          </li>
        </ul>
      `,
      directive:[CORE_DIRECTIVES]
    })
    export class FriendsList implement OnInit, OnDestroy {
      result:Array<Object>; 
    
      constructor(http: Http) {
      }
    
      ngOnInit() {
        this.friendsObservable = http.get('friends.json')
                      .map(response => response.json())
                      .subscribe(result => this.result = result);
       }
    
       ngOnDestroy() {
         this.friendsObservable.dispose();
       }
    }
    

    Renditen von beiden getund mapMethoden sind das Beobachtbare, nicht das Ergebnis (auf die gleiche Weise wie bei Versprechungen).

  • Lassen Sie das Beobachtbare durch die Winkelvorlage verwalten . Sie können die asyncPipe auch nutzen , um das Observable implizit zu verwalten. In diesem Fall muss die subscribeMethode nicht explizit aufgerufen werden.

    @Component({
      template: `
        <h1>My Friends</h1>
        <ul>
          <li *ngFor="#frnd of (result | async)">
            {{frnd.name}} is {{frnd.age}} years old.
          </li>
        </ul>
      `,
      directive:[CORE_DIRECTIVES]
    })
    export class FriendsList implement OnInit {
      result:Array<Object>; 
    
      constructor(http: Http) {
      }
    
      ngOnInit() {
        this.result = http.get('friends.json')
                      .map(response => response.json());
       }
    }
    

Sie können feststellen, dass Observables faul sind. Die entsprechende HTTP-Anfrage wird also nur einmal aufgerufen, wenn ein Listener mit der subscribeMethode daran angehängt ist .

Sie können auch feststellen, dass die mapMethode verwendet wird, um den JSON-Inhalt aus der Antwort zu extrahieren und ihn dann in der beobachtbaren Verarbeitung zu verwenden.

Hoffe das hilft dir, Thierry

Thierry Templier
quelle
Vielen Dank für alle Hinweise. Aber kannst du mir mit meinem Plunk helfen?
Nyks
Ich habe meine Antwort mit weiteren Details zu Ihrem Code aktualisiert. Hoffe es wird dir helfen ;-)
Thierry Templier
Entschuldigung, dass ich Ihre Antwort nicht akzeptieren konnte. Es ist klarer, aber die akzeptierte und geschätzte Antwort hat mir geholfen, genug über meine Frage zu verstehen. Aber hoffentlich erhalten Sie gute Treffer für Ihre klare Antwort, wenn Sie eine detailliertere Erklärung haben. Akzeptierte Antwort auch für gutes Grundverständnis.
Mikronyken
2
Thierry Templier Dies ist eine ausgezeichnete Antwort, aber eines ist mir nicht klar: Ich habe gelernt, dass http.get ('friends.json') .map (response => response.json ()) beobachtbare <Array <Object>> zurückgibt. Wenn ja, warum senden Sie es dann an this.result? Sie sind verschiedene Typen.
Stav Alfi
@StavAlfi pipessind auch ein observables. Schauen Sie sich dieses Video an: youtube.com/watch?v=bVI5gGTEQ_U vorgeschlagen von thierry für weitere Informationen.
CandidJ
11
import { HttpClientModule } from '@angular/common/http';

Die HttpClient-API wurde in Version 4.3.0 eingeführt. Es ist eine Weiterentwicklung der vorhandenen HTTP-API und verfügt über ein eigenes Paket @ angle / common / http. Eine der bemerkenswertesten Änderungen ist, dass das Antwortobjekt jetzt standardmäßig ein JSON ist, sodass es nicht mehr mit der Map-Methode analysiert werden muss

http.get('friends.json').subscribe(result => this.result =result);
Rajesh Kumar
quelle