I have a couple of API calls which rely upon each other. Specifically, I'm having trouble getting the final Observable to return properly: it causes the app to lag indefinitely.
If I call this.projectAttributeService.findAndUpdateByProjectAndMetumId({...})
on its own and then .subscribe
to it, it seems to work ok. This suggests that it's an issue with my Observable chaining on the front-end. As it currently stands, the method is not even being called on the backend (I have a break point set).
// .service
submitPhasesForm(projectId) {
return this.activityDateService.activities$.pipe(
first(),
concatMap((activities: ActivityDate[]) => {
this.activities = activities;
if (this.activities.length === 0) {
return observableOf({});
}
this.activities = activities.map(a => {
a.project_program_id = parseInt(projectId, 10);
return a;
});
return this.activityDateService.update(this.activities);
}),
mergeMap(() => {
if (this.activities.length === 0) {
return observableOf({});
}
return this.projectAttributeService.getAllMetadata(3).pipe(first())
}),
mergeMap((metaData: ProjectAttMetadataAPIResponse) => {
if (this.activities.length === 0) {
return observableOf({});
}
const metaDataId = (metaData as any).find(m => m.name === 'Phase').id;
// EDIT: the problem ended up being with the synchronous
// this.getProjectPhase(this.activities) method below
return this.projectAttributeService.findAndUpdateByProjectAndMetumId({
project_program_id: parseInt(projectId, 10),
value: this.getProjectPhase(this.activities),
project_attrib_metum_id: metaDataId
})
})
)
}
This is what findAndUpdateByProjectAndMetumId()
looks like (the call seems to work ok on its own):
findAndUpdateByProjectAndMetumId(body: ProjectAttribute): Observable < ProjectAttribute > {
return this.http.put < ProjectAttribute > (`${ environment.API_URL }project-attribute`, body);
}
And this is where submitPhasesForm()
is being called:
// .component
import { forkJoin as observableForkJoin } from 'rxjs';
return this.projectService.patch(this.projectId, {
summary: projectSummary || proj.summary
}).pipe(
first(),
mergeMap(() => {
return observableForkJoin(
this.phasesFormDataService.submitPhasesForm(this.projectId).pipe(first()),
this.pdpMetricsFormService.submitPdpForm(this.projectId).pipe(first()),
this.projectStatusFormService.submitStatusForm(this.projectId).pipe(first())
)
})
)
.subscribe((res) => {
this.router.navigate([`./pdp/${this.currentTab}/${this.projectId}`]);
});
The other two calls are very similar, albeit shorter:
submitPdpForm(projectId) {
return this.pdpMetricsForm$.pipe(
first(),
concatMap((formGroup: FormGroup) => {
if (!formGroup.get('etRadioModel')) {
return observableOf({});
}
const objSend = {...}
return this.projectService.upsertPdpMetrics(projectId, objSend);
})
)
}
...
submitStatusForm(projectId) {
return this.metrics$.pipe(
first(),
tap(metrics => {
this.metricsData = metrics;
}),
mergeMap(() => this.statusesForm$),
observableMap(statusesForm => {
const formGroup = statusesForm;
if (!formGroup.get('resourceRationale')) {
return {};
}
const obj = [{...}]
return sendObj;
}),
mergeMap((sendObj: any) => {
if (isEmpty(sendObj)) { return observableOf(sendObj) };
return this.projectService.upsertMetrics(projectId, sendObj).pipe(first());
})
)
Does anything look amiss with the way I'm chaining or calling those Observables?
Any help is much appreciated!
I'm returning of({})
if the first activities$
Observable yields no data, so I can fall through the Observable stream without making unnecessary API calls---I'm open to suggestions for a sleeker way to break
out the the Observable chain.