Reputation: 175
I have a bit of a complex chain of observables intending to populate 2 different stores (if null), and to use the objects that are populated to create a third object and feed that into a template with | async.
I suspect one of my observables is expiring, because when I edit the data and update my store, the data isn't reflected as updated.
The chain of observables goes a bit like this: Query store for Roster > no Roster? > API call to populate store > Roster? > query store for Manifest > no Manifest? > API call to populate store > Manifest? > compose Roster and Manifest into Registry > Template as registry$ | async
roster.component.ts:
ngOnInit(): void {
this.route.params.pipe(
switchMap((params: Params) => {
this.slug = params['slug'] ? params['slug'] : '';
this.appService.updateState('activeRosterSlug',this.slug);
this.registry$ = this.slug? this.rosterQuery.composeRegistry(this.slug) : null;
return this.rosterQuery.selectRoster(this.slug) //also needs the bare roster data to edit as json (and thereby update the store and chain the data back through the subscription that's failing)
}),
).subscribe(roster => {
this.jsonDirty = false;
this.data = roster;
console.log(this.registry$);
});
}
roster.query.ts:
selectRoster(slug:string):Observable<Roster> {
const roster$ = this.selectEntity(slug).pipe(
map((roster:Roster) => {
if (!roster) {
return this.rosterService.loadRoster(slug).pipe(switchMap(res => this.selectEntity(slug)))
}else{
return this.selectEntity(slug);
}
}),
mergeAll()
)
return roster$;
}
updateRoster(slug:string,roster:Roster){
this.rosterStore.update(slug,roster);
}
composeRegistry(slug:string):Observable<Registry>{
let roster:Roster;
const registry$ = this.selectRoster(slug).pipe(
tap((res:Roster) => roster = res),
mergeMap((res:Roster) => {
return this.manifestQuery.selectManifest(res.manifest);
}),
map((manifest:Manifest) => {
let registry: //do stuff to combine roster and manifest
return registry;
})
);
return registry$;
}
manifest.query.ts:
selectManifest(slug:string):Observable<Manifest> {
const manifest$ = this.selectEntity(slug).pipe(
map((manifest:Manifest) => {
if (!manifest) {
return this.manifestService.loadManifest(slug).pipe(switchMap(res => this.selectEntity(slug)));
}else{
return this.selectEntity(slug);
}
}),
mergeAll()
)
return manifest$;
};
roster.service.ts:
loadRoster(slug:string){
const rosterApi$ = this.api.rosterSearch(slug).pipe(
map((res:Response) => {
let roster:Roster = {
...JSON.parse(res[0].roster)
}
this.rosterStore.add([roster]);
}),
);
return rosterApi$;
}
api.service.ts:
rosterSearch(slug:string){
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
const postBody = {slug:slug}
return this.http.post('/api/rosters/search', postBody, httpOptions);
}
manifestSearch(slug:string){
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
const postBody = {slug:slug}
return this.http.post('/api/manifests/search', postBody, httpOptions);
}
I'm 90% sure the problem lies in how I'm composing the subscription to this.route.params, since I'm not seeing the same problem in another area that uses the same data (but doesn't edit so it doesn't chain the route and store observables)
edit: Odd. Removing the observable composition in favor of a timed out synchronous call (to test things) didn't change the behavior:
ngOnInit(): void {
this.route.params.subscribe((params: Params) => {
this.slug = params['slug'] ? params['slug'] : '';
this.appService.updateState('activeRosterSlug',this.slug);
this.registry$ = this.slug ? this.rosterQuery.composeRegistry(this.slug) : null;
}
);
setTimeout(() => {
this.data = this.rosterQuery.getEntity(this.slug)
},5000)
}
It still definitely works in the header, where I subscribe to a route service (instead of using activatedRoute) but that route service doesn't seem to function inside router-outlet.
Upvotes: 0
Views: 91