Currently i have a code that looks like this:
TS:
ngOnInit() {
this.authService.getCurrentUser().subscribe((response) => {
this.currentUser = response;
const position = this.appService.searchPosition();
const formData = this.appService.getFormData(this.candidateId);
forkJoin([position, formData]).subscribe({
next: (data) => {
[this.positionList, this.myForm] = data;
this.myForm.patchValue({
// Initiating form with values from formData
phoneNumber: formData.phoneNumber
});
// Here I want to add another service call to check for a status
this.appService.checkStatus(formData.phoneNumber, this.candidateId).subscribe(
response => {
// Response here is a boolean
if (response) {
this.status = true;
}
}
)
this.isLoading = false;
},
error: (err) => console.error(err),
});
});
}
HTML:
<button *ngIf="status">Some Button</button>
The issue I am facing is that this.status
does not update because the nested subscribe is fired after the view got initiated with this.isLoading = false
.
Putting this.isLoading = false
inside nested subscribe is not an option because the view won't initiate at all.
How should I call a nested subscribe in this case so that this.isLoading = false
works correctly here ?
Have tried switchMap
and mergeMap
as it was suggested in other threads. Didn't work, and I'm pretty sure it's because of how I tried to implement them.
This was my attempt:
this.authService.getCurrentUser().pipe(
switchMap((user) => {
this.currentUser = user
// This call gets formData for next switchMap
return this.appService.getFormData(this.candidateId);
}
),
switchMap((formData) => {
// This call gets status
reutrn this.appService.checkStatus(formData.phoneNumber, this.candidateId)
})
).subscribe(data => {
// Console log is not called and rest of the code doesn't work.
console.log(data);
})
I know one of those is most likely the right answer for me, but I simply can't get to understand how should I use them.
You are chaining unnecessary observables from the beginning, take a look at this:
this.authService.getCurrentUser().subscribe(response => {
this.currentUser = response;
...
...
})
The only purpose of getCurrentUser()
is to store data in the class property currentUser
, after that, the code that follows does not even use currentUser
value, then why searchPosition
and getFormData
need to be embedded in this first observable
? These two do not depend on the response from getCurrentUser()
, so primarily, you could start handling the user separately with something like:
// do not forget to handle the subscription
this.authService.getCurrentUser().subscribe(res => this.currentUser = res);
I see a few more things in your code that make me wonder the logic shown in this post, so I will try to figure out what you want to achieve. For handling the other observables, you could do it as the following:
const position$ = this.appService.searchPosition();
const formData$ = this.appService.getFormData(this.candidateId);
const final$ = forkJoin([position$, formData$]);
final$.pipe(
switchMap((res) => {
const [positionData, formData] = res;
this.positionList = positionData;
this.myForm.get('phoneNumber').patchValue(formData.phoneNumber);
return this.appService.checkStatus(formData.phoneNumber, this.candidateId);
})
).subscribe((response) => {
this.isLoading = false;
if (response) this.status = true;
})
Another alternative without using forkJoin
could be as the following:
this.appService.searchPosition().pipe(
switchMap((response) => {
this.positionList = response;
return this.appService.getFormData(this.candidateId);
}),
switchMap((response) => {
this.myForm.get('phoneNumber').patchValue(response.phoneNumber);
return this.appService.checkStatus(response.phoneNumber, this.candidateId);
})
).subscribe((response) => {
this.isLoading = false;
if (response) this.status = true;
});