I understand that Firebase Auth is designed only for Authenticating a user, not to store any user data/profiles or whatever.
I have created a Cloud function that watches for the Auth Service adding a new user, and creates a Firebase document with an ID equal to the Auth.uid:
export const addUser = functions.auth.user().onCreate(async (user) => {
try {
return await admin.firestore().collection("users").doc(user.uid).set({ address: "My street", favouriteFoods: [] });
} catch (error) {
return error;
}
});
What I now want to do is to subscribe to the authentication state on the Angular app, and then create a stream of changes to the Firebase document belonging to the currently logged in user, and remove it when the user logs out. Currently the constructor of my Auth Service looks like this:
public user: Observable<UserInfo> | null = null;
constructor(private auth: AngularFireAuth,
private fs: AngularFirestore,
private router: Router) {
this.authSub = auth.authState.subscribe(userCred => {
this.user = this.fs.doc<UserInfo>(`users/${userCred?.uid}`).snapshotChanges();
});
this.user?.subscribe((userDoc) => {
console.log(userDoc);
})
}
So the problem is that I want to subscribe to the user document, but when the service is constructed, the user hasn't authenticated. I had to define the user as an observable or null because otherwise I was getting a "not initialized" error. I want other components etc to be able to ask the Auth service for things like the user address or favourite foods stored on their related firebase document, but equally destroy them when the user logs out or watch if they get changed.
Cheers
You can use the onAuthStateChanged observer to listen to changes in the user's authentication state and get their Firestore document when they're authenticated, or set the observable to null when they log out.
As per the angular/fire documentation you can get the document data out of the DocumentChangeAction[] returned from snapshotChanges() using the map operator angular/fire
private user: Observable<any> | null = null;
constructor(private auth: AngularFireAuth,
private fs: AngularFirestore,
private router: Router) {
this.auth.onAuthStateChanged(async user => {
if (user) {
this.user = await this.fs.doc<any>(`users/${user.uid}`).snapshotChanges().pipe(
map(actions => {
const id = actions.payload.id;
const data = actions.payload.data();
return {id, ...data}
})
);
} else {
this.user = null;
}
})
}
getUser() {
return this.user;
}