UPDATE: 24.09.16 Angular 2.0 Stable
Diese Frage hat immer noch viel Verkehr, deshalb wollte ich sie aktualisieren. Mit dem Wahnsinn der Änderungen von Alpha, Beta und 7 RC-Kandidaten hörte ich auf, meine SO-Antworten zu aktualisieren, bis sie stabil waren.
Dies ist der perfekte Fall für die Verwendung von Subjects und ReplaySubjects
Ich persönlich bevorzuge die Verwendung, ReplaySubject(1)
da dadurch der zuletzt gespeicherte Wert übergeben werden kann, wenn neue Abonnenten auch dann zu spät anhängen:
let project = new ReplaySubject(1);
//subscribe
project.subscribe(result => console.log('Subscription Streaming:', result));
http.get('path/to/whatever/projects/1234').subscribe(result => {
//push onto subject
project.next(result));
//add delayed subscription AFTER loaded
setTimeout(()=> project.subscribe(result => console.log('Delayed Stream:', result)), 3000);
});
//Output
//Subscription Streaming: 1234
//*After load and delay*
//Delayed Stream: 1234
Selbst wenn ich zu spät anhänge oder später laden muss, kann ich immer den neuesten Anruf erhalten und muss mir keine Sorgen machen, dass der Rückruf verpasst wird.
Auf diese Weise können Sie auch denselben Stream verwenden, um auf Folgendes zuzugreifen:
project.next(5678);
//output
//Subscription Streaming: 5678
Aber was ist, wenn Sie zu 100% sicher sind, dass Sie den Anruf nur einmal tätigen müssen? Offene Themen und Observablen zu lassen ist nicht gut, aber es gibt immer das "Was wäre wenn?"
Das ist , wo AsyncSubject kommt.
let project = new AsyncSubject();
//subscribe
project.subscribe(result => console.log('Subscription Streaming:', result),
err => console.log(err),
() => console.log('Completed'));
http.get('path/to/whatever/projects/1234').subscribe(result => {
//push onto subject and complete
project.next(result));
project.complete();
//add a subscription even though completed
setTimeout(() => project.subscribe(project => console.log('Delayed Sub:', project)), 2000);
});
//Output
//Subscription Streaming: 1234
//Completed
//*After delay and completed*
//Delayed Sub: 1234
Genial! Obwohl wir das Thema geschlossen haben, antwortete es immer noch mit dem letzten geladenen Element.
Eine andere Sache ist, wie wir diesen http-Aufruf abonniert und die Antwort verarbeitet haben. Map ist großartig, um die Antwort zu verarbeiten.
public call = http.get(whatever).map(res => res.json())
Aber was wäre, wenn wir diese Anrufe verschachteln müssten? Ja, Sie könnten Themen mit einer speziellen Funktion verwenden:
getThing() {
resultSubject = new ReplaySubject(1);
http.get('path').subscribe(result1 => {
http.get('other/path/' + result1).get.subscribe(response2 => {
http.get('another/' + response2).subscribe(res3 => resultSubject.next(res3))
})
})
return resultSubject;
}
var myThing = getThing();
Aber das ist viel und bedeutet, dass Sie eine Funktion benötigen, um dies zu tun. Geben Sie FlatMap ein :
var myThing = http.get('path').flatMap(result1 =>
http.get('other/' + result1).flatMap(response2 =>
http.get('another/' + response2)));
Süß, das var
ist ein Observable, das die Daten vom letzten http-Aufruf erhält.
OK, das ist großartig, aber ich möchte einen Angular2-Service!
Ich habe dich:
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ReplaySubject } from 'rxjs';
@Injectable()
export class ProjectService {
public activeProject:ReplaySubject<any> = new ReplaySubject(1);
constructor(private http: Http) {}
//load the project
public load(projectId) {
console.log('Loading Project:' + projectId, Date.now());
this.http.get('/projects/' + projectId).subscribe(res => this.activeProject.next(res));
return this.activeProject;
}
}
//component
@Component({
selector: 'nav',
template: `<div>{{project?.name}}<a (click)="load('1234')">Load 1234</a></div>`
})
export class navComponent implements OnInit {
public project:any;
constructor(private projectService:ProjectService) {}
ngOnInit() {
this.projectService.activeProject.subscribe(active => this.project = active);
}
public load(projectId:string) {
this.projectService.load(projectId);
}
}
Ich bin ein großer Fan von Beobachtern und Observablen, also hoffe ich, dass dieses Update hilft!
Ursprüngliche Antwort
Ich denke, dies ist ein Anwendungsfall für die Verwendung eines beobachtbaren Subjekts oder in Angular2
der EventEmitter
.
In Ihrem Dienst erstellen Sie eine EventEmitter
, mit der Sie Werte darauf übertragen können. In Alpha 45 müssen Sie es konvertieren toRx()
, aber ich weiß, dass sie daran gearbeitet haben, dies zu beseitigen. In Alpha 46 können Sie das möglicherweise einfach zurückgeben EvenEmitter
.
class EventService {
_emitter: EventEmitter = new EventEmitter();
rxEmitter: any;
constructor() {
this.rxEmitter = this._emitter.toRx();
}
doSomething(data){
this.rxEmitter.next(data);
}
}
Auf diese Weise haben Sie die Single EventEmitter
, auf die Ihre verschiedenen Servicefunktionen jetzt zugreifen können.
Wenn Sie ein Observable direkt von einem Anruf zurückgeben möchten, können Sie Folgendes tun:
myHttpCall(path) {
return Observable.create(observer => {
http.get(path).map(res => res.json()).subscribe((result) => {
//do something with result.
var newResultArray = mySpecialArrayFunction(result);
observer.next(newResultArray);
//call complete if you want to close this stream (like a promise)
observer.complete();
});
});
}
Damit können Sie dies in der Komponente tun:
peopleService.myHttpCall('path').subscribe(people => this.people = people);
Und verwirren Sie die Ergebnisse des Anrufs in Ihrem Dienst.
Ich mag es, den EventEmitter
Stream selbst zu erstellen, falls ich von anderen Komponenten aus darauf zugreifen muss, aber ich konnte sehen, dass beide Möglichkeiten funktionieren ...
Hier ist ein Plunker, der einen Basisdienst mit einem Ereignisemitter zeigt: Plunkr
EventEmitter
für alles andere@Output()
als entmutigt. Siehe auch stackoverflow.com/questions/34376854/…Dies ist ein Beispiel aus Angular2-Dokumenten, wie Sie Ihre eigenen Observables erstellen und verwenden können:
Der Service
Die Komponente
Das vollständige und funktionierende Beispiel finden Sie hier: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service
quelle
Ich möchte hinzufügen, dass, wenn das erstellte Objekt statisch ist und nicht über http kommt, so etwas getan werden kann:
Bearbeiten: Für Angular 7.xx muss die Zuordnung mit pipe () erfolgen, wie hier beschrieben ( https://stackoverflow.com/a/54085359/986160 ):
Von der Antwort auf meine Frage zu Beobachtern und statischen Daten: https://stackoverflow.com/a/35219772/986160
quelle
Ich bin etwas spät zur Party, aber ich denke, mein Ansatz hat den Vorteil, dass EventEmitters und Subjects nicht verwendet werden.
Also, hier ist mein Ansatz. Wir kommen nicht von subscribe () weg und wollen es auch nicht. In diesem Sinne wird unser Service
Observable<T>
mit einem Beobachter zurückkehren, der unsere kostbare Fracht hat. Vom Aufrufer aus initialisieren wir eine VariableObservable<T>
und sie erhält die DiensteObservable<T>
. Als nächstes abonnieren wir dieses Objekt. Endlich bekommst du dein "T"! von Ihrem Dienst.Erstens, unser Personaldienst, aber Ihr Mitarbeiter gibt keine Parameter weiter, das ist realistischer:
Ok, wie Sie sehen können, geben wir einen
Observable
Typ "Menschen" zurück. Die Signatur der Methode sagt es sogar! Wir stecken das_people
Objekt in unseren Beobachter. Wir werden als nächstes von unserem Anrufer in der Komponente auf diesen Typ zugreifen!In der Komponente:
Wir initialisieren unsere,
_peopleObservable
indem wir dasObservable<people>
von unserer zurückgebenPeopleService
. Dann abonnieren wir diese Eigenschaft. Schließlich setzen wirthis.people
auf unsere data (people
) Antwort.Die Architektur des Dienstes auf diese Weise hat einen großen Vorteil gegenüber dem typischen Dienst: map (...) und component: "subscribe (...)" - Muster. In der realen Welt müssen wir den JSON unseren Eigenschaften in unserer Klasse zuordnen, und manchmal machen wir dort einige benutzerdefinierte Dinge. Diese Zuordnung kann also in unserem Service erfolgen. Und normalerweise müssen wir diese Zuordnung in einigen Komponenten nicht erneut durchführen, da unser Serviceabruf nicht einmal verwendet wird, sondern wahrscheinlich an anderen Stellen in unserem Code. Was ist außerdem, wenn wir den Menschen ein neues Feld hinzufügen?
quelle
In der Datei service.ts -
ein. Import 'von' aus beobachtbar / von
b. Erstellen einer JSON-Liste
c. Geben Sie das json-Objekt mit Observable.of () zurück
. - -
In der Komponente, in der wir die get-Funktion des Dienstes aufrufen -
quelle
Beachten Sie, dass Sie Observable # map verwenden , um das von
Response
Ihrer Basis-Observable ausgegebene Rohobjekt in eine analysierte Darstellung der JSON-Antwort zu konvertieren .Wenn ich dich richtig verstanden habe, willst du es
map
wieder. Aber dieses Mal konvertieren Sie diesen rohen JSON in Instanzen von IhnenModel
. Sie würden also so etwas tun wie:Sie haben also mit einer Observable begonnen, die ein
Response
Objekt ausgibt, diese in eine Observable umgewandelt, die ein Objekt des analysierten JSON dieser Antwort ausgibt, und diese dann in eine weitere Observable umgewandelt, die diese rohe JSON in ein Array Ihrer Modelle verwandelt hat.quelle