How to utilize Angular HTTPClient's progress
event to show progress in percentage of Get request which does not necessarily a file request?
Currently HTTPClient's progress
event fires after request completion. I am hoping to work with Content-Length
at back end and determine percentage of content loaded at front end.
I am loading a large amount of rows for a grid and need to show incremental progress on UI. Is it possible?
I know this question is older but, i stumbled upon this while searching for an answer to a similar problem and since there is no accepted answer i post my solution.
I recently implemented a generic way to display a progress bar for every request no matter the type in angular 8.
First i created a HttpInterceptor
which would automatically intercept every http call where the reportProgress
option is set to true
.
@Injectable()
export class HttpProgressInterceptor implements HttpInterceptor {
constructor(
private spinnerService: SpinnerService // my personal service for the progress bar - replace with your own
) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (req.reportProgress) {
// only intercept when the request is configured to report its progress
return next.handle(req).pipe(
tap((event: HttpEvent<any>) => {
if (event.type === HttpEventType.DownloadProgress) {
// here we get the updated progress values, call your service or what ever here
this.spinnerService.updateGlobalProgress(Math.round(event.loaded / event.total * 100)); // display & update progress bar
} else if (event.type === HttpEventType.Response) {
this.spinnerService.updateGlobalProgress(null); // hide progress bar
}
}, error => {
this.spinnerService.updateGlobalProgress(null); // hide progress bar
})
);
} else {
return next.handle(req);
}
}
}
You need to register this interceptor in your module
of course:
@NgModule({
declarations: [
AppComponent,
...
],
imports: [
BrowserModule,
...
RouterModule.forRoot(appRoutes)
],
providers: [
...
{ provide: HTTP_INTERCEPTORS, useClass: HttpProgressInterceptor, multi: true },
...}
],
bootstrap: [AppComponent]
})
export class AppModule { }
Basically we're done here, only thing left is that we need to change the way we call our apis. If you want a specific request to be monitored using this interceptor you need to tell angular to report the progress on the HttpRequest:
@Injectable()
export class MyService {
constructor(
private http: HttpClient
) {}
myGetMethod() {
const url = "api/data/load/big/data";
const req = new HttpRequest("GET", url, {
reportProgress: true // this is important!
});
return this.http.request(req);
}
}
This way of calling the httpClient
api deliveres a different object when calling .subscribe
so we need to take care of that when calling the myGetMethod()
:
ngOnInit() {
this.myService.myGetMethod().subscribe((event: HttpEvent<any>) => {
if (event.type === HttpEventType.Response) {
const responseData = event.body;
console.dir(responseData); // do something with the response
}
});
}
We could also listen here for the HttpEventType.DownloadProgress
event and update the progress values inside this component - but that was not the point of my example.
Hint: if you encounter the problem that event.total
is undefined - you must check whether your REST backend REALLY is providing the Content-Length
header - if this header is missing, you will not be able to calculate the progress!
anyway, i hope this will help somebody someday 😉