In the post, we have known how to upload file to Firebase Storage. This tutorial shows you way to upload, get, delete Images in a simple Angular 6 App.
I. Technology
– Angular 6
– AngularFire2 5.0
II. How to do
1. Set up the Firebase Project & Install AngularFire2
Please visit this post to know step by step.
2. Upload File Service
– upload file to Storage and file’s info to Database.
– get List Files from Firebase Storage by files’info (name/url) stored in Database.
– delete file with 2 steps: delete file’s info from Database, then delete file from Storage
export class UploadFileService { private basePath = '/uploads'; constructor(private db: AngularFireDatabase) { } pushFileToStorage(fileUpload: FileUpload) { const storageRef = firebase.storage().ref(); storageRef.child(`${this.basePath}/${fileUpload.file.name}`).put(fileUpload.file); fileUpload.url = downloadURL; fileUpload.name = fileName; this.saveFileData(fileUpload); } private saveFileData(fileUpload: FileUpload) { this.db.list(`${this.basePath}/`).push(fileUpload); } getFileUploads(numberItems): AngularFireList<FileUpload> { return this.db.list(this.basePath, ref => ref.limitToLast(numberItems)); } deleteFileUpload(fileUpload: FileUpload) { this.deleteFileDatabase(fileUpload.key) .then(() => { this.deleteFileStorage(fileUpload.name); }) .catch(error => console.log(error)); } private deleteFileDatabase(key: string) { return this.db.list(`${this.basePath}/`).remove(key); } private deleteFileStorage(name: string) { const storageRef = firebase.storage().ref(); storageRef.child(`${this.basePath}/${name}`).delete(); } } |
To know how to save file info to Firebase Realtime Database, please visit previous post:
Angular 4 Firebase – Upload File to Storage
3. Get and display List of Images
import { map } from 'rxjs/operators'; import { UploadFileService } from '../upload-file.service'; @Component({ selector: 'list-upload', templateUrl: './list-upload.component.html', styleUrls: ['./list-upload.component.css'] }) export class ListUploadComponent implements OnInit { fileUploads: any[]; constructor(private uploadService: UploadFileService) { } ngOnInit() { // Use snapshotChanges().pipe(map()) to store the key this.uploadService.getFileUploads(6).snapshotChanges().pipe( map(changes => changes.map(c => ({ key: c.payload.key, ...c.payload.val() })) ) ).subscribe(fileUploads => { this.fileUploads = fileUploads; }); } } |
HTML template:
<div *ngFor="let file of fileUploads"> {{file.name}} <img src="{{file.url}}"/> </div> |
4. Check image format
if (file.type.match('image.*')) { // do something } else { alert('invalid format!'); } |
III. Practice
1. Project Overview
1.1 Goal
We will build an Angular 6 Firebase App that can:
– helps user choose image file from local and upload it to Firebase Storage
– show progress with percentage
– save image metadata to Firebase Realtime Database
(Functions above from the posts: Angular 4 Firebase – Upload File to Storage)
– get list Images and display
1.2 Structure
2. Step by step
2.1 Set up the Firebase Project & Install AngularFire2
Please visit this post to know step by step.
*Note: Don’t forget to set RULES for public read/write Database and Storage.
2.2 Add Firebase config to environments variable
Open /src/environments/environment.ts, add your Firebase configuration that we have saved when Popup window was shown:
export const environment = { production: false, firebase: { apiKey: 'xxx', authDomain: 'jsa-angular6.firebaseapp.com', databaseURL: 'https://jsa-angular6.firebaseio.com', projectId: 'jsa-angular6', storageBucket: 'jsa-angular6.appspot.com', messagingSenderId: 'xxx' } }; |
2.3 Create Service & Components
Run the commands below:
– ng g s upload/UploadFile
– ng g c upload/FormUpload
– ng g c upload/ListUpload
– ng g c upload/DetailsUpload
2.4 Setup @NgModule
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AngularFireDatabaseModule } from 'angularfire2/database'; import { AngularFireModule } from 'angularfire2'; import { environment } from '../environments/environment'; import { AppComponent } from './app.component'; import { FormUploadComponent } from './upload/form-upload/form-upload.component'; import { ListUploadComponent } from './upload/list-upload/list-upload.component'; import { DetailsUploadComponent } from './upload/details-upload/details-upload.component'; @NgModule({ declarations: [ AppComponent, FormUploadComponent, ListUploadComponent, DetailsUploadComponent ], imports: [ BrowserModule, AngularFireModule.initializeApp(environment.firebase), AngularFireDatabaseModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } |
2.5 Model Class
fileupload.ts
export class FileUpload { key: string; name: string; url: string; file: File; constructor(file: File) { this.file = file; } } |
2.6 Service
upload-file.service.ts
import { Injectable } from '@angular/core'; import { AngularFireDatabase, AngularFireList } from 'angularfire2/database'; import * as firebase from 'firebase/app'; import 'firebase/storage'; import { FileUpload } from './fileupload'; @Injectable({ providedIn: 'root' }) export class UploadFileService { private basePath = '/uploads'; constructor(private db: AngularFireDatabase) { } pushFileToStorage(fileUpload: FileUpload, progress: { percentage: number }) { const storageRef = firebase.storage().ref(); const uploadTask = storageRef.child(`${this.basePath}/${fileUpload.file.name}`).put(fileUpload.file); uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED, (snapshot) => { // in progress const snap = snapshot as firebase.storage.UploadTaskSnapshot; progress.percentage = Math.round((snap.bytesTransferred / snap.totalBytes) * 100); }, (error) => { // fail console.log(error); }, () => { // success uploadTask.snapshot.ref.getDownloadURL().then(downloadURL => { console.log('File available at', downloadURL); fileUpload.url = downloadURL; fileUpload.name = fileUpload.file.name; this.saveFileData(fileUpload); }); } ); } private saveFileData(fileUpload: FileUpload) { this.db.list(`${this.basePath}/`).push(fileUpload); } getFileUploads(numberItems): AngularFireList<FileUpload> { return this.db.list(this.basePath, ref => ref.limitToLast(numberItems)); } deleteFileUpload(fileUpload: FileUpload) { this.deleteFileDatabase(fileUpload.key) .then(() => { this.deleteFileStorage(fileUpload.name); }) .catch(error => console.log(error)); } private deleteFileDatabase(key: string) { return this.db.list(`${this.basePath}/`).remove(key); } private deleteFileStorage(name: string) { const storageRef = firebase.storage().ref(); storageRef.child(`${this.basePath}/${name}`).delete(); } } |
2.7 Form Upload Compoment
form-upload.component.ts
import { Component, OnInit } from '@angular/core'; import { UploadFileService } from '../upload-file.service'; import { FileUpload } from '../fileupload'; @Component({ selector: 'form-upload', templateUrl: './form-upload.component.html', styleUrls: ['./form-upload.component.css'] }) export class FormUploadComponent implements OnInit { selectedFiles: FileList; currentFileUpload: FileUpload; progress: { percentage: number } = { percentage: 0 }; constructor(private uploadService: UploadFileService) { } ngOnInit() { } selectFile(event) { const file = event.target.files.item(0); if (file.type.match('image.*')) { this.selectedFiles = event.target.files; } else { alert('invalid format!'); } } upload() { const file = this.selectedFiles.item(0); this.selectedFiles = undefined; this.currentFileUpload = new FileUpload(file); this.uploadService.pushFileToStorage(this.currentFileUpload, this.progress); } } |
form-upload.component.html:
<div *ngIf="currentFileUpload" class="progress"> <div class="progress-bar progress-bar-info progress-bar-striped" role="progressbar" attr.aria-valuenow="{{progress.percentage}}" aria-valuemin="0" aria-valuemax="100" [ngStyle]="{width:progress.percentage+'%'}"> {{progress.percentage}}%</div> </div> <label class="btn btn-default"> <input type="file" (change)="selectFile($event)"> </label> <button class="btn btn-success" [disabled]="!selectedFiles" (click)="upload()">Upload</button> |
2.8 DetailsUpload Component
details-upload.component.ts
import { Component, OnInit, Input } from '@angular/core'; import { FileUpload } from '../fileupload'; import { UploadFileService } from '../upload-file.service'; @Component({ selector: 'details-upload', templateUrl: './details-upload.component.html', styleUrls: ['./details-upload.component.css'] }) export class DetailsUploadComponent implements OnInit { @Input() fileUpload: FileUpload; constructor(private uploadService: UploadFileService) { } ngOnInit() { } deleteFileUpload(fileUpload) { this.uploadService.deleteFileUpload(fileUpload); } } |
details-upload.component.html
{{fileUpload.name}} <button (click)='deleteFileUpload(fileUpload)' class="btn btn-danger btn-xs" style="float: right">Delete</button> <img src="{{fileUpload.url}}" alt="{{fileUpload.name}}" style="max-width:350px" /> |
2.9 ListUpload Component
list-upload.component.ts
import { Component, OnInit } from '@angular/core'; import { map } from 'rxjs/operators'; import { UploadFileService } from '../upload-file.service'; @Component({ selector: 'list-upload', templateUrl: './list-upload.component.html', styleUrls: ['./list-upload.component.css'] }) export class ListUploadComponent implements OnInit { fileUploads: any[]; constructor(private uploadService: UploadFileService) { } ngOnInit() { // Use snapshotChanges().pipe(map()) to store the key this.uploadService.getFileUploads(6).snapshotChanges().pipe( map(changes => changes.map(c => ({ key: c.payload.key, ...c.payload.val() })) ) ).subscribe(fileUploads => { this.fileUploads = fileUploads; }); } } |
list-upload.component.html
<div class="panel panel-primary"> <div class="panel-heading">List of Images</div> <div *ngFor="let file of fileUploads"> <div class="panel-body"> <details-upload [fileUpload]='file'></details-upload> </div> </div> </div> |
2.10 App Component
app.component.ts
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'JavaSampleApproach'; description = 'Angular-Firebase Demo'; } |
app.component.html
<div class="container" style="width:400px"> <div style="color: blue; margin-bottom: 20px"> <h1>{{title}}</h1> <h3>{{description}}</h3> </div> <form-upload></form-upload> <br/> <br/> <list-upload></list-upload> </div> |
2.11 Check Result
Run the App, go to http://localhost:4200/
.
Check Firebase Console:
– Database:
– Storage:
IV. Source Code
Angular6FirebaseStorage-Images
Last updated on November 29, 2018.
Hi.
Can you do upload and display image with Spring Boot + Angular 6 + Mysql.
Thanks in advance.
Hi Mirza,
You can visit this tutorial 🙂
Angular 6 Client – Upload Files/Download Files to MySQL with SpringBoot RestAPIs example
Regards,
JSA.
Grate tutorial, any help on how to use cloud firestore to archive this same operation?