Click here to Skip to main content
15,173,299 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I have this upload files button in my Angular app. So far my progress bar works fine but it just shows the loading bar while the file is uploading. So how do I add features to show the status of the upload % completed, also display the upload speed and the real time counter ETA to complete upload? Can it be achieved from front-end alone?

What I have tried:

Here's my file-upload.component.html

<input *ngIf="uploader.queue.length < 3" #uploadButton ng2FileSelect (change)="fileUpload()" [uploader]="uploader" id="supporting-doc-type-{{docType}}"
       type="file"
       class="upload-button"/>
<label for="supporting-doc-type-{{docType}}" class="fake-upload-button">
  {{'account.uploadNric.uploadDoc'| translate}}
</label>
<ng-container *ngIf="uploader != undefined && uploader.queue.length">
  <div class="row" *ngFor="let item of uploader.queue">
    <div class="col-8 text-left">
      <ng-container *ngIf="item.isSuccess; else elseBlock1">
        <a [attr.href]="getFileDownloadUrlByName(item.file.name)" target="_blank">{{item.file.name}}</a>
      </ng-container>
      <ng-template #elseBlock1>
        {{item.file.name}}
      </ng-template>
    </div>
    <div class="col-2">
      <ng-container *ngIf="item.isSuccess; else elseBlock2">
        {{getSimplifiedSize(item.file.size)}}
      </ng-container>
      <ng-template #elseBlock2>
        <mat-progress-bar mode="determinate" color="primary" value={{item.progress}}></mat-progress-bar>
      </ng-template>
    </div>
    <div class="col-2 text-right">
      class="fa fa-trash trash-can-icon">
    </div>
  </div>
</ng-container>

<div *ngIf="documentFormatInvalid" class="alert alert-danger roboto-condensed-font">
  {{'account.uploadNric.uploadFormatInvalid'| translate}}
</div>
<div *ngIf="documentExists" class="alert alert-danger roboto-condensed-font">
  {{'account.uploadNric.uploadDocExists'| translate}}
</div>
<div *ngIf="documentGenericError" class="alert alert-danger roboto-condensed-font">
  {{'account.uploadNric.uploadError'| translate}}
</div>
<div *ngIf="isExceedDocumentSize" class="alert alert-danger roboto-condensed-font">
  {{'account.uploadNric.uploadSizeInvalid'| translate}}
</div>


Here's my file-upload.component.css

.upload-button {
  display: none;
}

.fake-upload-button {
  border-radius: 4px;
  color: #fff;
  background-color: #29b6f6;
  padding: 4px 20px;
  cursor: pointer;
}

.col, .col-1, .col-10, .col-11, .col-12, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-lg, .col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-md, .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-sm, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-xl, .col-xl-1, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9 {
  padding: 0;
}

.trash-can-icon {
  cursor: pointer;
  font-size: 18px;
}


And here's my file-upload.component.ts

@Component({
  selector: 'file-upload',
  templateUrl: './file-upload.component.html',
  styleUrls: ['./file-upload.component.scss']
})
export class FileUploadComponent {

  docType = 'NRIC_FIN_DOCUMENT';
  uploader: FileUploader;
  fileIdentifier = new Map<string, string>();
  @Input()
  orderId: string;
  @Input()
  accountForm: FormGroup;
  documentFormatInvalid = false;
  documentExists = false;
  documentGenericError = false;
  isExceedDocumentSize = false;
  @ViewChild('uploadButton') uploadButton: ElementRef;

  constructor(private uploaderService: UploaderService, private utilService: UtilService,
              private novusService: NovusService, private authService: AuthService) {
  }

  ngOnInit() {
    this.utilService.observeData().subscribe(message => {
        this.initiateUploader();
      }
    );
  }

  fileUpload() {
    this.resetErrors();
    const fileItem = this.uploader.queue[this.uploader.queue.length - 1];
    fileItem.file.name = this.utilService.appendTimeStamp(fileItem.file.name);
    this.uploader.queue[this.uploader.queue.length - 1] = fileItem;
    const format = fileItem.file.type;
    if (!this.uploaderService.validFileSize(fileItem.file.size)) {
      this.isExceedDocumentSize = true;
      this.uploader.queue.pop();
      this.updateForm();
      return;
    }
    if (!this.uploaderService.validFileFormat(format)) {
      this.documentFormatInvalid = true;
      this.uploader.queue.pop();
      this.updateForm();
      return;
    }
    const name = fileItem.file.name;
    const orderId = this.orderId;
    this.uploader.onBuildItemForm = (fileItem: any, form: any) => {
      form.append('name', name);
      form.append('orderId', orderId);
      form.append('token', this.novusService.getMetaToken());
    };
    this.uploadButton.nativeElement.value = '';
    this.uploader.queue[this.uploader.queue.length - 1].upload();
  }

  getFileIdentifierByName(fileName: string): string {
    return this.fileIdentifier.get(fileName);
  }

  getFileDownloadUrlByName(fileName: string): string {
    return this.uploaderService.getDocumentDownloadUrl(this.getFileIdentifierByName(fileName));
  }

  getSimplifiedSize(size: string): string {
    return this.uploaderService.fileSizeConvertor(parseInt(size));
  }

  deleteFile(fileIdentifier: string): void {
    this.uploaderService.fileRemove(fileIdentifier).subscribe(res => {
    });
  }

  removeFileFromUploader(fileName: string): void {
    this.uploader.queue = this.uploader.queue.filter(function(el) {
      return el.file.name != fileName;
    });
    this.updateForm();
  }

  resetErrors(): void {
    this.isExceedDocumentSize = false;
    this.documentFormatInvalid = false;
    this.documentExists = false;
    this.documentGenericError = false;
  }

  updateForm(): void {
    const fileNames = this.uploader.queue.map(res => {
      return res.file.name;
    });
    this.accountForm.controls.fileUpload.markAsTouched();
    this.accountForm.controls.fileUpload.setValue(fileNames.join(';'));
  }

  initiateUploader(): void {
    const uploadHeaders = [{
      name: 'Accept', value: 'application/json, text/javascript, */*; q=0.01',
    }, {
      name: 'Authorization',
      value: `Bearer ${this.authService.getToken()}`
    }];
    const options: FileUploaderOptions = {
      url: `api/document/upload`,
      itemAlias: 'data',
      headers: uploadHeaders,
    };
    this.uploader = new FileUploader(options);
    this.uploader.onSuccessItem = (item, response) => {
      if (response) {
        const resp = JSON.parse(response);
        if (resp) {
          this.fileIdentifier.set(item.file.name, resp.api_message);
        } else if (resp.key === 'FILE_EXISTS') {
          this.uploader.queue.pop();
          this.documentExists = true;
        } else {
          this.uploader.queue.pop();
          this.documentGenericError = true;
        }
      }
      this.updateForm();
    };
    this.uploader.onAfterAddingFile = (file) => {
      file.withCredentials = false;
    };
  }
}
Posted
Comments
Gerry Schmitz 17-Mar-21 17:56pm
   
Math. Start with the file size.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900