Angular 角度2+;文件上载进度指示器

Angular 角度2+;文件上载进度指示器,angular,typescript,file-upload,multipartform-data,Angular,Typescript,File Upload,Multipartform Data,我有一个现有的表单上传组件,它可以将文件上传到后端。这很好,但问题是,我没有任何视觉指示器来指示有多少文件,即%的文件已上传到服务器。我相信这是我这个组件中缺少的非常需要的功能。此时此刻,请稍候来自app-loader.service.ts(屏幕截图) 是否可能,我可以修改请等待,上载%的文件已上载。我在progressbar在线上看到了很多答案,但我更希望有一个对我有意义的解决方案,并根据我的具体情况定制 form-upload.component.ts import { Component

我有一个现有的表单上传组件,它可以将文件上传到后端。这很好,但问题是,我没有任何视觉指示器来指示有多少文件,即%的文件已上传到服务器。我相信这是我这个组件中缺少的非常需要的功能。此时此刻,
请稍候
来自app-loader.service.ts(屏幕截图)

是否可能,我可以修改
请等待
,上载
%的文件
已上载。我在progressbar在线上看到了很多答案,但我更希望有一个对我有意义的解决方案,并根据我的具体情况定制

form-upload.component.ts

import {  Component,  ViewChild, } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Subscription } from 'rxjs/Subscription';
import { Observer  } from 'rxjs/Observer';
import { HttpClient} from '@angular/common/http';
import { TranslateService } from '@ngx-translate/core';
import { FieldConfig } from '../../models/field-config.interface';
import { WebSocketService, DialogService } from '../../../../../../services/';
import { AppLoaderService } from '../../../../../../services/app-loader/app-loader.service';
import { Http } from '@angular/http';
import { MatSnackBar } from '@angular/material';


@Component({
  selector: 'app-form-upload',
  templateUrl: './form-upload.component.html',
  styleUrls: ['../dynamic-field/dynamic-field.css', 'form-upload.component.css'],
})
export class FormUploadComponent {
  @ViewChild('fileInput') fileInput;
  config: FieldConfig;
  group: FormGroup;
  fieldShow: string;
  public busy: Subscription[] = [];
  public sub: Subscription;
  public observer: Observer < any > ;
  public jobId: Number;
  public fileBrowser = true;
  public apiEndPoint = '/_upload?auth_token=' + this.ws.token;

  constructor(
    protected ws: WebSocketService, protected http: Http, private loader: AppLoaderService,
    private dialog:DialogService, public snackBar: MatSnackBar, public translate: TranslateService) {}

