Angular Firebase Wait for Image to Be Uploaded
Build a dropzone file uploader in Athwart that tin send multiple files to Firebase storage simultaneously. 1050 words.
Created
Concluding Updated
Wellness Check
@angular/core@7.3
firebase@5
Firebase makes it easy to upload a huge payload of raw files a cloud storage saucepan. The following lesson will teach you how to upload files to Firebase Storage with Angular, including several advanced concepts almost how to…
- Handle multiple simultaneous concurrent file uploads.
- Save the resulting download URL to Firestore.
- Display a progress bar and provide UI controls to pause, cancel, and resume uploads.
This post kickoff appeared as [Episode 82 on AngularFirebase.com](https://angularfirebase.com/lessons/firebase-storage-with-angularfire-dropzone-file-uploader/) and has been updated to handle multiple files and save additional data to Firestore.
The demo video beneath demonstrates how the complete feature should work afterwards completing this lesson.
Footstep 0 - Prerequisites
- Install @angular/fire ✔️ How to install @angular/burn, aka AngularFire2
Base CSS Styles
Beneath you will detect the base CSS styles for a basic dropzone.
styles.scss
.dropzone { display : flex ; align-items : center ; justify-content : center ; flex-direction : column ; min-width : 80vw ; font-weight : 200 ; superlative : 300px ; border : 2px dashed #f16624 ; border-radius : 5px ; background : white ; margin : 10px 0 ; & .hovering { border : 2px solid #f16624 ; colour : #dadada ! important ; } .file-label { font-size : one .2em ; } } progress ::-webkit-progress-value { transition : width 0 .1s ease ; }
Footstep ane - Directive to Receive Files from the Browser
Desire to skip this footstep? Consider using this zero-dependency [file-driblet](https://github.com/GoogleChromeLabs/file-drop) web component developed by Google Chrome Labs
The starting time footstep is to create a directive that tin receive the files from the browser. The directive customize the Drag and Drop API to meet the specific needs of our characteristic.
command line
Emit Files as a Custom Event
The most important aspect of the directive below is that it listens to the drib issue on the parent element. This event contains the FileList that the user wants to upload. This data is emitted up as a custom event so it can exist used by our Uploader
component in the next step.
In addition, we listen to dragover/dragleave events so we can toggle CSS styles when the user is hovering over the dropzone.
dropzone.directive.ts
import { Directive , HostListener , Output , EventEmitter } from '@angular/core' ; @Directive ({ selector : '[dropzone]' }) export class DropzoneDirective { @Output () dropped = new EventEmitter < FileList >(); @Output () hovered = new EventEmitter < boolean >(); @HostListener ( 'driblet' , [ '$event' ]) onDrop ( $event ) { $event . preventDefault (); this . dropped . emit ( $consequence . dataTransfer . files ); this . hovered . emit ( false ); } @HostListener ( 'dragover' , [ '$effect' ]) onDragOver ( $event ) { $result . preventDefault (); this . hovered . emit ( truthful ); } @HostListener ( 'dragleave' , [ '$upshot' ]) onDragLeave ( $event ) { $result . preventDefault (); this . hovered . emit ( fake ); } }
Step 2 - Uploader Component
The adjacent footstep is put our directive to use in a component that will receive the files and loop over them. This component does not apply Firebase directly, but rather information technology manages the files dropped by the user and renders an upload-task
(which nosotros will build in stride iii) component for each file.
command line
Heed to File Drop
The HTML we add the dropzone
directive to a div and heed the custom events that it emits. In improver, we loop over a list of files and render upload-chore
which volition be created in the next footstep.
uploader.component.html
< div grade = "dropzone" dropzone ( hovered )=" toggleHover ($ event )" ( dropped )=" onDrop ($ effect )" [ class . hovering ]=" isHovering " > < h3 >AngularFire Drop Zone</ h3 > < p >Drag and Drop a File</ p > </ div > < h3 >Uploads</ h3 > < div * ngFor = "let file of files" > < upload-task [ file ]=" file " ></ upload-task > </ div >
The component typescript is very simple - it only takes the FileList dropped on the div and pushes it to an array.
uploader.component.ts
import { Component } from '@angular/core' ; @Component ({ selector : 'uploader' , templateUrl : './uploader.component.html' , styleUrls : [ './uploader.component.scss' ] }) export class UploaderComponent { isHovering: boolean ; files: File [] = []; toggleHover ( event: boolean ) { this . isHovering = event ; } onDrop ( files: FileList ) { for ( let i = 0 ; i < files . length ; i ++ ) { this . files . push ( files . particular ( i )); } } }
Step 3 - Upload Task Component
command line
ng yard component upload-task
Each child component is a self contained UploadTask that will outset running every bit presently as the component is initialized. It volition display the upload progress in realtime and save the download URL in firestore when it completes.
There is no hard limit on the number of files you can ship to Firebase simultaneously. The SDK will endeavour to utilize the most efficient strategy bachelor to transfer them to the cloud, which is mostly dependent on the user's network connection.
Show Progress and Provide User Controls
The HTML provides a progress bar and several buttons that let the user to pause, abolish, or resume an private upload.
upload-chore.component.html
< div * ngIf = "percentage | async as pct" > < progress [ value ]=" per centum " max = "100" ></ progress > {{ pct | number }}% </ div > < div * ngIf = "snapshot | async as snap" > {{ snap.bytesTransferred }} of {{ snap.totalBytes }} < div * ngIf = "downloadURL as url" > < h3 >Results!</ h3 > < img [ src ]=" url " >< br > < a [ href ]=" url " target = "_blank" rel = "noopener" >Download Me!</ a > </ div > < button ( click )=" task . pause ()" [ disabled ]="! isActive ( snap )" >Interruption</ button > < push ( click )=" task . abolish ()" [ disabled ]="! isActive ( snap )" >Cancel</ push button > < button ( click )=" job . resume ()" [ disabled ]="!( snap ?. state = == ' paused ')" >Resume</ button > </ div >
The component is responsible for managing the state of the upload. In this demo, the upload starts transferring data when initialized with ngOnInit
. It takes the file as an input belongings, then uses it's name as a reference in the storage bucket. Keep in listen, storage path names must be unique (merely similar whatever filesystem), then we also add a timestamp to the name to ensure uniqueness on each upload.
The snapshotChanges
Observable emits data every few hundred milliseconds with information most the upload'due south progress. You lot can use it for progress indicators or alternatively utilise percentageChanges
to heed the current progress ranging from 0 to 100.
Nosotros can detect when the upload has finished using the RxJS finalize
operator. At this bespeak, we can fetch the public download URL and salvage information technology to Firestore for easy access in the time to come.
upload-task.component.ts
import { Component , OnInit , Input , ChangeDetectorRef } from '@athwart/core' ; import { AngularFireStorage , AngularFireUploadTask } from '@angular/burn/storage' ; import { AngularFirestore } from '@angular/fire/firestore' ; import { Appreciable } from 'rxjs' ; import { finalize , tap } from 'rxjs/operators' ; @Component ({ selector : 'upload-job' , templateUrl : './upload-chore.component.html' , styleUrls : [ './upload-chore.component.scss' ] }) consign class UploadTaskComponent implements OnInit { @Input () file: File ; task: AngularFireUploadTask ; percentage: Observable < number >; snapshot: Observable < any >; downloadURL: string ; constructor ( private storage: AngularFireStorage , private db: AngularFirestore ) { } ngOnInit() { this . startUpload (); } startUpload() { // The storage path const path = `exam/ ${ Date . now () } _ ${ this . file . name } ` ; // Reference to storage saucepan const ref = this . storage . ref ( path ); // The principal job this . task = this . storage . upload ( path , this . file ); // Progress monitoring this . per centum = this . chore . percentageChanges (); this . snapshot = this . task . snapshotChanges (). piping ( tap ( console . log ), // The file'southward download URL finalize ( async () => { this . downloadURL = await ref . getDownloadURL (). toPromise (); this . db . collection ( 'files' ). add ( { downloadURL: this.downloadURL , path }); }), ); } isActive ( snapshot ) { return snapshot . state === 'running' && snapshot . bytesTransferred < snapshot . totalBytes ; } }
The final outcome should await something like this:
Source: https://fireship.io/lessons/angular-firebase-storage-uploads-multi/
Post a Comment for "Angular Firebase Wait for Image to Be Uploaded"