typescript - Așteaptă un abonament și o promisiune în Angular 4
Sunt nou în Angular 4, așa că accept că s-ar putea să fie mai bine să îmi schimb abordarea.
Ceea ce am este asta:
ngOnInit() {
this.route.paramMap
.switchMap((params: ParamMap) => {
var id = +params.get('id');
return this.service.getOne(id);
}).subscribe(data => {
if (data.clientID === 0) {
data.clientID = +this.route.snapshot.queryParams["parentId"];
}
this.model = data;
},); // Subscription
this.lookupService.getList("clients").then(data => {
this.clients = data;
}); // Promise
}
Pe partea clientului, trebuie să fac un alt apel către server, dar doar atunci când am date de la ambele apeluri de mai sus. Cu alte cuvinte, am nevoie ca Subscription să se finalizeze (bine, să nu se finalizeze, ci să seteze valoarea) și ca Promise să se finalizeze.
Există ceva asemănător cu Promise.all care să funcționeze pentru a asigura și că this.model a fost setat în apelul Subscription?
EDIT: Aș putea să le rulez în serie, dar din motive de performanță, vreau să le rulez în paralel.
EDIT 2: Promise a fost intenționat să încarce datele de căutare pentru a popula un dropdown o singură dată. Subscription a fost intenționat să schimbe modelul principal la fiecare schimbare a „id”-ului din URL.
Răspuns #1
Folosește
.zip()pe promisiune și pe observable-ul care preia modelul. Acesta va returna un array de rezultate pe care îl poți folosi pentru a popula proprietățile locale ale clasei. În acest moment poți apela a 3-a funcție (filtrul local). Odată ce promisiunea se finalizează, și.zipse va finaliza, deci acest lanț va avea doar un singur rezultat.Odată ce
.zip()se finalizează, ascultă noii parametri de rută și preia modelele corespunzătoare. Pe măsură ce acestea sosesc, setează proprietatea locală a clasei și rulează filtrul localAbonează-te pentru a declanșa întreaga secvență.
ngOnInit(){ // Will run getOne() with every new parameter let getModelForParam = this.route.paramMap.switchMap( params => this.service.getOne(+params.get('id')) ).share(); // Zip will wait for both below to produce, then output an array of results // and complete (since getList() promise completes after one call) Observable.zip( this.lookupService.getList('clients'), getModelForParam ).do(results => { // capture results in order of .zip() arguments this.clients = results[0]; this.model = results[1]; this.localFilter();// call the filter }).concat( // this part executes once .zip() completes getModelForParam // continue fetching models for new params ).subscribe(model => { this.model = model; this.localFilter(); }) }
Demonstrație live
Răspunsul #2
Poți folosi Observable.forkJoin, care este echivalentul lui Promise.all.
Observable.forkJoin(this.route.paramMap
.switchMap((params: ParamMap) => {
var id = +params.get('id');
return this.service.getOne(id);
}), Observable.fromPromise(this.lookupService.getList("clients")))
.subscribe((arrayOfResults) => {
[firstCallResult, secondCallResult] = arrayOfResults;
this.model = firstCallResult;
});
EDITARE:
Pentru a îndeplini partea referitoare la actualizarea parametrilor, putem folosi operatorul Observable.combineLatest:
Despre Observable.combineLatest
Deoarece emite ori de câte ori unul dintre observabilele sursă emite, blocul de abonare va fi executat. Deoarece celălalt observable provine dintr-o promisiune, acesta se va finaliza și nu va emite mai multe valori, astfel încât this.lookupService.getList() nu va fi apelat din nou.
Observable.combineLatest(this.route.paramMap
.switchMap((params: ParamMap) => {
var id = +params.get('id');
return this.service.getOne(id);
}), Observable.fromPromise(this.lookupService.getList("clients")))
.subscribe((arrayOfResults) => {
[firstCallResult, secondCallResult] = arrayOfResults;
this.model = firstCallResult;
// do whatever else is needed
});
