Angular2 http.get (), map (), iscriviti () e modello osservabile - comprensione di base


170

Ora ho una pagina iniziale in cui ho tre link. Dopo aver fatto clic sull'ultimo collegamento "amici", viene avviato il componente amici appropriati. Lì, voglio recuperare / ottenere l'elenco dei miei amici suddivisi in file friends.json. Fino ad ora tutto funziona bene. Ma sono ancora un principiante per il servizio HTTP di angular2 utilizzando gli osservabili di RxJs, la mappa, il concetto di abbonamento. Ho cercato di capirlo e di leggere alcuni articoli ma fino a quando non avrò un lavoro pratico, non capirò questi concetti correttamente.

Qui ho già creato plnkr che funziona tranne il lavoro relativo a HTTP.

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.

       }
  }

Si prega di guidare e spiegare correttamente. So che sarà molto vantaggioso per molti nuovi sviluppatori.

Risposte:


205

Ecco dove hai sbagliato:

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

dovrebbe essere:

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

o

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

Hai fatto due errori:

1- Hai assegnato l'osservabile stesso a this.result. Quando in realtà volevi assegnare la lista di amici a this.result. Il modo corretto per farlo è:

  • ti iscrivi all'osservabile. .subscribeè la funzione che esegue effettivamente l'osservabile. Prende tre parametri di callback come segue:

    .subscribe(success, failure, complete);

per esempio:

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

Di solito, si prendono i risultati dal callback di successo e lo si assegna alla propria variabile. la richiamata dell'errore è autoesplicativa. il callback completo viene utilizzato per determinare che sono stati ricevuti gli ultimi risultati senza errori. Sul tuo plunker, il callback completo verrà sempre chiamato dopo il callback riuscito o errore.

2- Il secondo errore, ti ha chiamato .json()su .map(res => res.json()), allora hai chiamato di nuovo sul callback successo del osservabile. .map()è un trasformatore che trasformerà il risultato in qualunque cosa tu ritorni (nel tuo caso .json()) prima che sia passato al callback di successo che dovresti chiamare una volta su uno di essi.


2
ecco il tuo plunker . Ho cambiato linea: 21, 23 su myfriends.ts
Abdulrahman Alsoghayer

1
Quello che non ho capito è perché usare qui la funzione "map"? Potremmo semplicemente chiamare il .json sul risultato. Quindi qual è il vantaggio di farlo?
rubmz,

5
Hai ragione @rubmz. Potresti farlo come ho già detto nella mia risposta, ma un enorme vantaggio è la separazione della logica. Ad esempio, nel tuo servizio, hai una funzione getFriends(){return http.get('friends.json').map(r => r.json());}. Ora puoi chiamare getFriends().subscribe(...)senza dover chiamare .json()ogni volta.
Abdulrahman Alsoghayer,

2
Sì, questo è solo un po 'di confusione per i neofiti. Cosa fa quella misteriosa mappa () e cosa no ... Ma alla fine ho
capito

1
@Abdulrahman, forse sarete interessati ad avere uno sguardo a questa domanda anche: stackoverflow.com/questions/40505691/...
nyluje

138

concetti

Osservabili in breve affronta l'elaborazione e gli eventi asincroni. In confronto alle promesse questo potrebbe essere descritto come osservabili = promesse + eventi.

La cosa fantastica degli osservabili è che sono pigri, possono essere cancellati e puoi applicare alcuni operatori (come map, ...). Ciò consente di gestire le cose asincrone in modo molto flessibile.

Un ottimo esempio che descrive il meglio della potenza degli osservabili è il modo di collegare un ingresso filtro a un elenco filtrato corrispondente. Quando l'utente immette caratteri, l'elenco viene aggiornato. Gli osservabili gestiscono le corrispondenti richieste AJAX e annullano le precedenti richieste in corso se un'altra è innescata da un nuovo valore nell'input. Ecco il codice corrispondente:

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

( textValueè il controllo associato all'ingresso del filtro).

Ecco una descrizione più ampia di questo caso d'uso: come guardare per i cambiamenti di forma in Angular 2? .

Ci sono due grandi presentazioni ad AngularConnect 2015 e EggHead:

Christoph Burgdorf ha anche scritto alcuni post sul blog sull'argomento:

In azione

In effetti riguardo al tuo codice, hai mescolato due approcci ;-) Eccoli:

  • Gestisci l'osservabile da solo . In questo caso, sei responsabile di chiamare il subscribemetodo sull'osservabile e assegnare il risultato in un attributo del componente. È quindi possibile utilizzare questo attributo nella vista per iterare sulla raccolta:

    @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();
       }
    }
    

    Ritorni da entrambi gete mapmetodi sono l'osservabile non il risultato (allo stesso modo che con le promesse).

  • Lasciate gestire l'osservabile dal modello angolare . Puoi anche sfruttare la asyncpipa per gestire implicitamente l'osservabile. In questo caso, non è necessario chiamare esplicitamente il subscribemetodo.

    @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());
       }
    }
    

Puoi notare che gli osservabili sono pigri. Quindi la richiesta HTTP corrispondente verrà chiamata solo una volta un listener con allegato su di essa usando il subscribemetodo.

È inoltre possibile notare che il mapmetodo viene utilizzato per estrarre il contenuto JSON dalla risposta e utilizzarlo quindi nell'elaborazione osservabile.

Spero che questo ti aiuti, Thierry


Grazie per tutti i riferimenti. Ma puoi aiutarmi con il mio plunk?
Nyks

Ho aggiornato la mia risposta con maggiori dettagli sul tuo codice. Spero che ti possa aiutare ;-)
Thierry Templier,

scusa se non ho potuto accettare la tua risposta. È più chiara ma la risposta accettata e apprezzata mi ha aiutato a capire abbastanza sulla mia domanda. Ma spero che otterrai buoni risultati per la tua risposta chiara dato che hai una spiegazione più dettagliata. Risposta accettata anche per una buona comprensione di base.
Micronyks,

2
Thierry Templier è un'ottima risposta, ma una cosa non mi è chiara, ho pensato a http.get ('friends.json') .map (response => response.json ()) restituibile osservabile <Array <Oggetto>>. Se sì, come mai lo invii a this.result? sono tipi diversi.
Stav Alfi,

@StavAlfi pipessono anche un observables. guarda questo video: youtube.com/watch?v=bVI5gGTEQ_U suggerito da Thierry per maggiori informazioni.
candidJ

11
import { HttpClientModule } from '@angular/common/http';

L'API HttpClient è stata introdotta nella versione 4.3.0. È un'evoluzione dell'API HTTP esistente e ha il suo pacchetto @ angular / common / http. Una delle modifiche più importanti è che ora l'oggetto risposta è un JSON per impostazione predefinita, quindi non è più necessario analizzarlo con il metodo map. Direttamente possiamo usare come di seguito

http.get('friends.json').subscribe(result => this.result =result);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.