  upload(location = "/tmp/") {
    if(this.config.updater && this.config.parent ){
      this.config.updater(this, this.config.parent);
      return;
    }
  this.loader.open();

  const fileBrowser = this.fileInput.nativeElement;
  if (fileBrowser.files && fileBrowser.files[0]) {
    const formData: FormData = new FormData();
    formData.append('data', JSON.stringify({
      "method": "filesystem.put",
      "params": [location + '/' + fileBrowser.files[0].name, { "mode": "493" }]
    }));
    formData.append('file', fileBrowser.files[0]);

    this.http.post(this.apiEndPoint, formData).subscribe(
      (data) => {
        this.newMessage(location + '/' + fileBrowser.files[0].name);
        this.loader.close();
        this.snackBar.open("File upload complete.", 'close', { duration: 5000 });
      },
      (error) => {
        this.loader.close();
        this.dialog.errorReport(error.status, error.statusText, error._body);
      }
    );
  } else{
    this.loader.close();
  };
}
newMessage(message){
  if(this.config.message){
    this.config.message.newMessage(message);
  }

}
}
从'@angular/core'导入{Component,ViewChild,};
从'@angular/forms'导入{FormGroup};
从'rxjs/Subscription'导入{Subscription};
从'rxjs/Observer'导入{Observer};
从'@angular/common/http'导入{HttpClient};
从'@ngx translate/core'导入{TranslateService};
从“../../models/field config.interface”导入{FieldConfig};
从“../../../../../../services/”导入{WebSocketService,DialogService}”;
从“../../../../../../services/app loader/app loader.service”导入{AppLoaderService};
从'@angular/Http'导入{Http};
从“@angular/material”导入{matsnakbar};
@组成部分({
选择器:“应用程序表单上载”,
templateUrl:'./form upload.component.html',
样式URL:['../dynamic field/dynamic field.css','form upload.component.css'],
})
导出类FormUploadComponent{
@ViewChild('fileInput')fileInput;
配置:FieldConfig;
组:FormGroup;
现场表演:弦乐;
公共忙:订阅[]=[];
公开分:认购;
公众观察员:观察员;
公共职务ID:编号;
public fileBrowser=true;
公共apiEndPoint='/_upload?auth_token='+this.ws.token;
建造师(
受保护的ws:WebSocketService、受保护的http:http、专用加载程序:AppLoaderService、,
私有对话框:DialogService,公共snackBar:Matsnakbar,公共translate:TranslateService){}
上传(location=“/tmp/”){
if(this.config.updater&&this.config.parent){
this.config.updater(this,this.config.parent);
返回;
}
this.loader.open();
const fileBrowser=this.fileInput.nativeElement;
if(fileBrowser.files&&fileBrowser.files[0]){
const formData:formData=new formData();
append('data',JSON.stringify({
“方法”:“filesystem.put”,
“params”:[location+'/'+fileBrowser.files[0]。名称,{“mode”:“493”}]
}));
formData.append('file',fileBrowser.files[0]);
this.http.post(this.apident,formData).subscribe(
(数据)=>{
this.newMessage(位置+'/'+fileBrowser.files[0].name);
this.loader.close();
this.snackBar.open(“文件上传完成”,“关闭”,“持续时间:5000}”);
},
(错误)=>{
this.loader.close();
此.dialog.errorReport(错误状态、错误.statusText、error.\u正文);
}
);
}否则{
this.loader.close();
};
}
新消息(消息){
if(this.config.message){
this.config.message.newMessage(message);
}
}
}
form-upload.component.html

 <div id="{{config.name}}" class="dynamic-field form-input" [formGroup]="group" [ngClass]="fieldShow" [class.has-tooltip]="config.tooltip" *ngIf="!config.isHidden">
  <div class="top">
    <label>{{ config.placeholder | translate }}</label>
    <tooltip *ngIf="config.tooltip" [message]="config.tooltip"></tooltip>
  </div>
  <div *ngIf="config.hideButton;else showButton">
      <mat-card-content>
          <input type="file" #fileInput accept="{{config.acceptedFiles}}" (change)="upload(config.fileLocation)" [formControlName]="config.name">
      </mat-card-content>
  </div>
  <ng-template #showButton>
      <mat-card-content>
          <input type="file" #fileInput accept="{{config.acceptedFiles}}" [formControlName]="config.name">
      </mat-card-content>
      <mat-card-actions class="buttons">
          <button mat-button type="button" (click)="upload(config.fileLocation)">Upload</button>
      </mat-card-actions>
      <mat-error *ngIf="config.hasErrors">{{config.errors}}</mat-error>
  </ng-template>
</div>

{{config.placeholder | translate}}
上传
{{config.errors}}
app-loader.service.ts

import { Injectable } from '@angular/core';
import { MatDialog, MatDialogRef } from '@angular/material';
import { Observable } from 'rxjs/Rx';
import { AppLoaderComponent } from './app-loader.component';
import { TranslateService } from '@ngx-translate/core';
import { T } from '../../translate-marker';

@Injectable()
export class AppLoaderService {
  dialogRef: MatDialogRef<AppLoaderComponent>;
  constructor(private dialog: MatDialog, private translate: TranslateService) { }

  public open(title: string = T('Please wait')): Observable<boolean> {
    this.translate.get(title).subscribe(t => {
      this.dialogRef = this.dialog.open(AppLoaderComponent, {disableClose: true});
      this.dialogRef.updateSize('200px', '200px');
      this.dialogRef.componentInstance.title = t;
    });
    return this.dialogRef.afterClosed();
  }

