Frage Wie kann man Http Component in einem Service in angular 2 beta effizient nutzen?


Ich versuche mit zu spielen Winkel 2-Beta und ich möchte damit arbeiten Http Komponente. Aber es gibt ein ernstes Problem hier:

ich lese Dies und Ich weiß in Angular 2 (Im Gegensatz zu Angular 1), Http Komponente ist kein Dienst, der a zurückgibt Versprechen. Es gibt etwas zurück, das genannt wird Beobachtbar. Wir wissen, dass eine Komponente besser nicht zu verwenden ist Http direkt. Ein effizienter Weg ist es, einen Dienst zu machen, der für den Verbrauch verantwortlich ist Http. Aber wie?! Sollte dies nach Abschluss einer Anfrage ein Versprechen abgeben? (ansehen Hier)

Macht das überhaupt Sinn ?!


16
2017-12-24 09:08


Ursprung


Antworten:


Mit Angular 2 ist es möglich, Dienste zu implementieren. Sie entsprechen einfach den nachstehend beschriebenen injizierbaren Klassen. In diesem Fall kann diese Klasse in andere Elemente wie Komponenten injiziert werden.

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;
  }
}

Sie können ein injizieren Http Objekt (unter Verwendung seines Konstruktors) in der von Ihnen angegebenen Bedingung HTTP_PROVIDERS beim Bootstrapping der Hauptkomponente Ihrer Anwendung:

import {bootstrap} from 'angular2/platform/browser'
import {HTTP_PROVIDERS} from 'angular2/http';
import {AppComponent} from './app.component'

bootstrap(AppComponent, [
  HTTP_PROVIDERS
]);

Dieser Service kann dann in eine Komponente injiziert werden, wie unten beschrieben. Vergessen Sie nicht, es innerhalb der angeben providers Liste der Komponente.

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;
  }
}

Sie können dann eine Methode implementieren, die den Http Objekt in Ihrem Dienst und geben Sie das Objekt Observable zurück, das Ihrer Anfrage entspricht:

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

Die Komponente kann dies dann aufrufen getCompanies Methode und subskribieren Sie einen Callback für das Observable-Objekt, um benachrichtigt zu werden, wenn die Antwort den Status der Komponente aktualisiert (genau wie bei den Versprechungen 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);
  }
}

Bearbeiten

Wie Fuchs in seinem Kommentar vorgeschlagen, die async Pipe könnte auch verwendet werden, um das beobachtbare Objekt implizit zu subskribieren. Hier ist der Weg, es zu benutzen. Aktualisieren Sie zunächst Ihre Komponente, um das beobachtbare Objekt in das Attribut einzufügen, das Sie anzeigen möchten:

export class CompanyList implements OnInit {
  public companies: Company[];

  constructor(private service: CompanyService) {
    this.service = service;
  }

  ngOnInit() {
    this.companies = this.service.getCompanies();
  }
}

Verwenden Sie dann die asynchrone Pipe in Ihrer Vorlage:

@Component({
  selector: 'company-list',
  providers: [ CompanyService ],
  template: `
    <ul>
      <li *ngFor="#company of companies | async">{{company.name}}</li>
    </ul>
  `
})
export class CompanyList implements OnInit {
  (...)
}

Dieser Artikel in zwei Teilen könnte auch mehr Details geben:

Hoffe es hilft dir, Thierry


23
2017-12-24 10:03



Es besteht keine Notwendigkeit, die Observable, die von der Http-Methode get () zurückgegeben wird, in ein Versprechen zu konvertieren. In den meisten Fällen kann der Dienst das Observable einfach zurückgeben.

Wenn wir einen holen Array oder ein primitiver Typ (d. h. string, number, boolean) vom Server, können wir unsere Controllerlogik vereinfachen, indem wir die zurückgegebene Observable direkt in unserer Vorlage verwenden asynchronePipe. Diese Pipe wird die Observable automatisch abonnieren (sie funktioniert auch mit einer Zusage) und gibt den neuesten Wert zurück, den die Observable ausgegeben hat. Wenn ein neuer Wert ausgegeben wird, markiert die Pipe die Komponente, die auf Änderungen geprüft werden soll. Daher wird die Ansicht automatisch mit dem neuen Wert aktualisiert.

Wenn wir einen holen Objekt vom Server, Ich bin mir keiner Möglichkeit bewusst, asyncPipe zu verwenden, Wir könnten die asynchrone Pipe in Verbindung mit dem sicheren Navigationsoperator wie folgt verwenden:

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

Aber das sieht kompliziert aus, und wir müssten das für jede Objekteigenschaft wiederholen, die wir anzeigen wollten.

Stattdessen schlage ich vor subscribe() auf das Observable in der Komponente und speichern Sie das enthaltene Objekt in einer Komponenteneigenschaft. Wir benutzen dann die sicherer Navigationsoperator (?.) oder (wie @Evan Plaice in einem Kommentar erwähnt) NgIf in der Vorlage. Wenn wir den sicheren Navigationsoperator oder NgIf nicht verwenden, wird ein Fehler ausgegeben, wenn die Vorlage zum ersten Mal versucht, zu rendern, da das Objekt noch nicht mit einem Wert gefüllt ist.

Beachten Sie, dass der folgende Service immer eine Observable für jede Get-Methode zurückgibt.

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: `
    <div>array data using '| async':
      <div *ngFor="#item of arrayData$ | async">{{item}}</div>
    </div>
    <div>primitive data using '| async': {{primitiveData$ | async}}</div>
    <div>object data using ?.: {{objectData?.name}}</div>
    <div *ngIf="objectData">object data using NgIf: {{objectData.name}}</div>`
})
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);
  }
}

Hinweis: Ich habe "Observable" in die Namen der Servicemethoden geschrieben - z. getArrayDataObervable() - Nur um zu verdeutlichen, dass die Methode ein Observable zurückgibt. Normalerweise werden Sie nicht "Observable" in den Namen setzen.

Daten / array.json

[ 1,2,3 ]

Daten / primitive.json

Greetings SO friends!

Daten / Objekt.json

{ "name": "Mark" }

Ausgabe:

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

Plunker


Ein Nachteil bei der Verwendung der async pipe ist, dass es keinen Mechanismus gibt, um Serverfehler in der Komponente zu behandeln. ich beantwortete eine andere Frage das erklärt, wie man solche Fehler in der Komponente fängt, aber wir müssen immer verwenden subscribe() in diesem Fall.


6
2018-01-02 00:48