AKTUALIZACJA: 9/24/16 Angular 2.0 Stable
To pytanie nadal generuje duży ruch, więc chciałem je zaktualizować. Z powodu szaleństwa zmian w kandydatach do wersji Alpha, Beta i 7 RC, przestałem aktualizować odpowiedzi SO, dopóki nie ustabilizowały się.
Jest to idealny przypadek do używania Subjects i ReplaySubjects
Ja osobiście wolę używać ReplaySubject(1)
, ponieważ pozwala ostatnia wartość przechowywane mają być przekazane, gdy nowi abonenci dołączyć nawet jeśli późno:
let project = new ReplaySubject(1);
project.subscribe(result => console.log('Subscription Streaming:', result));
http.get('path/to/whatever/projects/1234').subscribe(result => {
project.next(result));
setTimeout(()=> project.subscribe(result => console.log('Delayed Stream:', result)), 3000);
});
Więc nawet jeśli połączę się późno lub muszę załadować później, zawsze mogę uzyskać najnowsze połączenie i nie martwić się, że przegapię oddzwonienie.
Umożliwia to również użycie tego samego strumienia do skierowania w dół:
project.next(5678);
//output
//Subscription Streaming: 5678
Ale co, jeśli masz 100% pewności, że telefon wystarczy wykonać tylko raz? Pozostawianie otwartych tematów i obserwowalnych nie jest dobre, ale zawsze pojawia się pytanie „Co jeśli?”
W tym miejscu pojawia się AsyncSubject .
let project = new AsyncSubject();
project.subscribe(result => console.log('Subscription Streaming:', result),
err => console.log(err),
() => console.log('Completed'));
http.get('path/to/whatever/projects/1234').subscribe(result => {
project.next(result));
project.complete();
setTimeout(() => project.subscribe(project => console.log('Delayed Sub:', project)), 2000);
});
Niesamowite! Mimo że zamknęliśmy temat, nadal odpowiadał, podając ostatnią załadowaną rzecz.
Inną rzeczą jest to, jak zasubskrybowaliśmy to wywołanie http i obsłużyliśmy odpowiedź. Mapa świetnie nadaje się do przetwarzania odpowiedzi.
public call = http.get(whatever).map(res => res.json())
Ale co by było, gdybyśmy musieli zagnieździć te połączenia? Tak, możesz użyć przedmiotów ze specjalną funkcją:
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();
Ale to dużo i oznacza, że potrzebujesz do tego funkcji. Wpisz FlatMap :
var myThing = http.get('path').flatMap(result1 =>
http.get('other/' + result1).flatMap(response2 =>
http.get('another/' + response2)));
Świetnie, var
jest to obserwowalne, które pobiera dane z końcowego wywołania http.
OK, to świetnie, ale chcę usługę angular2!
Mam cię:
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) {}
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({
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);
}
}
Jestem wielkim fanem obserwatorów i obserwatorów, więc mam nadzieję, że ta aktualizacja pomoże!
Oryginalna odpowiedź
Myślę, że jest to przypadek użycia korzystania z obserwowalnych Temat lub w .Angular2
EventEmitter
W swojej usłudze tworzysz obiekt, EventEmitter
który pozwala na wpychanie do niego wartości. W Alpha 45 musisz go przekonwertować toRx()
, ale wiem, że pracowali nad pozbyciem się tego, więc w Alpha 46 możesz po prostu zwrócić plik EvenEmitter
.
class EventService {
_emitter: EventEmitter = new EventEmitter();
rxEmitter: any;
constructor() {
this.rxEmitter = this._emitter.toRx();
}
doSomething(data){
this.rxEmitter.next(data);
}
}
W ten sposób jest to jedno, do EventEmitter
którego mogą teraz kierować różne funkcje usługowe.
Jeśli chcesz zwrócić obserwowalny bezpośrednio z połączenia, możesz zrobić coś takiego:
myHttpCall(path) {
return Observable.create(observer => {
http.get(path).map(res => res.json()).subscribe((result) => {
var newResultArray = mySpecialArrayFunction(result);
observer.next(newResultArray);
observer.complete();
});
});
}
To pozwoliłoby ci to zrobić w komponencie:
peopleService.myHttpCall('path').subscribe(people => this.people = people);
I bałagan z wynikami rozmowy w twojej usłudze.
Lubię EventEmitter
samodzielnie tworzyć strumień na wypadek, gdyby potrzebował uzyskać do niego dostęp z innych komponentów, ale widziałem działanie obu sposobów ...
Oto plunker, który pokazuje podstawową usługę z emiterem zdarzeń: Plunkr
EventEmitter
do niczego, ale@Output()
jest odradzane. Zobacz także stackoverflow.com/questions/34376854/…To jest przykład z dokumentacji Angular2, w jaki sposób możesz tworzyć i używać własnych Observables:
Serwis
Składnik
Pełny i działający przykład można znaleźć tutaj: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service
źródło
Dodam, że jeśli tworzony obiekt jest statyczny i nie przechodzi przez http, to można to zrobić:
Edycja: w przypadku mapowania Angular 7.xx należy wykonać za pomocą pipe (), jak opisano tutaj ( https://stackoverflow.com/a/54085359/986160 ):
z odpowiedzi na moje pytanie dotyczące obserwatorów i danych statycznych: https://stackoverflow.com/a/35219772/986160
źródło
Trochę się spóźniłem na imprezę, ale myślę, że moje podejście ma tę zaletę, że brakuje w nim użycia EventEmitterów i Subjects.
Oto moje podejście. Nie możemy uciec od subscribe () i nie chcemy. W tym duchu nasza usługa zwróci
Observable<T>
obserwatora, który ma nasz cenny ładunek. Od wywołującego zainicjujemy zmienną,Observable<T>
która otrzyma wartość usługiObservable<T>
. Następnie zasubskrybujemy ten obiekt. Wreszcie otrzymujesz swoje „T”! z Twojej usługi.Po pierwsze, nasi ludzie obsługują, ale Twój nie przekazuje parametrów, to bardziej realistyczne:
Ok, jak widać, zwracamy
Observable
typ „ludzie”. Podpis metody nawet tak mówi! Wsuwamy_people
obiekt do naszego obserwatora. Następnie uzyskamy dostęp do tego typu od naszego wywołującego w komponencie!W komponencie:
Inicjalizujemy nasze
_peopleObservable
, zwracając toObservable<people>
z naszegoPeopleService
. Następnie subskrybujemy tę właściwość. Na koniec ustawiliśmythis.people
naszą odpowiedź data (people
).Architektura usługi w ten sposób ma jedną, zasadniczą przewagę nad typową usługą: mapa (...) i komponent: wzorzec „subskrybuj (...)”. W prawdziwym świecie musimy mapować json do naszych właściwości w naszej klasie i czasami robimy tam niestandardowe rzeczy. Więc to mapowanie może wystąpić w naszej usłudze. I zazwyczaj dlatego, że nasze zgłoszenie serwisowe zostanie użyte nie raz, ale prawdopodobnie w innych miejscach naszego kodu nie musimy ponownie wykonywać tego mapowania w jakimś komponencie. Co więcej, co jeśli dodamy nowe pole do ludzi? ....
źródło
W pliku service.ts -
za. import „of” from obsable / of
b. utworzyć listę json
c. zwraca obiekt json przy użyciu Observable.of ()
Np. -
W komponencie, w którym wywołujemy funkcję get usługi -
źródło
Zauważ, że używasz Observable # map do konwersji surowego
Response
obiektu, który emituje Twoja podstawowa Observable, na przeanalizowaną reprezentację odpowiedzi JSON.Jeśli dobrze cię zrozumiałem,
map
znowu chcesz . Ale tym razem konwertowanie tego surowego JSON na wystąpienia twojegoModel
. Więc zrobiłbyś coś takiego:Zacząłeś więc od Observable, który emituje
Response
obiekt, przekształcił go w obserwowalny, który emituje obiekt przeanalizowanego kodu JSON tej odpowiedzi, a następnie przekształcił go w kolejny obserwowalny, który przekształcił ten surowy JSON w tablicę twoich modeli.źródło