30

Thus there are many ad hoc libraries supporting upload/download progress in angular2, I do not know how to use native angular2 http api to show progress while doing upload/download.

The reason why I want to use native http api is because I want to utilize:

  1. http interceptors (http API wrappers) around native http api that validate, cache & enrich the actual http request being sent such as this & this
  2. Angular's http api is much more robust than any ad hoc APIs

There is a nice article about how to do upload/download using angular's http api

But the article mentions that there is no native way to support progress.

Did anyone try using http api for showing progress?

If not, do you know an issue in the angular repo for this?

1
  • Someone requested for closure of this question saying its too broad. Well, its not. Did anyone use angular's http api to track progress?. Any generic Http API is supposed to be used in this context. Its as specific as a question can get. Commented Feb 14, 2017 at 18:21

3 Answers 3

55

As of Angular 4.3.x and beyond versions, it can be achieved using the new HttpClient from @angular/common/http.

Read the Listening to progress events section.

Simple upload example (copied from the section mentioned above):

    const req = new HttpRequest('POST', '/upload/file', file, {
      reportProgress: true,
    });

    http.request(req).subscribe(event => {
      // Via this API, you get access to the raw event stream.
      // Look for upload progress events.
      if (event.type === HttpEventType.UploadProgress) {
        // This is an upload progress event. Compute and show the % done:
        const percentDone = Math.round(100 * event.loaded / event.total);
        console.log(`File is ${percentDone}% uploaded.`);
      } else if (event instanceof HttpResponse) {
        console.log('File is completely uploaded!');
      }
    });

And for downloading, it might be something like pretty much the same:

    const req = new HttpRequest('GET', '/download/file', {
      reportProgress: true,
    });

    http.request(req).subscribe(event => {
      // Via this API, you get access to the raw event stream.
      // Look for download progress events.
      if (event.type === HttpEventType.DownloadProgress) {
        // This is an download progress event. Compute and show the % done:
        const percentDone = Math.round(100 * event.loaded / event.total);
        console.log(`File is ${percentDone}% downloaded.`);
      } else if (event instanceof HttpResponse) {
        console.log('File is completely downloaded!');
      }
    });

Remember in case that you're monitoring a download, the Content-Length has to be set, otherwise, there's no way to the request to be measured.

Sign up to request clarification or add additional context in comments.

6 Comments

Worked for me on 4.1.x as well
R u sure it was 4.1.x? Not only in package.json but the fetched was above?
Hi i am getting event.total as undefined not sure why ?
@slartidan import { HttpClient } from '@angular/common/http'; constructor(private http: HttpClient)
I can add that when using Angular 7.2.4, I needed both reportProgress: true and observe: 'events' to actually see the progress events. Only observe: 'events' will not do download/upload progress events, and leaving out observe will default to observe: 'body' which only returns the body of the response and no other events.
|
3

I would suggest using the native JavaScript XHR wrapped as an Observable, it's fairly easy to create on your own:

upload(file: File): Observable<string | number> {

    let fd: FormData = new FormData();

    fd.append("file", file);

    let xhr = new XMLHttpRequest;

    return Observable.create(observer => {

        xhr.addEventListener("progress", (progress) => {

            let percentCompleted;

            // Checks if we can really track the progress
            if (progress.lengthComputable) {

                // progress.loaded is a number between 0 and 1, so we'll multiple it by 100
                percentCompleted = Math.round(progress.loaded / progress.total * 100);

                if (percentCompleted < 1) {
                    observer.next(0);
                } else {
                    // Emit the progress percentage
                    observer.next(percentCompleted);
                }
            }
        });

        xhr.addEventListener("load", (e) => {

            if (e.target['status'] !== 200) observer.error(e.target['responseText']);

            else observer.complete(e.target['responseText']);
        });

        xhr.addEventListener("error", (err) => {

            console.log('upload error', err);

            observer.error('Upload error');
        });

        xhr.addEventListener("abort", (abort) => {

            console.log('upload abort', abort);

            observer.error('Transfer aborted by the user');
        });

        xhr.open('POST', 'http://some-dummy-url.com/v1/media/files');

        // Add any headers if necessary
        xhr.setRequestHeader("Authorization", `Bearer rqrwrewrqe`);

        // Send off the file
        xhr.send(fd);

        // This function will get executed once the subscription
        // has been unsubscribed
        return () => xhr.abort()
    });
}

And this is how one would use it:

// file is an instance of File that you need to retrieve from input[type="file"] element
const uploadSubscription = this.upload(file).subscribe(progress => {
    if (typeof progress === Number) {
        console.log("upload progress:", progress);
    }
});

// To abort the upload
// we should check whether the subscription is still active
if (uploadSubscription) uploadSubscription.unsubscribe();

6 Comments

Writing my own version is something I want to avoid & I have mentioned why that is the case in the question
For eg., your example does not handle unsubscriptions at all. Along with that I will lose interception capabilities that validates & enriches the request in various way before the request is sent
You don't need to unsubscribe from my code sample. We call either complete or error in all of the XHR events, these will unsubscribe automatically. Please elaborate on what you mean with validating and enriching the the request. Angular's http doesn't provide this at the moment, look at github.com/angular/angular/blob/master/modules/%40angular/http/…. There is bytesLoaded and totalBytes but this has not been used anywhere yet.
w.r.t complete/error, if the user clicks on a different tab while the request is being sent (its possible an appication to have this behaviour to be natual), the user can be asked a prompt to cancel the existing request and move on to the clicked page. In this case, you would need unsubscribe
|
1

This is now possible, check out https://angular.io/guide/http#tracking-and-showing-request-progress.

I could give an example here but I think that the official example from the Angular docs would be better

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.