Angular2 http.get (), map (), subscribe () e padrão observável - entendimento básico

170

Agora, eu tenho uma página inicial onde tenho três links. Depois de clicar no último link de 'amigos', o componente de amigos apropriado é iniciado. Lá, quero buscar / obter uma lista dos meus amigos inseridos no arquivo friends.json. Até agora tudo funciona bem. Mas ainda sou novato no serviço HTTP do angular2 usando o conceito de observação, mapa e assinatura do RxJs. Eu tentei entender e ler alguns artigos, mas até eu começar o trabalho prático, não vou entender esses conceitos corretamente.

Aqui eu já criei o plnkr que está funcionando, exceto o trabalho relacionado ao 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, guie e explique corretamente. Eu sei que será muito benéfico para muitos novos desenvolvedores.

nyks
fonte

Respostas:

205

Aqui é onde você errou:

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

deveria ser:

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

ou

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

Você cometeu dois erros:

1- Você atribuiu o próprio observável a this.result. Quando você realmente queria atribuir a lista de amigos this.result. A maneira correta de fazer isso é:

  • você assina o observável. .subscribeé a função que realmente executa o observável. São necessários três parâmetros de retorno de chamada, como segue:

    .subscribe(success, failure, complete);

por exemplo:

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

Geralmente, você pega os resultados do retorno de chamada bem-sucedido e o atribui à sua variável. o retorno de chamada de erro é auto-explicativo. o retorno de chamada completo é usado para determinar que você recebeu os últimos resultados sem erros. No seu plunker, o retorno de chamada completo sempre será chamado após o retorno de sucesso ou erro.

2- O segundo erro, você chamada .json()em .map(res => res.json()), então você chamou-o novamente no callback sucesso do observável. .map()é um transformador que transformará o resultado no que você retornar (no seu caso .json()) antes de ser passado para o retorno de chamada bem-sucedido, você deve chamá-lo uma vez em qualquer um deles.

Abdulrahman Alsoghayer
fonte
2
aqui você vai o seu afunilador .
Alterei as
1
O que eu não entendi é por que usar a função "map" aqui? Poderíamos simplesmente chamar o .json no resultado. Então, qual é o benefício de fazer isso?
rubmz
5
Você está certo @rubmz. Você pode fazer isso como mencionei na minha resposta. Mas um grande benefício é separar a lógica. Por exemplo, em seu serviço, você tem uma função getFriends(){return http.get('friends.json').map(r => r.json());}. Agora, você pode ligar getFriends().subscribe(...)sem ter que ligar .json()sempre.
Abdulrahman Alsoghayer
2
Sim, isso é um pouco confuso para iniciantes. O que esse mapa misterioso () faz e não o que ... Mas finalmente consegui que também :)
rubmz
1
@Abdulrahman, talvez você também esteja interessado em dar uma olhada nesta questão: stackoverflow.com/questions/40505691/… #
nyluje
138

Conceitos

Observáveis ​​em pequenas abordagens de processamento assíncrono e eventos. Comparando com promessas, isso pode ser descrito como observáveis ​​= promessas + eventos.

O que é ótimo com os observáveis ​​é que eles são preguiçosos, podem ser cancelados e você pode aplicar alguns operadores neles (como map, ...). Isso permite lidar com coisas assíncronas de uma maneira muito flexível.

Uma excelente amostra que descreve melhor o poder dos observáveis ​​é a maneira de conectar uma entrada de filtro a uma lista filtrada correspondente. Quando o usuário digita caracteres, a lista é atualizada. Os observáveis ​​manipulam solicitações AJAX correspondentes e cancelam solicitações anteriores em andamento se outra for acionada por um novo valor na entrada. Aqui está o código correspondente:

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

( textValueé o controle associado à entrada do filtro).

Aqui está uma descrição mais ampla desse caso de uso: Como observar as alterações de formulário no Angular 2? .

Há duas ótimas apresentações no AngularConnect 2015 e EggHead:

Christoph Burgdorf também escreveu ótimas postagens de blog sobre o assunto:

Em ação

De fato, com relação ao seu código, você misturou duas abordagens ;-) Aqui estão elas:

  • Gerencie o observável por conta própria . Nesse caso, você é responsável por chamar o subscribemétodo no observável e atribuir o resultado a um atributo do componente. Você pode usar esse atributo na exibição para iterar sobre a coleção:

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

    Retornos de ambos gete mapmétodos são observáveis ​​e não o resultado (da mesma maneira que com promessas).

  • Vamos gerenciar o observável pelo modelo Angular . Você também pode aproveitar o asynccanal para gerenciar implicitamente o observável. Nesse caso, não há necessidade de chamar explicitamente o 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());
       }
    }
    

Você pode perceber que os observáveis ​​são preguiçosos. Portanto, a solicitação HTTP correspondente será chamada apenas uma vez que um ouvinte estiver anexado usando o subscribemétodo

Você também pode observar que o mapmétodo é usado para extrair o conteúdo JSON da resposta e usá-lo no processamento observável.

Espero que isso ajude você, Thierry

Thierry Templier
fonte
Obrigado por todas as referências. Mas você pode me ajudar com a minha coragem?
Neyks
Atualizei minha resposta com mais detalhes sobre seu código. Espero que isso irá ajudá-lo ;-)
Thierry Templier
desculpe por não poder aceitar sua resposta. É mais clara, mas a resposta aceita e apreciada me ajudou a entender o suficiente sobre minha pergunta. Mas espero que você receba bons resultados por sua resposta clara, pois possui uma explicação mais detalhada. Resposta aceita também para um bom entendimento básico.
micronyks
2
Thierry Templier, esta é uma excelente resposta, mas uma coisa não está clara para mim: pensei em http.get ('friends.json') .map (response => response.json ()) retorna observável <Array <Object>>. Se sim, então como é que você envia para this.result? eles são tipos diferentes.
Stav Alfi
@StavAlfi pipestambém são um observables. confira este vídeo: youtube.com/watch?v=bVI5gGTEQ_U sugerido por thierry para obter mais informações.
precisa saber é
11
import { HttpClientModule } from '@angular/common/http';

A API HttpClient foi introduzida na versão 4.3.0. É uma evolução da API HTTP existente e possui seu próprio pacote @ angular / common / http. Uma das mudanças mais notáveis ​​é que agora o objeto de resposta é um JSON por padrão, portanto, não há mais necessidade de analisá-lo com o método de mapeamento.

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