此方式是使用 HttpClient 來進行表單與檔案上傳, 並利用 Material Dialog 套件, 將上傳的程序包住模組化, 以方便程式間的再利用與撰寫
► 使用方式
► 使用方式
constructor(private dialog: MatDialog) {}
ocClickUploadPhoto() {
const dialodRef = this.dialog.open(UploadDialog, {
data: <IUpload>{
title: '照片上傳',
content: '請選擇 .jpg, .png 的圖片檔',
url: 'data/UserPhotoUpload.php?uid='+this.userId
},
disableClose: true, autoFocus: false, hasBackdrop: true,
});
dialodRef.afterClosed().subscribe(res => {
console.log(res);
if (res && res.result === 'ok') {
this.editForm.get('avatar').setValue(res.data);
}
});
}
► upload.dialog.c.ts
import { Component, OnDestroy, ViewChild, Inject } from '@angular/core';
import { HttpEventType } from '@angular/common/http';
import { FormControl, FormGroup } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { FileUploadService } from './upload.service'
import { BaseDialog } from './base.dialog';
import { NotificationService } from '../notification.service';
@Component({
selector: 'upload-dialog',
templateUrl: './upload.dialog.c.html',
styleUrls: ['./upload.dialog.c.scss']
})
export class UploadDialog extends BaseDialog implements OnDestroy {
uploadForm: FormGroup;
fileToUpload: File = null;
uploadProgress: number = 0;
uploadComplete: boolean = false;
uploadingProgressing: boolean = false;
fileUploadSub: any;
serverResponse: any;
@ViewChild('fileInput') fileInput: any;
title: string = '檔案上傳';
content: string = '';
requestURL: string = '';
constructor(private fileUploadService: FileUploadService, dialogRef: MatDialogRef<UploadDialog>, @Inject(MAT_DIALOG_DATA) private params: IUpload,
private toast: NotificationService) {
super(dialogRef);
if (params) {
if (params.title) { this.title = params.title; }
if (params.content) { this.content = params.content; }
if (params.url && params.url.length>0) {
this.requestURL = params.url;
} else {
this.toast.warning('參數錯誤[url], 無法作業');
this.onClose();
}
} else {
this.toast.warning('參數錯誤[params], 無法作業');
this.onClose();
}
this.uploadForm = new FormGroup({
selectFile: new FormControl(''),
});
}
ngOnDestroy() {
if (this.fileUploadSub) {
this.fileUploadSub.unsubscribe();
}
}
handleProgress(event) {//上傳狀態,進度處理
if (event.type === HttpEventType.DownloadProgress) {
this.uploadingProgressing = true
this.uploadProgress = Math.round(100 * event.loaded / event.total)
} else if (event.type === HttpEventType.UploadProgress) {
this.uploadingProgressing = true;
this.uploadProgress = Math.round(100 * event.loaded / event.total);
} else if (event.type === HttpEventType.Response) {
console.log(event);
this.uploadComplete = true;
let status:string = event.body['status'];
let msg:string = event.body['message'];
let data:string = event.body['data'];
if(status=='ok') {
if(msg.length>0) {
this.toast.success(msg);
} else {
this.toast.success(this.uploadForm.get('selectFile').value + ' 上傳完成');
}
this.reset();
this.dialogRef.close({result:BaseDialog.OK, data:data});
} else {
if(msg.length>0) {
this.toast.warning(msg);
} else {
this.toast.warning(this.uploadForm.get('selectFile').value + ' 上傳失敗');
}
}
}
}
handleSubmit(model: any, isValid: boolean, event: any) {
event.preventDefault();
if (isValid) {
let submittedData = model;
this.fileUploadSub = this.fileUploadService
.upload(this.requestURL, this.fileToUpload, submittedData)
.subscribe(
res => this.handleProgress(res),
error => {
console.log('error', error)
}
);
}
}
//file input has changed
handleFileInput(files: FileList) {
let fileItem = files.item(0);
//console.log("The file is", fileItem)
this.fileToUpload = fileItem
}
reset() {
this.uploadForm.reset();
this.uploadProgress = 0;
this.uploadingProgressing = false;
this.fileInput.nativeElement.value = "";
this.fileToUpload = null;
}
}
export interface IUpload {
url: string,
title: string,
content: string
}
► upload.dialog.c.html
<div mat-dialog-title>
<div class="container">
<div class="row text-center">
<div class="col-md">
{{title}}
</div>
</div>
</div>
</div>
<form [formGroup]='uploadForm' #statusNgForm='ngForm' (submit)='handleSubmit(uploadForm.value, uploadForm.valid, $event)'>
<mat-dialog-content class="post-form">
<div class="container">
<div class="row">
<div class="col-md">
<div class="form-group">
<label class="btn btn-primary fileContainer">
<i class="fas fa-file "></i>
<input #fileInput type="file" formControlName="selectFile" (change)="handleFileInput($event.target.files)" required>
</label>
<span>{{fileToUpload ? fileToUpload.name : '選取檔案'}}</span>
<div [class.hidden]="!uploadingProgressing" style="width:100%; border: #3498db solid; border-width: 1px; border-radius:2px">
<div [style.width]="uploadProgress + '%'" style="height:2px; background-color:#007; color:#fff; border-radius:2px">
<!--span>{{uploadProgress}}%</span-->
</div>
</div>
{{ content }}
</div>
</div>
</div>
</div>
</mat-dialog-content>
<mat-dialog-actions>
<div class="container align-items-center">
<div class="row text-center">
<div class="col">
<button mat-button type='submit' color="warn" [disabled]='uploadForm.invalid'><i class="fas fa-upload"></i> 上傳</button>
</div>
<div class="col">
<button #firstFocus mat-button type='button' color="primary" (click)='onClose()'>取消</button>
</div>
</div>
</div>
</mat-dialog-actions>
</form>
► upload.dialog.c.css
.mat-dialog-content {
min-width: 480px;
}
.fileContainer {
overflow: hidden;
position: relative;
}
.fileContainer [type=file] {
cursor: inherit;
display: block;
font-size: 999px;
filter: alpha(opacity=0);
min-height: 100%;
min-width: 100%;
opacity: 0;
position: absolute;
right: 0;
text-align: right;
top: 0;
}
p {
font-size: 14px;
color:#a200ff;
}
► upload.service.ts
將 httpClient 參數 reportProgress = true 來處理上傳進度資訊
import { Injectable } from '@angular/core';
import { HttpClient, HttpRequest, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class FileUploadService {
constructor(private http: HttpClient) { }
upload(requsetURL:string, fileItem?: File, extraData?: object): Observable<HttpEvent<any>> {
const formData: FormData = new FormData();
let fileName;
if (extraData) {//加入表單資料
for (let key in extraData) {
if (key == 'fileName') {//自訂檔案名稱
fileName = extraData[key]
}
formData.append(key, extraData[key])
}
}
if (fileItem) {//加入檔案
if (!fileName) {
fileName = fileItem.name
}
formData.append('file', fileItem, encodeURI(fileName));
}
const req = new HttpRequest('POST', requsetURL, formData, {
reportProgress: true, responseType: 'json'
});
return this.http.request(req);
}
}