NgRX Effect for downloading media file and dispatching progress Actions until Finish action is dispatched

NgRX Effect for downloading media file and dispatching progress Actions until Finish action is dispatched



I am learning NGRX and RXJS in my Podcast project.



My current question is: how to call progress Actions within my @effect based on my Download Action.



The effect looks like this and works:


@Effect()
downloadEpisodes$ = this.actions$.ofType( episodeActions.DOWNLOAD_EPISODE )
.pipe(
map( ( action: episodeActions.DownloadEpisodes ) => action.payload ),
switchMap( ( episode ) =>
return this.episodesService
.download( episode ) // -> download the media file as blobl
.pipe(
map( event => this.episodesService.getHttpProgress( event ) ), // => report download progress
tap( message =>
console.log( message );

),
// switchMap( response => new episodeActions.DownloadProgressEpisodes( response ) // => doesn't work cause its not iterable accoring to typescript.
last(), // => emit last (completed) message to caller
switchMap( response =>
return this.episodesService.downloadSuccess( response ) // => process response blob
.pipe(
tap( response => console.log('--->', response )),
map( response => new episodeActions.DownloadEpisodesSuccess( response ) ),
catchError( error => of (new episodeActions.DownloadEpisodesFail( error ) ) )
)
)
)
)
);



This will report the following in my console:


Downloading file
episodes.effect.ts:57 File is 7% downloaded.
episodes.effect.ts:57 File is 11% downloaded.
episodes.effect.ts:57 File is 15% downloaded.
episodes.effect.ts:57 File is 18% downloaded.
episodes.effect.ts:57 File is 26% downloaded.
episodes.effect.ts:57 File is 30% downloaded.
episodes.effect.ts:57 File is 44% downloaded.
episodes.effect.ts:57 File is 48% downloaded.
episodes.effect.ts:57 File is 70% downloaded.
episodes.effect.ts:57 File is 74% downloaded.
episodes.effect.ts:57 File is 100% downloaded.
episodes.effect.ts:57 HttpResponse headers: HttpHeaders, status: 200, statusText: "OK", url: "http://localhost:3000/episodes/https%3A%2F%2Fwww.s…ple-videos.com%2Faudio%2Fmp3%2Fcrowd-cheering.mp3", ok: true, …



What do I want to change?



Well, the tap message under the getHttpProgress function is called as many times until the upload is done. Then the last() call forwards the httpResponse to the next switchMap.


tap message


getHttpProgress


last()


httpResponse


switchMap



What I would like to achieve is to dispatch an action new episodeActions.DownloadProgressEpisodes( message ) during the Download progress (multiple times) to store the download progress within the episode (call the reducer to update the episode entity).


new episodeActions.DownloadProgressEpisodes( message )



Unfortunately, I don't understand how to dispatch multiple DownloadProgressEpisodes actions during the download process without breaking or the last switchMap that calls the this.episodesService.downloadSuccess( response ).
I tried to add a action call after the tap, before the last call as it seemed to be an Iterator. However, it didn't dispatch those actions, nothing showed up in my redux devTool.
When I dispatch the DownloadProgressEpisode from my service within the getHttpProgress call, It works but I am not sure if that is the proper way.


DownloadProgressEpisodes


download


switchMap


this.episodesService.downloadSuccess( response )


tap


last


Iterator


DownloadProgressEpisode


getHttpProgress



In the end I want to see the following in my redux devTool:


[Podcast] Download Episode;
[Podcast] Download Episode Progress; // payload 0%
[Podcast] Download Episode Progress; // payload 10%
...etc
[Podcast] Download Episode Progress; // payload 100%
[Podcast] Download Episode Success;



What is the best way to solve this?



Or alternatively, should I use different effects for the Download, which calls an effect for the DownloadProgress which repeats itself until finished and then call and effect for DownloadSuccess?




1 Answer
1



I would split this effect in several smaller ones. Right now you're doing several things in the same effect: download, update progress and process the result. You can try to create an effect for each of them.



Download the episode:


@Effect()
downloadEpisode$ = this.actions$.pipe(
ofType(episodeActions.DOWNLOAD_EPISODE),
switchMap(( payload ) => this.episodesService
.download(payload).pipe(
map(response => new episodeActions.DownloadEpisodesSuccess(response)),
catchError(err => of(new episodeActions.DownloadEpisodesFail(error))),
)
)
)



Catch the download success action and process it:


@Effect()
processEpisode$ = this.actions$.pipe(
ofType(episodeActions.DOWNLOAD_EPISODE_SUCESS),
switchMap(( payload ) => this.episodesService
.downloadSuccess(payload).pipe(
map(response => new episodeActions.ProcessEpisodesSuccess(response)),
catchError(err => of(new episodeActions.ProcessEpisodesFail(error))),
)
)
)



And about showing/updating the progress:


@Effect()
updateProgress$ = this.actions$.pipe(
ofType(episodeActions.DOWNLOAD_EPISODE),
switchMap(( payload ) => this.episodesService
.getHttpProgress(payload).pipe(
map(res => new episodeActions.DownloadEpisodesProgress(res)),
)
)
)



This way of showing the progress assumes that getHttpProgress method will return a new observable each time a new episode is downloaded. We listed for the action that notifies the download was started and then we switch map to the output of getHttpProgress.





I did occur to me to do that but I was wondering if that would create to many effects. I read some opinions about relying to much on Effects and how it becomes to abstract. But in this case, there are 3 separate actions with reducers, so it make sense to use separate Effects for them, yes.
– Mattijs
Aug 26 at 3:14





Is there a preference for downloadEpisodes$ = this.actions$.pipe( ofType( episodeActions.DOWNLOAD_EPISODE ), or this.actions$.ofType( episodeActions.DOWNLOAD_EPISODE ).pipe or is it all the same? I know actions$ offers an ofType operator out of the box.
– Mattijs
Aug 26 at 7:12



downloadEpisodes$ = this.actions$.pipe( ofType( episodeActions.DOWNLOAD_EPISODE ),


this.actions$.ofType( episodeActions.DOWNLOAD_EPISODE ).pipe


actions$


ofType





also, the response of the this.episodesService.download is of the type Observable<HttpEvent<any>> . Only when HttpEvenType is 4, will there be a response that can be send to ProcessEpisodeSuccess.
– Mattijs
Aug 26 at 7:41


this.episodesService.download


Observable<HttpEvent<any>>





So I think in the first DOWNLOAD_EPISODE effect I have to test the response (HttpEvent) for its type and based on that dispatch a PROGRESS or SUCCESS action. I will have a play.
– Mattijs
Aug 26 at 7:46





There is an ofType method on actions but as far as I know it will be removed in favor of the operator ofType to be used inside the pipe method.
– Adrian Fâciu
Aug 26 at 9:30






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)