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 5 App.
I. Technology
– Angular 5
– 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, progress: { percentage: number }) { 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{ 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 { FileUpload } from '../fileupload'; import { UploadFileService } from '../upload-file.service'; export class ListUploadComponent implements OnInit { fileUploads: any[]; constructor(private uploadService: UploadFileService) { } ngOnInit() { // Use snapshotChanges().map() to store the key this.uploadService.getFileUploads(6).snapshotChanges().map(changes => { return changes.map(c => ({ key: c.payload.key, ...c.payload.val() })); }).subscribe(fileUploads => { this.fileUploads = fileUploads; }); } }
HTML template:
{{file.name}}![]()
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 5 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-angular5.firebaseapp.com', databaseURL: 'https://jsa-angular5.firebaseio.com', projectId: 'jsa-angular5', storageBucket: 'xxxbucket.appspot.com', messagingSenderId: 'xxx' } };
2.3 Setup @NgModule
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 { UploadFileService } from './upload/upload-file.service'; 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: [UploadFileService], bootstrap: [AppComponent] }) export class AppModule { }
2.4 Model Class
export class FileUpload { key: string; name: string; url: string; file: File; constructor(file: File) { this.file = file; } }
2.5 Service
import { Injectable } from '@angular/core'; import { AngularFireDatabase, AngularFireList } from 'angularfire2/database'; import * as firebase from 'firebase'; import { FileUpload } from './fileupload'; @Injectable() 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 fileUpload.url = uploadTask.snapshot.downloadURL; fileUpload.name = fileUpload.file.name; this.saveFileData(fileUpload); } ); } private saveFileData(fileUpload: FileUpload) { this.db.list(`${this.basePath}/`).push(fileUpload); } getFileUploads(numberItems): AngularFireList{ 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.6 Form Upload Compoment
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:
2.7 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}}![]()
2.8 ListUpload Component
list-upload.component.ts
import { Component, OnInit } from '@angular/core'; import { FileUpload } from '../fileupload'; 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().map() to store the key this.uploadService.getFileUploads(6).snapshotChanges().map(changes => { return changes.map(c => ({ key: c.payload.key, ...c.payload.val() })); }).subscribe(fileUploads => { this.fileUploads = fileUploads; }); } }
list-upload.component.html
List of Images
2.9 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 = 'Angular5-Firebase Demo'; }
app.component.html
{{title}}
{{description}}
2.10 Check Result
Run the App, go to http://localhost:4200/
.
Check Firebase Console:
– Database:
– Storage:
IV. Source Code
Angular5FirebaseStorage-list-images
Last updated on November 29, 2018.
Dear Admin of JavaSampleApproach. I’m very thankful for all of stuffs you did for this Angular and Firebase Tutorial, These are what I was looking for days. A great presentation of tutorial like this. God bless you admin. Thank you for all of these tutorials. Keep doing good content !
Radvil from Indonesia
Hi Radvil,
Thank you so much for your comment, it makes us feel motivated to keep working 🙂
Best Regards,
JSA.
[ts] Property ‘map’ does not exist on type ‘Observable<AngularFireAction<DatabaseSnapshot>[]>’.
error in ListUploadComponent.ts.
Please help.
Property ‘key’ does not exist on type ‘DatabaseSnapshot’.
Property ‘key’ does not exist on type ‘DatabaseSnapshotExists’.
Getting this error, Please help.
import { Component , OnInit} from ‘@angular/core’;
import { Hero} from ‘./hero’;
import {AngularFireList, AngularFireDatabase} from ‘@angular/fire/database’;
@Component({
selector: ‘app-root’,
templateUrl: ‘./app.component.html’,
styleUrls: [‘./app.component.css’]
})
export class AppComponent implements OnInit {
title = ‘Angular Pipe Testing’;
todaydate = new Date();
heros: AngularFireList;
heroslist: Hero[];
selectedhero: Hero;
n = ”;
a = ”;
add = ”;
constructor(private firebase: AngularFireDatabase) {}
ngOnInit() {
const x = this.getData().snapshotChanges();
x.subscribe(item => {
this.heroslist = [];
item.forEach(element => {
const y = element.payload.toJSON();
y[‘$key’] = element.key;
this.heroslist.push(y as Hero);
});
});
}
getData() {
this.heros = this.firebase.list(‘Forms’);
return this.heros;
}
Details(hero: Hero) {
this.selectedhero = hero;
}
MyFormUpload() {
this.heros.push({
name : this.n,
age : this.a,
address: this.add
});
console.log(‘Upload success’);
}
}
export interface Hero {
$key: string;
name: string;
age: string;
address: string
}
I have the same problem with the key does not exist on type ‘DatabaseSnapshot’.
I have review the code, the key error is triggered when trying to display the images from the: ‘ListUploadComponent’. If you delete that part of code it’ll run correctly. Besides, the uploading section works successfully.
I’ll continue to try to display the images, if I find something useful I’ll share.
I continue to trying to fix the error and I found that is related to the image save. When the image is saved it only gets save on the storage, but it doesn’t have a relation in the database, this is due to the fact that the url is not retrieved in the pushFileToStorage Method.
I fixed that by using the method like the next one:
this will return correctly the url of the image from the cloud storage and insert as a register in the database, once that is set the image display bring the images successfully.
Greetings.
error TS2339: Property ‘map’ does not exist on type ‘Observable<AngularFireAction<DatabaseSnapshot>[]>’
it is not sending the downloadURL to firebase database in
angular7 and “angularfire2”: “^5.1.1”
what can i do?
🙁