I am developing multiple parallel file upload feature with ability to delete/cancel ongoing http calls. Once all call gets completed/cancelled, I notify the consumer about it.
For this I am combining individual http observables using forkJoin. But in case user clicks on cancel button, I should not be waiting for the completion of actual http response.
takeUntill won't handle it elegantly as it will act only after receiving the next value from underlying source http stream.
this.uploadFiles().subscribe(data => {
console.warn("Upload completed now!!!!!", data);
});
uploadFiles() {
return forkJoin(
this.files.map(file => // returns array of observable
this.uploadFile(file).pipe( catchError(() => of("Error re-emitted as success to prevent early exit"))))
).pipe(map(() => {
// logic for some user friendly statistic
return data;
}));
}
Use takeUntil with a Subject as notifier to complete Observables. You can pass a file id to the Subject and use filter in takeUntil to only cancel the file upload of a file with a given id.
Use defaultIfEmpty to provide a value that indicates a cancelled request. This also prevents the outer forkJoin from completing immediately when an inner empty request completes.
private cancelUpload$ = new Subject<number>();
uploadFiles() {
let errorCount = 0, cancelledCount = 0, successCount = 0;
return forkJoin(this.dummyFiles.map(file =>
this.uploadFile(file).pipe(
// react to CANCEL event
map(response => response == 'CANCEL' ? ++cancelledCount : ++successCount),
catchError(() => of(++errorCount))
)
)).pipe(map(() => ({ errorCount, successCount, cancelledCount })));
}
uploadFile(file: any) {
http$.pipe(
...
takeUntil(this.cancelUpload$.pipe(filter(id => id == file.id))), // cancel
defaultIfEmpty('CANCEL'), // provide value when cancelled
)
}
cancelUpload(file: any) {
file.uploadStatus = "cancelled";
this.cancelUpload$.next(file.id) // cancel action
}
https://stackblitz.com/edit/angular-zteeql-e1zacp
Assign the subscription to the variable and cancel it with button:
$http: Subscription;
this.$http = this.http.post(this.uploadUrl, formData, {
reportProgress: false
// observe: 'events',
});
And in the cancel function:
cancelUpload(file: any) {
file.uploadStatus = "cancelled";
this.$http.unsubscribe();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With