Angular 12 with Firebase 9
Tags: angular, firebase, firestore, rxjs
Published: 2021-09-06 23:19:35

## Update 3/7/24
For a modern Angular Firebase App, see my latest post:
https://code.build/p/angular-todo-app-with-firebase-fmLJ37

___
## Original Post
___
## Quick Reference

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

**app.module.ts** - Imports
```typescript
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
  ],
})
```
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**
```typescript
import {
  collection,
  doc,
  docData,
  DocumentReference,
  CollectionReference,
  Firestore,
  onSnapshot,
  query,
  where,
  Unsubscribe,
  Query,
  DocumentData,
  collectionData,
  collectionChanges,
  docSnapshots,
  ...
} from '@angular/fire/firestore';
```

**constructor**
```typescript
constructor(
  private afs: Firestore
) { }
```

## Documents
**valueChanges()**
```typescript
docData<Post>(
  doc(this.afs, 'posts', id)
);
```

**snapShotChanges()**
```typescript
docSnapshots<Post>(
  doc(this.afs, `posts/${id}`)
);
```


## Collections

**valueChanges()**
```typescript
collectionData<Post>(
  query<Post>(
    collection(this.afs, 'posts') as CollectionReference<Post>,
    where('published', '==', true)
  ), { idField: 'id' }
);
```

**snapShotChanges()**
```typescript
collectionChanges<Post>(
  query<Post>(
    collection(this.afs, 'posts') as CollectionReference<Post>,
    where('published', '==', true)
  )
);
```

**createId()**
```typescript
doc(collection(this.afs, 'id')).id;
```

## Auth

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

### Code

```typescript
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) {
    ...
  }
}
```

## Storage

**Import**
```typescript
import {
  Storage,
  ref,
  deleteObject,
  uploadBytes,
  uploadString,
  uploadBytesResumable,
  percentage,
  getDownloadURL,
  ...
} from '@angular/fire/storage';
```

### Code
```typescript
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;
}
```

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.

- For that see [Code.Build](https://code.build/p/LWmSi3HfQzu5TMKPzb5p6i/angular-12-with-firebase-9).

- Or Firebase 9 [Official Docs](https://firebase.google.com/docs/firestore/quickstart)

- Here is also an official [angularfire sample project](https://github.com/angular/angularfire/tree/master/samples/modular)

J