Accessing firebase.storage() with AngularFire2 (Angular2 rc.5)

Victor Locoman picture Victor Locoman · Aug 21, 2016 · Viewed 12.3k times · Source


I am trying to access firebase.storage() on my project, with:

  • "@angular": "2.0.0-rc.5"
  • "angularfire2": "^2.0.0-beta.3-pre2"
  • "firebase": "^3.3.0"

I found this solution, and created my .component.ts file with:

import { Component } from '@angular/core';
declare var firebase : any;

@Component({
  template: '<img [src]="image">'
})
export class RecipesComponent {
  image: string;
  constructor() {
    const storageRef = firebase.storage().ref().child('images/image.png');
    storageRef.getDownloadURL().then(url => this.image = url);
  }
}

and I get the following error in the browser console:

EXCEPTION: Error: Uncaught (in promise): EXCEPTION: Error in ./bstorageComponent class FBStorageComponent_Host - inline template:0:0
ORIGINAL EXCEPTION: Error: No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp().
ORIGINAL STACKTRACE:
Error: No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp().

but, I initialised firebase in app.module.ts with this import

AngularFireModule.initializeApp(firebaseConfig)

I'm not getting what I'm missing. How can I access storage using firebase? I have no problem with accessing database with angularfire2.
Thanks

Answer

cartant picture cartant · Aug 22, 2016

Internally, AngularFire2 calls Firebase's initializeApp in a DI factory when creating its FirebaseApp.

You are seeing the error because you are accessing the global firebase instance and initializeApp has not yet been called - as the DI infrastructure has not needed to create FirebaseApp or any of its dependencies.

Rather than using the global firebase, you could inject FirebaseApp (which is the value returned by Firebase's initializeApp function):

import { Component, Inject } from '@angular/core';
import { FirebaseApp } from 'angularfire2';

@Component({
  template: '<img [src]="image">'
})
export class RecipesComponent {
  image: string;
  constructor(@Inject(FirebaseApp) firebaseApp: any) {
    const storageRef = firebaseApp.storage().ref().child('images/image.png');
    storageRef.getDownloadURL().then(url => this.image = url);
  }
}

And, as it's no longer required, you could delete declare var firebase : any;.


Early versions of the Firebase NPM module did not include typings. Recent versions now include them, so the firebaseApp property could be strongly typed like this:

import { Component, Inject } from '@angular/core';
import { FirebaseApp } from 'angularfire2';
import * as firebase from 'firebase';

@Component({
  template: '<img [src]="image">'
})
export class RecipesComponent {
  image: string;
  constructor(@Inject(FirebaseApp) firebaseApp: firebase.app.App) {
    const storageRef = firebaseApp.storage().ref().child('images/image.png');
    storageRef.getDownloadURL().then(url => this.image = url);
  }
}

With the refactoring that accompanied the version 4 release candidate of AngularFire2, FirebaseApp is no longer a token, so the injection can be simplified:

import { Component, Inject } from '@angular/core';
import { FirebaseApp } from 'angularfire2';
import 'firebase/storage';

@Component({
  template: '<img [src]="image">'
})
export class RecipesComponent {
  image: string;
  constructor(firebaseApp: FirebaseApp) {
    const storageRef = firebaseApp.storage().ref().child('images/image.png');
    storageRef.getDownloadURL().then(url => this.image = url);
  }
}

However, an explicit import of firebase/storage is required because AngularFire2 now imports only the portions of the Firebase API that it uses. (Note that there is a proposal for storage support.)