  public close() {
    this.dialogRef.close();
  }
}
从'@angular/core'导入{Injectable};
从“@angular/material”导入{MatDialog,MatDialogRef};
从'rxjs/Rx'导入{Observable};
从“/app loader.component”导入{AppLoaderComponent};
从'@ngx translate/core'导入{TranslateService};
从“../../translate marker”导入{T};
@可注射()
导出类AppLoaderService{
dialogRef:MatDialogRef;
构造函数(私有对话框:MatDialog,私有转换:TranslateService){}
公开(标题:string=T('Please wait')):可观察{
this.translate.get(title.subscribe)(t=>{
this.dialogRef=this.dialog.open(AppLoaderComponent,{disableClose:true});
this.dialogRef.updateSize('200px','200px');
this.dialogRef.componentInstance.title=t;
});
返回此.dialogRef.afterClosed();
}
公共关闭(){
this.dialogRef.close();
}
}

我在查看了
src/app/upload/upload.service.ts的源代码后提出了解决方案

如果有人感兴趣,这里是区别

diff --git a/src/app/pages/common/entity/entity-form/components/form-upload/form-upload.component.ts b/src/app/pages/common/entity/entity-form/components/form-upload/form-upload.component.ts
index 68be9cdf5..2aec0dd86 100644
--- a/src/app/pages/common/entity/entity-form/components/form-upload/form-upload.component.ts
+++ b/src/app/pages/common/entity/entity-form/components/form-upload/form-upload.component.ts
@@ -2,13 +2,13 @@ import {  Component,  ViewChild, } from '@angular/core';
 import { FormGroup } from '@angular/forms';
 import { Subscription } from 'rxjs/Subscription';
 import { Observer  } from 'rxjs/Observer';
-import { HttpClient} from '@angular/common/http';
+import { HttpClient, HttpRequest, HttpEventType, HttpResponse } from '@angular/common/http';
 import { TranslateService } from '@ngx-translate/core';
 import { FieldConfig } from '../../models/field-config.interface';
-import { WebSocketService, DialogService } from '../../../../../../services/';
+import { WebSocketService } from '../../../../../../services/';
 import { AppLoaderService } from '../../../../../../services/app-loader/app-loader.service';
-import { Http } from '@angular/http';
 import { MatSnackBar } from '@angular/material';
+import { DialogService } from '../../../../../../services/';


 @Component({
@@ -27,10 +27,10 @@ export class FormUploadComponent {
   public jobId: Number;
   public fileBrowser = true;
   public apiEndPoint = '/_upload?auth_token=' + this.ws.token;
-
+
   constructor(
-    protected ws: WebSocketService, protected http: Http, private loader: AppLoaderService,
-    private dialog:DialogService, public snackBar: MatSnackBar, public translate: TranslateService) {}
+    protected ws: WebSocketService,protected http: HttpClient, private loader: AppLoaderService,
+    public dialog: DialogService, public snackBar: MatSnackBar, public translate: TranslateService) {}

   upload(location = "/tmp/") {
     if(this.config.updater && this.config.parent ){
@@ -47,21 +47,29 @@ export class FormUploadComponent {
       "params": [location + '/' + fileBrowser.files[0].name, { "mode": "493" }]
     }));
     formData.append('file', fileBrowser.files[0]);
+    const req = new HttpRequest('POST', this.apiEndPoint, formData, {
+      reportProgress: true
+    });
+    this.http.request(req).subscribe(event => {
+      if (event.type === HttpEventType.UploadProgress) {
+        const percentDone = Math.round(100 * event.loaded / event.total);
+        const upload_msg = `${percentDone}% Uploaded`
+        this.loader.dialogRef.componentInstance.title = upload_msg;
+
+      } else if (event instanceof HttpResponse) {
+        if(event.statusText==="OK") {
+          this.newMessage(location + '/' + fileBrowser.files[0].name);
+          this.loader.close();
+          this.snackBar.open("File upload complete.", 'close', { duration: 5000 });
+        }
+      };
+    },(error)=> {
+      this.loader.close();
+      this.dialog.errorReport("Error",error.statusText, error.message);

-    this.http.post(this.apiEndPoint, formData).subscribe(
-      (data) => {
-        this.newMessage(location + '/' + fileBrowser.files[0].name);
-        this.loader.close();
-        this.snackBar.open("File upload complete.", 'close', { duration: 5000 });
-      },
-      (error) => {
-        this.loader.close();
-        this.dialog.errorReport(error.status, error.statusText, error._body);
-      }
-    );
-  } else{
-    this.loader.close();
-  };
+    });
+
+  }
 }
 newMessage(message){
   if(this.config.message){
(END)

以下是Angular的HttpClient解决方案的可能副本: