I have an APP with an "Export" button. When clicked , the APP get from the server a big text file and uses the HTML5 blob API to "save as" so the user can save it to his disk
In order to start the export operation in dispatch export action
this.store.dispatch(new scanListsActions.Export(id));
this action is then handled by the "effects" code that goes to the backend server to grab the file. when done, ExportSuccess action is dispatched.
Now, i don't want to store the file content in the store since it is very big, on the other hand i need the data in the view in order to send it to the user. currently you can see that i send it to the user in the reducer code (below).
How normally is it done? where is the place to hold the that sends the file to the user?
import * as fileSaver from 'file-saver'; // npm i --save file-saver
export function reducer(state: ScanListsState = initialState, action: ScanListsActions): ScanListsState {
switch (action.type) {
case ScanListsActionTypes.Export:
return {
...state,
loading: true
};
case ScanListsActionTypes.ExportSuccess:
// these 2 lines below send the file to the user (starts a download)
// where should i put this code. I don't think the reducer is the place for it
const blob = new Blob([action.payload.data], { type: 'text/plain; charset=utf-8' });
fileSaver.saveAs(blob, 'destination_list.txt');
return {
...state,
loading: false,
error: null
};
case ScanListsActionTypes.GeneralFail:
return {
...state,
loading: false,
error: action.payload
};
default:
return state;
}
}
Effects code
@Injectable()
export class ScanListsEffects {
constructor(private scanListService: ScanListService,
private actions$: Actions) { }
@Effect()
exportScanList$: Observable<Action> = this.actions$.pipe(
ofType(scanListsActions.ScanListsActionTypes.Export),
mergeMap((action: scanListsActions.Export) =>
this.scanListService.getScanList(action.payload).pipe(
map(sList => (new scanListsActions.ExportSuccess(sList))),
catchError(err => of(new scanListsActions.GeneralFail(err)))
)
)
);
}
You should make a service call for your saving, just as you did for your read. In an effect you'd call the service:
Something like:
@Effect()
fileSaveExportScanList$: Observable<Action> = this.actions$.pipe(
ofType(scanListsActions.ScanListsActionTypes.ExportSuccess),
mergeMap((action: scanListsActions.ExportSuccess) =>
this.scanListService.saveScanList(action.payload).pipe(
map (() => (new scanListsActions.SaveSuccess())),
catchError(err => of(new scanListsActions.GeneralFail(err)))
)
)
);
and then have a service call 'saveScanList'
saveScanList(data: any){
const blob = new Blob([data], { type: 'text/plain; charset=utf-8' });
fileSaver.saveAs(list, 'destination_list.txt');