Angular2 http.get (), map (), subscribe () y patrón observable - comprensión básica

170

Ahora, tengo una página inicial donde tengo tres enlaces. Una vez que hace clic en el último enlace de 'amigos', se inicia el componente de amigos apropiado. Ahí, quiero buscar / obtener la lista de mis amigos almacenados en el archivo friends.json. Hasta ahora todo funciona bien. Pero todavía soy un novato en el servicio HTTP de angular2 que usa el concepto de observación, mapa y suscripción de RxJs. He tratado de entenderlo y leer algunos artículos, pero hasta que no entre en el trabajo práctico, no voy a entender esos conceptos correctamente.

Aquí ya hice plnkr que funciona, excepto el trabajo relacionado con 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.

       }
  }

Por favor guíe y explique adecuadamente. Sé que será muy beneficioso para muchos desarrolladores nuevos.

nyks
fuente

Respuestas:

205

Aquí es donde te equivocaste:

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

debería ser:

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

o

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

Has cometido dos errores:

1- Usted asignó el observable a sí mismo this.result. Cuando realmente quería asignar la lista de amigos this.result. La forma correcta de hacerlo es:

  • te suscribes a lo observable. .subscribees la función que realmente ejecuta el observable. Se necesitan tres parámetros de devolución de llamada de la siguiente manera:

    .subscribe(success, failure, complete);

por ejemplo:

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

Por lo general, toma los resultados de la devolución de llamada exitosa y lo asigna a su variable. la devolución de llamada de error se explica por sí misma. la devolución de llamada completa se utiliza para determinar que ha recibido los últimos resultados sin ningún error. En su plunker, la devolución de llamada completa siempre se llamará después de la devolución de llamada correcta o errónea.

2- El segundo error, se llama .json()en .map(res => res.json()), a continuación, que llamó de nuevo a la devolución de llamada de éxito de lo observable. .map()es un transformador que transformará el resultado a lo que sea que devuelva (en su caso .json()) antes de pasarlo a la devolución de llamada exitosa, debe llamarlo una vez en cualquiera de ellos.

Abdulrahman Alsoghayer
fuente
2
Aquí tienes tu saqueador . Cambié las líneas: 21, 23 en myfriends.ts
Abdulrahman Alsoghayer
1
Lo que no entendí es ¿por qué usar la función "mapa" aquí? Podríamos llamar al .json sobre el resultado. Entonces, ¿cuál es el beneficio de hacerlo?
rubmz
55
Tienes razón @rubmz. Podrías hacerlo como mencioné en mi respuesta, pero un gran beneficio es separar la lógica. Por ejemplo, en su servicio, tiene una función getFriends(){return http.get('friends.json').map(r => r.json());}. Ahora, puede llamar getFriends().subscribe(...)sin tener que llamar .json()cada vez.
Abdulrahman Alsoghayer
2
Sí, esto es un poco confuso para los novatos. Qué hace ese misterioso mapa () y qué no ... Pero finalmente lo conseguí también :)
rubmz
1
@Abdulrahman, tal vez te interese echar un vistazo a esta pregunta también: stackoverflow.com/questions/40505691/…
nyluje
138

Conceptos

En pocas palabras, se observan procesos y eventos asincrónicos. En comparación con las promesas, esto podría describirse como observables = promesas + eventos.

Lo bueno de los observables es que son flojos, pueden cancelarse y puede aplicar algunos operadores en ellos (como map, ...). Esto permite manejar cosas asincrónicas de una manera muy flexible.

Una gran muestra que describe mejor el poder de los observables es la forma de conectar una entrada de filtro a una lista filtrada correspondiente. Cuando el usuario ingresa caracteres, la lista se actualiza. Los observables manejan las solicitudes AJAX correspondientes y cancelan las solicitudes en curso anteriores si otra se activa por un nuevo valor en la entrada. Aquí está el código correspondiente:

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

( textValuees el control asociado con la entrada del filtro).

Aquí hay una descripción más amplia de tal caso de uso: ¿Cómo observar los cambios de forma en Angular 2? .

Hay dos excelentes presentaciones en AngularConnect 2015 y EggHead:

Christoph Burgdorf también escribió algunas excelentes publicaciones de blog sobre el tema:

En acción

De hecho, con respecto a su código, combinó dos enfoques ;-) Aquí están:

  • Gestiona lo observable por tu cuenta . En este caso, usted es responsable de llamar al subscribemétodo en el observable y asignar el resultado a un atributo del componente. Luego puede usar este atributo en la vista para iterar sobre la colección:

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

    Rentabilidad en forma tanto gety mapmétodos son los observables no el resultado (de la misma manera que con promesas).

  • Deje gestionar lo observable por la plantilla angular . También puede aprovechar la asynctubería para administrar implícitamente lo observable. En este caso, no hay necesidad de llamar explícitamente al subscribemétodo.

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

Puedes notar que los observables son vagos. Por lo tanto, la solicitud HTTP correspondiente solo se llamará una vez que un oyente esté conectado mediante el subscribemétodo.

También puede observar que el mapmétodo se usa para extraer el contenido JSON de la respuesta y luego usarlo en el procesamiento observable.

Espero que esto te ayude, Thierry

Thierry Templier
fuente
Gracias por todas las referencias. Pero, ¿puedes ayudarme con mi golpe?
nyks
Actualicé mi respuesta con más detalles sobre su código. Espero que te ayude ;-)
Thierry Templier
Lamento no haber podido aceptar tu respuesta. Es más claro, pero la respuesta aceptada y apreciada me ayudó a comprender lo suficiente sobre mi pregunta. Pero con suerte obtendrá buenos resultados por su respuesta clara ya que tiene una explicación más detallada. Respuesta aceptada también para una buena comprensión básica.
micronyks
2
Thierry Templier esta es una excelente respuesta, pero una cosa no está clara para mí, pensé que http.get ('friends.json') .map (response => response.json ()) devuelve observable <Array <Object>>. En caso afirmativo, ¿cómo puede enviarlo a this.result? Son tipos diferentes.
Stav Alfi
@StavAlfi pipestambién son un observables. mira este video: youtube.com/watch?v=bVI5gGTEQ_U sugerido por thierry para obtener más información.
sinceroJ
11
import { HttpClientModule } from '@angular/common/http';

La API HttpClient se introdujo en la versión 4.3.0. Es una evolución de la API HTTP existente y tiene su propio paquete @ angular / common / http. Uno de los cambios más notables es que ahora el objeto de respuesta es un JSON de forma predeterminada, por lo que ya no es necesario analizarlo con el método de mapa.

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