Come consumare componenti Http in modo efficiente in un servizio in angular 2 beta?

Sto provando a giocare con Angular 2-beta e voglio lavorare con il componente Http . Ma c’è un problema serio qui:

Ho letto questo e so che in Angular 2 (A differenza di Angular 1), il componente Http non è un servizio che restituisce una Promessa . Restituisce qualcosa chiamato Observable . Sappiamo che un componente è meglio non usare Http direttamente. Un modo efficiente è quello di creare un servizio che è responsabile di consumare Http . Ma come?! Se questo dopo aver completato una richiesta, restituire una promise? (guarda qui )

Ha senso ?!

È ansible con Angular 2 implementare i servizi. Corrispondono semplicemente alle classi iniettabili come descritto di seguito. In questo caso questa class può essere iniettata in altri elementi come i componenti.

 import {Injectable} from 'angular2/core'; import {Http, Headers} from 'angular2/http'; import 'rxjs/add/operator/map'; @Injectable() export class CompanyService { constructor(http:Http) { this.http = http; } } 

È ansible inserire un object Http in esso (utilizzando il suo costruttore) alla condizione specificata HTTP_PROVIDERS quando si HTTP_PROVIDERS bootstrap del componente principale della propria applicazione:

 import {bootstrap} from 'angular2/platform/browser' import {HTTP_PROVIDERS} from 'angular2/http'; import {AppComponent} from './app.component' bootstrap(AppComponent, [ HTTP_PROVIDERS ]); 

Questo servizio può essere quindi iniettato in un componente, come descritto di seguito. Non dimenticare di specificarlo nell’elenco dei providers del componente.

 import { Component, View, Inject } from 'angular2/core'; import { CompanyService } from './company-service'; @Component({ selector: 'company-list', providers: [ CompanyService ], template: ` (...) ` }) export class CompanyList { constructor(private service: CompanyService) { this.service = service; } } 

È quindi ansible implementare un metodo sfruttando l’object Http nel servizio e restituire l’object Observable corrispondente alla richiesta:

 @Injectable() export class CompanyService { constructor(http:Http) { this.http = http; } getCompanies() { return this.http.get('https://angular2.apispark.net/v1/companies/') .map(res => res.json()); } } 

Il componente può quindi chiamare questo metodo getCompanies e sottoscrivere una richiamata sull’object Observable da notificare quando la risposta è lì per aggiornare lo stato del componente (nello stesso modo in cui si faceva con le promesse in Angular1):

 export class CompanyList implements OnInit { public companies: Company[]; constructor(private service: CompanyService) { this.service = service; } ngOnInit() { this.service.getCompanies().subscribe( data => this.companies = data); } } 

modificare

Come suggerito da foxx nel suo commento, il pipe async potrebbe anche essere usato per sottoscrivere implicitamente l’object osservabile. Ecco il modo di usarlo. Prima aggiorna il tuo componente per mettere l’object osservabile nell’attributo che vuoi visualizzare:

 export class CompanyList implements OnInit { public companies: Company[]; constructor(private service: CompanyService) { this.service = service; } ngOnInit() { this.companies = this.service.getCompanies(); } } 

Usa quindi la pipe asincrona nel tuo modello:

 @Component({ selector: 'company-list', providers: [ CompanyService ], template: ` 
  • {{company.name}}
` }) export class CompanyList implements OnInit { (...) }

Questo articolo in due parti potrebbe fornire ulteriori dettagli:

Spero che ti aiuti, Thierry

Non è necessario convertire l’osservabile restituito dal metodo get () di Http in una promise. Nella maggior parte dei casi, il servizio può semplicemente restituire l’osservabile.

Se stiamo recuperando un array o un tipo primitivo (cioè stringa, numero, booleano) dal server, possiamo semplificare la logica del controller utilizzando l’osservabile restituito direttamente nel nostro modello, con asyncPipe . Questa pipe si abbonerà automaticamente all’osservabile (funziona anche con una promise) e restituirà il valore più recente che l’osservabile ha emesso. Quando viene emesso un nuovo valore, la pipe contrassegna il componente da controllare per le modifiche, quindi la vista si aggiornerà automaticamente con il nuovo valore.

Se stiamo recuperando un object dal server, non sono a conoscenza di alcun modo per usare asyncPipe, potremmo usare la pipe async, in collaborazione con l’operatore di navigazione sicura come segue:

 {{(objectData$ | async)?.name}} 

Ma sembra complicato e dovremmo ripeterlo per ogni proprietà dell’object che volevamo mostrare.

Invece, suggerisco di subscribe() all’osservabile nel componente e memorizzare l’object contenuto in una proprietà del componente. Quindi usiamo l’ operatore di navigazione sicura (?.) O (come @Evan Plaice menzionato in un commento) NgIf nel modello. Se non usiamo l’operatore di navigazione sicura o NgIf, verrà generato un errore quando il modello tenta prima di eseguire il rendering, perché l’object non è ancora popolato con un valore.

Nota come il servizio sottostante restituisce sempre un osservabile per ciascuno dei metodi get.

service.ts

 import {Injectable} from 'angular2/core'; import {Http} from 'angular2/http'; import 'rxjs/add/operator/map'; // we need to import this now @Injectable() export class MyService { constructor(private _http:Http) {} getArrayDataObservable() { return this._http.get('./data/array.json') .map(data => data.json()); } getPrimitiveDataObservable() { return this._http.get('./data/primitive.txt') .map(data => data.text()); // note .text() here } getObjectDataObservable() { return this._http.get('./data/object.json') .map(data => data.json()); } } 

app.ts

 import {Component} from 'angular2/core'; import {MyService} from './my-service.service'; import {HTTP_PROVIDERS} from 'angular2/http'; @Component({ selector: 'my-app', providers: [HTTP_PROVIDERS, MyService], template: ` 
array data using '| async':
{{item}}
primitive data using '| async': {{primitiveData$ | async}}
object data using ?.: {{objectData?.name}}
object data using NgIf: {{objectData.name}}
` }) export class AppComponent { constructor(private _myService:MyService) { console.clear(); } ngOnInit() { this.arrayData$ = this._myService.getArrayDataObservable(); this.primitiveData$ = this._myService.getPrimitiveDataObservable(); this._myService.getObjectDataObservable() .subscribe(data => this.objectData = data); } }

Nota: inserisco “Osservabile” nei nomi dei metodi di servizio, ad es. getArrayDataObervable() , solo per evidenziare che il metodo restituisce un Osservabile. Normalmente non inserirai “Osservabile” nel nome.

Dati / array.json

 [ 1,2,3 ] 

Dati / primitive.json

 Greetings SO friends! 

Dati / object.json

 { "name": "Mark" } 

Produzione:

 array data using '| async': 1 2 3 primitive data using '| async': Greetings SO friends! object data using .?: Mark object data using NgIf: Mark 

Plunker


Uno svantaggio con l’utilizzo del pipe async è che non esiste un meccanismo per gestire gli errori del server nel componente. Ho risposto ad un’altra domanda che spiega come rilevare tali errori nel componente, ma in questo caso abbiamo sempre bisogno di usare subscribe() .