Reputation: 6441
Im slowly starting to grasp rxjs, but once in a while i encounter things that puzzle me.
In this case its about the withLatestFrom operator. The rxjs statement below sits in the OnInit method of my angular component. When the screen loads, i see that the api call in the getApiData() method is executed twice, while im sure that the userEventSubject$ was never triggered (thats why i have the first tap operator).
What i expect to happen is that the getApiData() method only gets called when userEventSubject$.next() is called, and never when the screen loads ...
this.userEventSubject$
.pipe(
tap(creditNote => console.log('tapped!')),
takeUntil(this.ngUnsubscribe$),
filter(userEventData => this.checkValidity(userEventData)),
withLatestFrom(this.apiService.getApiData()),
mergeMap(([userEventData, apiData]) => {
let modalRef = this.modalService.show(ModalDialogComponent, {
initialState: { apiData }
});
let instance = <ModalDialogComponent>modalRef.content;
return instance.save.pipe(
mergeMap((info) =>
this.apiService.saveSomeData(userEventData, info).pipe(
catchError((error, caught) => {
instance.error = error;
return empty();
})
)
),
tap(response => modalRef.hide())
);
})
)
.subscribe((response) => {
this.handleResponse(response);
});
Fixed version:
this.userEventSubject$
.pipe(
tap(creditNote => console.log('tapped!')),
takeUntil(this.ngUnsubscribe$),
filter(userEventData => this.checkValidity(userEventData)),
mergeMap(userEventData =>
this.apiService.getApiData().pipe(
map(data => {
return { userEventData, data };
})
)
),
mergeMap(values => {
let modalRef = this.modalService.show(ModalDialogComponent, {
initialState: { data: values.apiData }
});
let instance = <ModalDialogComponent>modalRef.content;
return instance.save.pipe(
mergeMap((info) =>
this.apiService.saveSomeData(userEventData, info).pipe(
catchError((error, caught) => {
instance.error = error;
return empty();
})
)
),
tap(response => modalRef.hide())
);
})
)
.subscribe((response) => {
this.handleResponse(response);
});
Upvotes: 3
Views: 1126
Reputation: 7331
When you're building the pipe, the this.apiService.getApiData()
is not in an arrow function, but it's executed right away. It doesn't matter that the call passed as an argument. The expression gets executed as any other JS call would (try putting console.log
in the same place).
You could do .concatMap(userData => this.apiService.getApiData().map(apidata => {userData, apiData}))
(or switchMap
), but that would call the API always. I don't know what bests suits your needs.
Upvotes: 5