Angular 5 Firebase – Upload/Display/Delete Images from Storage

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

angular-5-firebase-upload-get-images-storage-demo

1.2 Structure

angular-5-firebase-upload-get-images-storage-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:

{{progress.percentage}}%
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}}

{{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/.

angular-5-firebase-upload-get-images-storage-demo

Check Firebase Console:
– Database:

angular-5-firebase-upload-get-images-storage-result-database

– Storage:

angular-5-firebase-upload-get-images-storage-result-storage

IV. Source Code

Angular5FirebaseStorage-list-images



By grokonez | February 19, 2018.

Last updated on November 29, 2018.



Related Posts


11 thoughts on “Angular 5 Firebase – Upload/Display/Delete Images from Storage”

  1. 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

    1. Hi Radvil,

      Thank you so much for your comment, it makes us feel motivated to keep working 🙂

      Best Regards,
      JSA.

  2. [ts] Property ‘map’ does not exist on type ‘Observable<AngularFireAction<DatabaseSnapshot>[]>’.

    error in ListUploadComponent.ts.

    Please help.

  3. Property ‘key’ does not exist on type ‘DatabaseSnapshot’.
    Property ‘key’ does not exist on type ‘DatabaseSnapshotExists’.

    Getting this error, Please help.

    1. 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’);
      }
      }

    1. 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.

      1. 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:

            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('An error had happen');
                        console.log(error);
                    },
                    () => {
                        // success
                        uploadTask.snapshot.ref.getDownloadURL().then(function(downloadURL) {
                            console.log('File available at', downloadURL);
                            fileUpload.url = downloadURL;
                        });
                        fileUpload.name = fileUpload.file.name;
                        this.saveFileData(fileUpload);
                    }
                );
            }
        

        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.

        1. error TS2339: Property ‘map’ does not exist on type ‘Observable<AngularFireAction<DatabaseSnapshot>[]>’

        2. it is not sending the downloadURL to firebase database in
          angular7 and “angularfire2”: “^5.1.1”
          what can i do?
          🙁

          uploadTask.snapshot.ref.getDownloadURL().then(function(downloadURL) {
                          console.log('File available at', downloadURL);
                          fileUpload.url = downloadURL;
                          console.log(fileUpload.url)
                      });
                      fileUpload.name = fileUpload.file.name;
                      this.saveFileData(fileUpload);
          

Got Something To Say:

Your email address will not be published. Required fields are marked *

*