8
votes

My app has 3 download buttons Each button click will dispatch DownloadFileAction(payload=fileId) An Effect will keep listening for Download_File_Action type

@effect()
download_attachment$: Observable = this.actions$
.ofType(FileActions.ActionTypes.DOWNLOAD_ATTACHMENT)
.map(toPayload)
.switchMap( attachment => {
return this.service.downloadAttachment(attachment.link) //absolute link
.map( (data) => {
this.service.saveAttachment(data); //save file locally
return new FileActions.DownloadAttachmentSuccessAction(attachment);
})
.catch(error => {
//debugger;
console.log(error);
});

})

If more than 1 button are clicked at the same time, 2 DownloadFileAction actions will be dispatched

Howerver, download_attachment$ effect only listen for one which is downloaded first and then return DownloadAttachmentSuccessAction, thus the other downloading files will not be finished

Is there any solution or workaround ? Your idea is much appreciated

1
Replace switchMap with mergeMap. - cartant
Thanks @cartant, mergeMap works perfectly - Huy Nguyen

1 Answers

12
votes

As @cartant mentioned in a comment, replace switchMap with mergeMap.

The difference being, switchMap will switch contexts everytime the parent observable fires and mergeMap will keep listening to the parent observable and merge or combine the results.

SwitchMap

In essence the switchMap is unsubscribing from the parent observable's first stream when the parent observable emits a new value.

enter image description here

In the marble diagram, you can see when 3 is emitted and then 5 is emitted, the final output doesn't include 3 30s because when 5 was emitted, it switched contexts and the values are dropped.

MergeMap

MergeMap will merge all the values emitted from the parent observable.

enter image description here

In the marble diagram for mergeMap you can see all values get emitted for every value emitted from the parent observable. ie, all 30s get emitted, even though the last value comes in after 5 is emitted from the parent.

Hope that helps illustrate it a little better.