Angular RxJS - How to monitor progress of HTTP Get Request (not file)
Solution 1
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 😉
Solution 2
What about this:
import { HttpEventType, HttpClient, HttpRequest} from '@angular/common/http';
...
const request = new HttpRequest('GET', url, {
reportProgress: true
});
http.request(request).subscribe(event => {
// progress
if (event.type === HttpEventType.DownloadProgress) {
console.log(event.loaded, event.total);
// event.loaded = bytes transfered
// event.total = "Content-Length", set by the server
const percentage = 100 / event.total * event.loaded;
console.log(percentage);
}
// finished
if (event.type === HttpEventType.Response) {
console.log(event.body);
}
})
abdul-wahab
I am a Front End Web Developer with a good grasp on back end technologies. I like the evolution of JavaScript into ES and TypeScript and advancements of Angular and React. I am always looking to improve JavaScript applications structure and build processes, hence npm helps me a lot. I am also keenly looking forward the time when we'll be able to develop similar or better native mobile and mobile web applications using cross platform technologies as we are able today to build using SDKs.
Updated on June 20, 2022Comments
-
abdul-wahab almost 2 years
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 withContent-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?
-
abdul-wahab over 6 yearsThe three
console.log
prints just once, after the request has completed.loaded, total: 4 undefined
progress: NaN
response: null
-
Markus Kollers over 6 yearsWhat angular version are you using?
-
abdul-wahab over 6 yearsI am using
4.4.3
. -
Markus Kollers over 6 yearsI don't understand your printed values? Is total empty?
-
abdul-wahab over 6 yearsYes, total is always
undefined
. Don't you think total showsContent-Length
? -
Markus Kollers over 6 yearsYes, the total value depends on the
Content-Length
-Header. Are you sure it is set in the response? And how large is your response? Only 4 bytes? -
abdul-wahab over 6 yearsI am setting it with
response.Headers.Add("Content-Length", System.Text.ASCIIEncoding.ASCII.GetByteCount(serializedDataTable).ToString());
. It's a Nancy endpoint. Response is around 10KB. But this header doesn't show in Network. I am using webpack proxy for API requests. Any ideas? -
Markus Kollers over 6 yearsIf the header isn't visible in network in your browser, your server isn't sending it. Different problem, different question ;-)
-
abdul-wahab over 6 yearsYeah, problem is, any header except
Content-Length
is sent. For some reason, content-length isn't getting through. -
Natalie Perret over 5 yearsIt's written "not file"
-
Kamil Kiełczewski about 4 yearsI also add near
reportProgress: true
following option:observe: "events"
- this makes that progress bar refresh more often