32

In my application that i am developing in Angular 4, user can upload multipart files into server. Files are large. I need to show the current progress of file upload process with it's percentage to user, how can i do it?

Thanks in advance!

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
komron
  • 2,267
  • 2
  • 17
  • 26

6 Answers6

26

This works in Angular 9 and 10 (note observe: 'events')

const headers = new HttpHeaders({
        'Content-Type': 'application/json',
        Accept: 'application/json',
        Authorization: token
      }))
const formData = new FormData();
formData.append('file_param_name', file, file.name);

this.httpClient.post(url, formData, {
    headers,
    reportProgress: true,
    observe: 'events'
}).subscribe(resp => {
    if (resp.type === HttpEventType.Response) {
        console.log('Upload complete');
    }
    if (resp.type === HttpEventType.UploadProgress) {
        const percentDone = Math.round(100 * resp.loaded / resp.total);
        console.log('Progress ' + percentDone + '%');
    } 
});
Ian
  • 2,898
  • 1
  • 27
  • 29
8
uploadDocument(file) {

    return this.httpClient.post(environment.uploadDocument, file, { reportProgress: true, observe: 'events' })
}
Shantam Mittal
  • 383
  • 4
  • 8
  • 6
    Please consider adding comments and explanation. This will help your reader to understand your code. [How to Answer](https://stackoverflow.com/help/how-to-answer) – Anthony Apr 25 '19 at 00:15
3

Gajender.service.ts

 import { Injectable } from '@angular/core';
 import {HttpClient, HttpParams, HttpRequest, HttpEvent} from '@angular/common/http';
 import {Observable} from "rxjs";

      constructor(private http: HttpClient) {
      }

       uploadFileData(url: string, file: File): Observable<HttpEvent<any>> {

        let formData = new FormData();
        let user = {
          name : 'Gajender'
        }
        formData.append('file', file);
        formData.append("user", JSON.stringify(user)); 

        let params = new HttpParams();

        const options = {
          params: params,
          reportProgress: true,
        };

        const req = new HttpRequest('POST', url, formData, options);
        return this.http.request(req);
      }

user.component.ts

constructor( private gajender: Gajender) { }
  @ViewChild('selectfile') el:ElementRef;   //in html we make variable of selectfile
  progress = { loaded : 0 , total : 0 };

uploadFile = (file) => {
    var filedata = this.el.nativeElement.files[0];
    this.gajender.uploadFileData('url',filedata)
    .subscribe(
      (data: any) => { 
        console.log(data);
        if(data.type == 1 && data.loaded && data.total){
          console.log("gaju");
          this.progress.loaded = data.loaded;
          this.progress.total = data.total;
        }
        else if(data.body){
          console.log("Data Uploaded");
          console.log(data.body);
        }

       },
      error => console.log(error) 
    )

user.component.html

<form enctype="multipart/form-data"  method="post">
  <input type='file' [(ngModel)]="file" name="file" #selectfile >
  <button type="button" (click)="uploadFile(file)">Upload</button>
</form>
Progress
<progress [value]=progress.loaded  [max]=progress.total>
</progress>
Gajender Singh
  • 1,285
  • 14
  • 13
2

You can easily achieve this with:

npm i angular-progress-http

After importing the module, you can now add below it to your app.module.ts or wherever you stack your app modules in your application.

You will import this (in app.module.ts):

import { HttpModule } from '@angular/http';

import { ProgressHttpModule } from 'angular-progress-http';

Still in your app.module.ts

at @NgModule

@NgModule({

  imports: [

    HttpModule,

    ProgressHttpModule
  ]
})

Then in your component file (whatever.component.ts), where you want to use it. You can place this:

import { ProgressHttp } from 'angular-progress-http';

Then implement like this:

constructor(private http: ProgressHttp) {}
    onSubmit(): void {
        const _formData = new FormData();
        _formData.append('title', this.title);
        _formData.append('doc', this.doc);

        this.http.withUploadProgressListener(progress => { console.log(`Uploading ${progress.percentage}%`); })
        .withDownloadProgressListener(progress => { console.log(`Downloading ${progress.percentage}%`); })
        .post('youruploadurl', _formData)
        .subscribe((response) => {
            console.log(response);
        });
    }
Tolulope Owolabi
  • 314
  • 3
  • 13
  • Good, thanx, will give it a try – komron Jan 10 '18 at 09:25
  • By the way doing `console.log('Uploading ${progress.percentage}%')` is kinda wrong i think , it will always log `0` or will it console log each progress change ? – komron Jan 10 '18 at 09:27
  • yes, it will console log each progress change. you can easily use it in your view. – Tolulope Owolabi Jan 10 '18 at 10:17
  • The percentage progress always return NaN if there is no connection and 100 if there is. How can this be achieved for tracking the whole progress percentage from 0, 1, 2, 50 to 100%? @tolulopeowolabi – KnowledgeSeeker Jul 03 '18 at 07:24
1

Simple we can use --

 upload(formData) {
return this.http.post<any>(api - url, formData, {
  reportProgress: true,
  observe: 'events'
}).pipe(
  map((event: HttpEvent) => {
    if (event.type === HttpEventType.UploadProgress) {
      const percentDone = Math.round(100 * event.loaded / event.total);
      return { status: 'progress', message: percentDone };
    }
    if (event.type === HttpEventType.Response) {
      return event.body;
    }
  }),
  catchError(this.handleError)
);

}

Trilok Singh
  • 1,227
  • 12
  • 10
0

use angular-loading-bar library, if you don't want to use angular-loading-bar library you can use progress callback eq-xhrrequest.upload.onprogress.

k.prerna
  • 31
  • 1
  • 6