Based on searchCriteria collected from a form, I have a method that return observable of talents.
getTalents(searchCriteria) {
return this._allUsers$.pipe(
tap((talents) => console.log(talents)),
map((talents: any) => {
let filtered = talents.filter(
(t) =>
(t.userType === 'talent' || t.userType === 'both') &&
this.matchOccupationOrSkill(
searchCriteria.occupation,
t.occupation,
t.skills
)
);
if (searchCriteria.loggedInUserId) {
filtered = filtered.filter(
(t) => t.id !== searchCriteria.loggedInUserId
);
}
return filtered;
})
);
}
where _allUsers$ is a shared observable,
this._allUsers$ = firestore.collection<any>('users').valueChanges().pipe(share());
I am calling getTalents inside ngOnInit method of a route component TalentSearchResult.
ngOnInit(): void {
this.subs.add(
this.route.queryParams.subscribe(params => {
if (params.action==='homesearch' || params.action==='jobsearch'){
this.criteria = {
occupation:params.occupation,
industry:params.industry,
loggedInUserId:params.loggedInUserId,
}
this.dataService.getTalents(this.criteria).pipe(take(1)).subscribe(talents => {
this.count = talents.length;
if (this.count >0){
this.Talents = talents.sort((p1,p2)=> p2.createdate-p1.createdate);
}
})
}
})
)
}
Search works for the first time, then when I go back (using brower back button) and search with a new criteria, it routed correctly to the TalentSearchResult component, however, stale list is being returned. I debugged and found that line 3 in the first code section above, i.e. tap((talents) => console.log(talents)) already logs in the stale value, even before the pipe/map/filter is executed ! Please advice
If you are using _allUsers$ or dataService.getTalents() elsewhere in the app, then you should replace share() with shareReplay(1). Using share() allows multiple subscribers to an observable, but any late subscribers won't get any data until .valueChanges() emits a new value. Using shareReplay(1) will allow late subscribers to immediately get its last cached value.
If you're certain this is the only component subscribing to these observables, then it could be that your component isn't closing subscriptions properly. This may be caused by the nested subscriptions (an anti-pattern) you have inside your ngOnInit() event. I would recommend changing this logic to utilize operators:
this.subs.add(
this.route.queryParams.pipe(
filter(({ action }) => ['homesearch', 'jobsearch'].includes(action)),
map(({ occupation, industry, loggedInUserId }) => ({ occupation, industry, loggedInUserId })),
switchMap(criteria =>
this.dataService.getTalents(criteria).pipe(take(1))
),
filter(talents => !!talents.length),
tap(talents => this.Talents = talents.sort((p1, p2) => p2.createdate - p1.createdate))
).subscribe()
);