Reputation: 7633
I'm trying to create a flow of changing language for my blog and, in sum, this is how it would look like:
Subject
), i.e., the language change.Firebase
for the correct page based on that language.If I do each step separately and, later, the user changes the language, then the query won't be triggered because it doesn't know an event has just happened. So I believe this should be some sort of nested subscription/observable. Am I wrong?
I've tried nesting subscriptions, but it didn't work. I believe it was because of scoping bugs. Right now, this is what I'm trying:
this.headerService.langChanged.pipe(
map(
(newLang: string) => {
this.db
.collection<AboutMePage>(
this.aboutMeCollectionName,
ref => ref.where('lang', '==', newLang)
)
.valueChanges();
})
)
.subscribe(
value => {
this.aboutMe = value[0]
}
);
The headerService.langChanged
is a Subject<string>
.
Is there an rxjs
operator for this use case? concat
seemed like a good candidate, but it would have wait for the previous Observable
to end, which it doesn't in this case. And there's also the fact that I have to pass parameters onto the next observable...
Upvotes: 1
Views: 1220
Reputation: 872
I think there's valid solutions for you using any of concat
, switchMap
, merge
, forkJoin
, etc. It really depends on the small things that you want out of them such as concurrency. I put together a little Stackblitz example using forkJoin
here: https://stackblitz.com/edit/angular-xyf8a6
You can see in the console logs the different timings of each inner Observable
to verify that using forkJoin
has it so that it'll only take as long as the slowest observable.
And the subscription as I have it:
this.langChanged
.subscribe(newLang => {
console.log(`language changed ${newLang}`);
this.cancelLangChange.next();
forkJoin(
this.getUserName(newLang),
this.getUserBio(newLang),
this.getUserCreationDate(newLang)
)
.pipe(takeUntil(this.cancelLangChange))
.subscribe(([username, bio, userCreationDate]) => {
this.aboutMe.username = username;
this.aboutMe.bio = bio;
this.aboutMe.userCreationDate = userCreationDate;
});
});
I also added a second Subject
cancelLangChange
which is meant to cancel the forkJoin
subscriptions if a user selects another language while it is still loading the first change.
Upvotes: 2
Reputation: 7633
I managed to get it to work by using pipe
and map
basically. The map
operation will use the first observable to generate another one based on the former's parameters. Then we subscribe in a nested manner, which will finally give us the data we wanted.
this.aboutMeSubscription = this.headerService.langChanged.pipe(
map(
(newLang: string) => {
return this.db
.collection<AboutMePage>(
this.aboutMeCollectionName,
ref => ref.where('lang', '==', newLang)
)
.valueChanges();
})
)
.subscribe(
langChangedAboutMeObs => {
this.langChangedSubscription = langChangedAboutMeObs
.subscribe(
(value: AboutMePage[]) => {
this.aboutMe = value[0];
}
);
}
);
I also changed my Subject
to a BehaviorSubject
so an initial value has been emitted even before the user does anything. Lastly, it's important to unsubscribe to both subscriptions on ngOnDestroy
.
Upvotes: 0