I have to make a couple of optional calls to upload files to get ids before I can send a post to a different route with those file ids.
const body = ...
const updateFile1Reference = map((file: File | null) => {
if (file) {
body.file1 = { id: file.id }
}
return body
})
const uploadFile1 = body.file1 ?
this.fileService.upload(body.file1).pipe(updateFile1Reference) :
of(body)
const updateFile2Reference = map((file: File | null) => {
if (file) {
body.file2 = { id: file.id }
}
return body
})
const uploadFile2 = body.file2 ?
this.fileService.upload(body.file2).pipe(updateFile2Reference) :
of(body)
const update = this.service.update(body)
return of(body).pipe(
switchMap(() => uploadFile1),
switchMap(() => uploadFile2),
switchMap(() => update)
)
However I am seeing the update run before the file uploads.
The switchMap
in your code are running parallel; they are responsible for switching to the inner observable (uploadFile2
, uploadFile1
) from the outer observable (of(body)
), they do not care if the previous switchMap completes or not. Thus we need to nest the switchMap
operators for sequential execution.
If you have APIs dependent on each other, then use forkJoin
(to fetch the IDs in parallel), then use a nested switchMap
to perform the final save.
return forkJoin([uploadFile1, uploadFile2]).pipe(
switchMap(() => update)
)
We can also reduce the boiler plate code by running a map
operation and constructing the APIs.
const files = ['file1', 'file2'];
const api$: any[] = [];
api$ = files.map((fileName: any) => body[fileName] ?
this.fileService.upload(body[fileName]).pipe(
map((file: File | null) => {
if (file) {
body[fileName] = { id: file.id }
}
return body
})
) :
of(body))
return forkJoin(api$).pipe(
switchMap(() => update)
)