檔案上傳

1 篇文章 / 0 new
author
檔案上傳
此方式是使用 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);
    }
}
Free Web Hosting