[AngularFire] Angular File Uploads to Firebase Storage with Angular control value accessor
阿新 • • 發佈:2017-10-22
state spa lec span tor event allow load loading
The upload class will be used in the service layer. Notice it has a constructor for file
attribute, which has a type of File
. This will allows us to initialize new uploads with a JavaScript File object. You will see why this is important in the next step.
export class Upload { $key: string; file:File; name:string; url:string; progress:number; createdAt: Date= new Date(); constructor(file:File) { this.file = file; } }
Then build the upload service, which can inject to component:
import { Injectable } from ‘@angular/core‘; import {Subject} from ‘rxjs/Subject‘; import {MatSnackBar} from ‘@angular/material‘; import * as firebase from ‘firebase‘; import UploadTaskSnapshot= firebase.storage.UploadTaskSnapshot; import {Upload} from ‘./upload‘; @Injectable() export class UploadService { uploading$ = new Subject<number>(); completed$ = new Subject<Upload>(); constructor( private snackBar: MatSnackBar ) { } uploadFile(upload: Upload, folder: string) {// Create a storage ref const storageRef = firebase.storage().ref(); const uploadTask = storageRef.child(`${folder}/${upload.file.name}`).put(upload.file); // Upload file uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED, (snapshot: UploadTaskSnapshot) => { upload.progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; this.uploading$.next(upload.progress); }, (err) => { this.snackBar.open(err.message, ‘OK‘, { duration: 3000, }); }, () => { upload.url = uploadTask.snapshot.downloadURL; upload.name = upload.file.name; this.completed$.next(upload); this.uploading$.next(null); }); } deleteUpload(name: string, folder: string) { const storageRef = firebase.storage().ref(); storageRef.child(`${folder}/${name}`).delete(); this.completed$.next(); } }
Component:
import {ChangeDetectionStrategy, Component, forwardRef, Input} from ‘@angular/core‘; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from ‘@angular/forms‘; import {UploadService} from ‘../../services/upload.service‘; import {Upload} from ‘../../services/upload‘; import {Observable} from ‘rxjs/Observable‘; export const TYPE_CONTROL_ACCESSOR = { provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => ImageUploaderComponent) }; @Component({ selector: ‘image-uploader‘, changeDetection: ChangeDetectionStrategy.OnPush, providers: [TYPE_CONTROL_ACCESSOR], templateUrl: ‘./image-uploader.component.html‘, styleUrls: [‘./image-uploader.component.scss‘] }) export class ImageUploaderComponent implements ControlValueAccessor { @Input() img; private onTouch: Function; private onModelChange: Function; private value: string; file: Upload; currentUpload: Upload; progress$: Observable<number>; constructor(private uploadService: UploadService) { this.progress$ = this.uploadService.uploading$; this.uploadService.completed$.subscribe((upload) => { if (upload) { this.setSelected(upload.url); this.currentUpload = upload; } else { this.setSelected(‘‘); this.currentUpload = null; } }); } onChange($event) { const file = $event.target.files[0]; this.file = new Upload(file); this.uploadService.uploadFile(this.file, ‘icons‘); } writeValue(value: any): void { this.value = value; } registerOnChange(fn: Function): void { this.onModelChange = fn; } registerOnTouched(fn: Function): void { this.onTouch = fn; } setSelected(value: string): void { this.value = value; this.onModelChange(value); this.onTouch(); } clear() { if (this.file) { this.uploadService.deleteUpload(this.file.name, ‘icons‘); this.setSelected(‘‘); } } }
Template:
<div *ngIf="progress$ | async as p"> <mat-progress-bar mode="determinate" [value]="p"></mat-progress-bar> </div> <mat-card-subtitle> Select / upload icon </mat-card-subtitle> <mat-card-content fxLayout="column"> <div fxLayout="row" fxLayoutAlign="space-around"> <div *ngIf="currentUpload" class="image-container" fxFlex="30%"> <img [src]="currentUpload?.url || ‘‘" [alt]="currentUpload?.name || ‘‘"> </div> </div>
[AngularFire] Angular File Uploads to Firebase Storage with Angular control value accessor