Intended to be run with Angular 12, AngularFire 7.0 allows you to take full advantage of the new tree-shakable Firebase JS SDK (v9) while also providing a compatible experience with the prior API.
ng update @angular/fire
- Angular 12 is required
- AngularFire now only works in Ivy applications
- Firebase JS SDK v9 is required
- The existing AngularFire v6 API surface has moved from
@angular/fire/*
to@angular/fire/compat/*
(see compatibility mode) - compat/auth:
USE_EMULATOR
DI token is now in the form of['http://localhost:9099']
AngularFire v7.0 has a compatibility layer that supports the AngularFire v6.0 API. Just change your imports from @angular/fire/*
to @angular/fire/compat/*
and firebase/*
to firebase/compat/*
.
While not as tree-shakable as the new modular SDK, this allows you to upgrade and take advantage of the benefits of the new SDK ASAP.
Most developers can stop here for now as the new API isn't feature complete.
In order to better support the tree-shakability introduced in Firebase v9 & to reduce the maintence required when the JS SDK adds new configuration flags, AngularFire providers now take a factory for a fully instantiated instance of the SDK you'd like to inject.
Before:
@NgModule({
imports: [
AngularFireModule.initializeApp(config),
AngularFirestoreModule.enablePersistence(),
AngularFireStorageModule,
],
providers: [
{ provide: USE_EMULATOR, useValue: ['localhost', 8080] },
],
})
Modular SDK:
@NgModule({
imports: [
provideFirebaseApp(() => initializeApp(config)),
provideFirestore(() => {
const firestore = getFirestore();
connectFirestoreEmulator(firestore, 'localhost', 8080);
enableIndexedDbPersistence(firestore);
return firestore;
}),
provideStorage(() => getStorage()),
],
})
Before when you injected Firebase JS SDK services into AngularFire they would be lazy-loaded and a promise-proxy would be returned to you. In AngularFire v7 you get the intiated service directly. We no longer lazy load for you.
import { Firestore, doc, onSnapshot, DocumentReference, docSnapshots } from '@angular/fire/firestore';
@Component({})
export class Foo {
doc: DocumentReference;
constructor(
firestore: Firestore, // Injects the instantiated Firestore instance
) {
// You can directly operate on the instance with JS SDK methods which we've
// reexported in AngularFire
this.doc = doc(firestore, 'foo/1');
onSnapshot(doc, snap => {
// ...
});
// or use the convenience observables
docSnapshots(doc).subscribe(...);
}
async update() {
await updateDoc(this.doc, { ... });
...
}
}
In AngularFire v7 working with multiple instances was difficult, in the new SDK we have new DI tokens that make working with them much more straight forward.
@NgModule({
imports: [
provideFirebaseApp(() => initializeApp(config)),
provideFirebaseApp(() => initializeApp(config2, 'anotherApp')),
provideStorage(() => getStorage()),
provideStorage(() => getStorage(getApp(), 'anotherBucket')),
provideStorage(() => getStorage(getApp('anotherApp'))),
],
})
import { FirebaseApp, FirebaseApps } from '@angular/fire/app';
import { Storage, StorageInstances } from '@angular/fire/storage';
export class Foo {
constructor(
defaultApp: FirebaseApp, // Injects the default FirebaseApp
allFirebaseApps: FirebaseApps, // Injects an array of all initialized Firebase Apps
storage: Storage, // Injects the default storage instance
allStorageInstances: StorageInstances, // Injects an array of all the intialized storage instances
) { }
}
How the main injection tokens (i.e, FirebaseApp
, Storage
) function have changed from v7 but it should provide a much more powerful and intuitive API.
Beyond Depdency Injection AngularFire is sporting an entirely new API:
- We no longer handle lazy-loading the Firebase JS SDK modules for you
- We no longer provide classes beyond Depedency Injection
- No more Proxy / Promise-Proxy
- We reexport and Zone-wrap all Firebase and RxFire APIs
So developing with the new AngularFire is easy, you can use it just like the vanilla Firebase JS SDK. Just change all your firebase/app
imports to @angular/fire/app
, firebase/firestore
to @angular/fire/firestore
, firebase/database
to @angular/fire/database
, etc. Then if you're feeling comfortable with RXJS and would like to use some of our convenience operators you can just dip into that toolbox.
v6 / Compat | v7 Modular | |
---|---|---|
AngularFirestore | doc |
import { doc } from '@angular/fire/firestore';
doc<T>(firestore, 'foo/bar') // DocumentReference<T> |
collection |
import { collection } from '@angular/fire/firestore';
collection<T>(firestore, 'foo') // CollectionReference<T> |
|
collectionGroup |
import { collectionGroup } from '@angular/fire/firestore';
collectionGroup<T>(firestore, 'foo') // Query<T> |
|
AngularFirestoreDocument | set |
import { setDoc } from '@angular/fire/firestore';
setDoc(docRef, { ... }) // Promise<void> |
update |
import { updateDoc } from '@angular/fire/firestore';
updateDoc(docRef, { ... }) // Promise<void> |
|
delete |
import { deleteDoc } from '@angular/fire/firestore';
deleteDoc(docRef) // Promise<void> |
|
collection |
import { collection } from '@angular/fire/firestore';
collection<T>(docRef, 'bar') // CollectionReference<T> |
|
snapshotChanges |
import { docSnapshots } from '@angular/fire/firestore';
docSnapshots<T>(docRef) // Observable<DocumentSnapshot<T>> |
|
valueChanges |
import { docData } from '@angular/fire/firestore';
docData<T>(docRef) // Observable<T> |
|
get |
import { getDoc } from '@angular/fire/firestore';
getDoc<T>(docRef) // Promise<DocumentSnapshot<T>> |
AngularFire does not lazy-load services any longer. We have provided a helper observable for detecting when a new service instance is instantiated. In this example we'll code split out of all the Firestore related code and lazy-load
// firestore_operations.ts
import {
collectionData,
firestoreInstance$,
collection,
getFirestore
} from '@angular/fire/firestore';
import { first } from 'rxjs/operators';
import { IFoo } from '../interfaces';
export { getFirestore };
export const fooData = firestoreInstance$.pipe(
first(),
concatMap(firestore => collectionData<IFoo>(collection(firestore, 'foo'))),
);
export class AuthService {
constructor() {
getRedirectResult().then(result => {
// Initialize Firestore only after a user logs in
if (result.user) {
const { getFirestore } = await import('./firestore_operations');
getFirestore();
}
});
}
}
@Component({})
export class Foo {
data: Observable<IFoo[]>;
constructor() {
this.data = of(undefined).pipe(
concatMap(() => import('./firestore_operations')),
concatMap(it => it.fooData)
);
}
}