DEV Community 👩‍💻👨‍💻

Cover image for Angular 12 with Firebase 9
Jonathan Gamble
Jonathan Gamble

Posted on • Updated on • Originally published at fireblog.io

Angular 12 with Firebase 9

Quick Reference

Angular's Docs have not been updated fully yet, so I made a quick reference.

app.module.ts - Imports

import { provideFirebaseApp, initializeApp } 
from '@angular/fire/app';
import { getAuth, provideAuth } 
from '@angular/fire/auth';
import { getFirestore, provideFirestore } 
from '@angular/fire/firestore';
import { getStorage, provideStorage } 
from '@angular/fire/storage';
import {
  getAnalytics,
  provideAnalytics,
  ScreenTrackingService,
  UserTrackingService
} from '@angular/fire/analytics';
...

@NgModule({
  declarations: [],
  imports: [
    provideAnalytics(() => getAnalytics()),
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideFirestore(() => getFirestore()),
    provideAuth(() => getAuth()),
    provideStorage(() => getStorage())
    ...
  ],
  providers: [
    ScreenTrackingService,
    UserTrackingService
  ],
})
Enter fullscreen mode Exit fullscreen mode

Note: For Angular Universal SSR, you may have problems with provideAnalytics(). Either use the old version, or only load it on the server version. I could not get it to work correctly in regular Angular, but they may have fixed the code in a newer version.

import

import {
  collection,
  doc,
  docData,
  DocumentReference,
  CollectionReference,
  Firestore,
  onSnapshot,
  query,
  where,
  Unsubscribe,
  Query,
  DocumentData,
  collectionData,
  collectionChanges,
  docSnapshots,
  ...
} from '@angular/fire/firestore';
Enter fullscreen mode Exit fullscreen mode

constructor

constructor(
  private afs: Firestore
) { }
Enter fullscreen mode Exit fullscreen mode

Documents

valueChanges()

docData<Post>(
  doc(this.afs, 'posts', id)
);
Enter fullscreen mode Exit fullscreen mode

snapShotChanges()

docSnapshots<Post>(
  doc(this.afs, `posts/${id}`)
);
Enter fullscreen mode Exit fullscreen mode

Collections

valueChanges()

collectionData<Post>(
  query<Post>(
    collection(this.afs, 'posts') as CollectionReference<Post>,
    where('published', '==', true)
  ), { idField: 'id' }
);
Enter fullscreen mode Exit fullscreen mode

snapShotChanges()

collectionChanges<Post>(
  query<Post>(
    collection(this.afs, 'posts') as CollectionReference<Post>,
    where('published', '==', true)
  )
);
Enter fullscreen mode Exit fullscreen mode

createId()

doc(collection(this.afs, 'id')).id;
Enter fullscreen mode Exit fullscreen mode

Auth

imports

import {
  Auth,
  signOut,
  signInWithPopup,
  user,
  signInWithEmailAndPassword,
  createUserWithEmailAndPassword,
  updateProfile,
  sendEmailVerification,
  sendPasswordResetEmail,
  getAdditionalUserInfo,
  OAuthProvider,
  linkWithPopup,
  unlink,
  updateEmail,
  updatePassword,
  User,
  reauthenticateWithPopup,
  authState,
  onAuthStateChanged
  ...
} from '@angular/fire/auth';
Enter fullscreen mode Exit fullscreen mode

Code

user$: Observable<User | null>;

constructor(private auth: Auth) {

  // user observable, not user doc
  this.user$ = user(auth);

  // or use this version...
  this.user$ = authState(auth);

  // or use this version...
  this.user$ = new Observable((observer: any) =>
    onAuthStateChanged(auth, observer)
  );

  // or pipe user doc, Profile interface
  // returns user doc, not User type
  // here this.user$: Observable<Profile | null>;
  this.user$ = user(auth).pipe(
      switchMap((user: User | null) =>
        user
          ? docData(doc(this.afs, 'users', user.uid))
            as Observable<Profile>
          : of(null)
      )
    );

}

async getUser(): Promise<User | null> {
  return await this.user$.pipe(take(1)).toPromise();
}

...

async emailLogin(email: string, password: string)
: Promise<any> {
  return await signInWithEmailAndPassword(this.auth, email, password);
}

async emailSignUp(email: string, password: string)
: Promise<void> {

  const credential = await createUserWithEmailAndPassword(
    this.auth,
    email,
    password
  );
  await updateProfile(
    credential.user, { displayName: credential.user.displayName }
  );
  await sendEmailVerification(credential.user);

  // create user in db
  ...
}

async resetPassword(email: string): Promise<any> {

  // sends reset password email
  await sendPasswordResetEmail(this.auth, email);
  ...
}

async oAuthLogin(p: string): Promise<void> {

  // get provider, sign in
  const provider = new OAuthProvider(p);
  const credential = await signInWithPopup(this.auth, provider);
  const additionalInfo = getAdditionalUserInfo(credential);

  // create user in db
  if (additionalInfo?.isNewUser) {
    ...
  }
}
Enter fullscreen mode Exit fullscreen mode

Storage

Import

import {
  Storage,
  ref,
  deleteObject,
  uploadBytes,
  uploadString,
  uploadBytesResumable,
  percentage,
  getDownloadURL,
  ...
} from '@angular/fire/storage';
Enter fullscreen mode Exit fullscreen mode

Code

uploadPercent: Observable<number>;

constructor(private storage: Storage) { }

async upload(
  folder: string,
  name: string,
  file: File | null
): Promise<string> {

  const ext = file!.name.split('.').pop();
  const path = `${folder}/${name}.${ext}`; {

  if (file) {
    try {
      const storageRef = ref(this.storage, path);
      const task = uploadBytesResumable(storageRef, file);
      this.uploadPercent = percentage(task);
      await task;
      const url = await getDownloadURL(storageRef);
    } catch(e: any) {
      console.error(e);
    }   
  } else {
    // handle invalid file
  }
  return url;
}
Enter fullscreen mode Exit fullscreen mode

I may update this with more items, but I wanted to be particular to Angular and not get into the general Firebase 9 updates. I didn't want to show every possible example, but you start to see the patterns.

J

Top comments (16)

Collapse
joel2k0 profile image
Joel • Edited on

Type casting is not working here:

docSnapshots<Post>(
  doc(this.afs, `posts/${id}`)
);
Enter fullscreen mode Exit fullscreen mode
Argument of type 'DocumentReference<DocumentData>' is not assignable to parameter of type 'DocumentReference<Post>'.
  The types returned by 'converter.fromFirestore(...)' are incompatible between these types.
    Type 'DocumentData' is not assignable to type 'Post'.ts(2345)
Enter fullscreen mode Exit fullscreen mode
Collapse
jdgamble555 profile image
Jonathan Gamble Author • Edited on

Yes, Angular Firebase is definitely not perfected code with Firebase 9. You can get around that with:

docSnapshots<Post>(
  doc(this.afs, `posts/${id}`) as DocumentReference<Post>
);
Enter fullscreen mode Exit fullscreen mode
Collapse
free_the_bees profile image
Michael Peake

Thank you. This has been very useful today. I'm starting a new project and want to use the new APIs but the lack of documentation is infuriating.

Collapse
vulps profile image
Andrew MacFarlane

I have been scouring the internet for 24 hours looking for an example of how to implement the new AngularFire Auth API!! thank you!!!

Collapse
alsmith141510 profile image
Alsmith141510

HI: This code doesn't work with 7.4.1 and angular 14.
this.user$ = user(auth).pipe(
switchMap((user: User | null) =>
user
? docData(doc(this.afs, 'users', user.uid))
as Observable
: of(null)
)
);

Collapse
neelavar profile image
Prasanna Neelavar

Very good reference and crisp representation of the required imports & implementation without any fluff. Thank you.

Collapse
kaliahaze profile image
Kalia Hayes

Great reference, thank you. Turns out when you step away from AngularFire for a year+ several things change lol.

Collapse
baluditor profile image
Baluditor

Thanks. I was loosing my sanity over the official docs.

Collapse
apluspluslabs profile image
A++Labs

great article
do u have anywhare u go in details about the use of collections search where, pagination... in angular 12+ firestore 9 (angularfire 7)

Collapse
jdgamble555 profile image
Jonathan Gamble Author

Yes, just look at the where examples above. Pagination will use limit() and orderBy() as usual, just import them.

Collapse
desoga profile image
deji adesoga

Exellent resource. I am currently working on a tutorial using Angular 12 with firebase 9.

Collapse
paxforce profile image
Patrick Simonski

Thanks so much for this! You wrote "I may update this with more items..." and I cant' wait. We need articles like this, bc the official @angular/angularfire documentation is awful.

Collapse
jdgamble555 profile image
Jonathan Gamble Author

Is there something you specifically need? If so I can add it!

Collapse
paxforce profile image
Patrick Simonski

Nothing specific, just more of that juicy stuff - the more the better.

Collapse
island_dev profile image
Joey The Dev

You saved a life today. Thank you

Collapse
dragosilies profile image
DragosIlies

When adding a new document to firestore, how do we tell it to auto generate id? If I don't put id in doc() it gives me an error.

🌚 Friends don't let friends browse without dark mode.

Sorry, it's true.