I have following issue
Got AuthService.ts where I authenticate my users with google account. In the same service I'm sending user details to Firestore db, such as uid, email, etc.
Now. In a component I need to get that uid from logged user, so in a constructor I've defined my AuthService and trying to get the uid.
When I go with this.auth.user.subscribe(user => console.log(user.uid));
It seems to work -> console logging the uid.
But, when I'm trying to assing it to a variable and console log / use the variable it goes with undefined
error.
Here is the code:
this.auth.user.subscribe(user => this.userDoc = this.afs.doc(
users/${user.uid}));
this.user = this.userDoc.valueChanges();
console.log(this.user);
What am I doing wrong?
Thats my component code:
import { Component, OnInit } from '@angular/core';
import {AngularFirestore, AngularFirestoreDocument} from 'angularfire2/firestore';
import {Observable} from 'rxjs/Observable';
import {AuthService} from '../core/auth.service';
@Component({
selector: 'app-judge-dashboard',
templateUrl: './judge-dashboard.component.html',
styleUrls: ['./judge-dashboard.component.css']
})
export class JudgeDashboardComponent implements OnInit {
// entryDoc: AngularFirestoreDocument<any>;
// entry: Observable<any>;
userDoc: AngularFirestoreDocument<any>;
user: Observable<any>;
constructor(public auth: AuthService, private afs: AngularFirestore) { }
ngOnInit() {
this.auth.user.subscribe(user => console.log(user.uid)); //it works
this.auth.user.subscribe(user => this.userDoc = this.afs.doc(`users/${user.uid}`));
this.user = this.userDoc.valueChanges();
console.log(this.user); // this one undefined
}
}
And the AuthService:
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import * as firebase from 'firebase/app';
import { AngularFireAuth } from 'angularfire2/auth';
import { AngularFirestore, AngularFirestoreDocument } from 'angularfire2/firestore';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/switchMap';
import { User } from '../user';
@Injectable()
export class AuthService {
user: Observable<User>;
constructor(private afAuth: AngularFireAuth,
private afs: AngularFirestore,
private router: Router) {
//// Get auth data, then get firestore user document || null
this.user = this.afAuth.authState
.switchMap(user => {
if (user) {
return this.afs.doc<User>(`users/${user.uid}`).valueChanges();
} else {
return Observable.of(null);
}
});
}
googleLogin() {
const provider = new firebase.auth.GoogleAuthProvider();
return this.oAuthLogin(provider);
}
private oAuthLogin(provider) {
return this.afAuth.auth.signInWithPopup(provider)
.then((credential) => {
this.updateUserData(credential.user);
});
}
private updateUserData(user) {
// Sets user data to firestore on login
const userRef: AngularFirestoreDocument<any> = this.afs.doc(`users/${user.uid}`);
const data: User = {
uid: user.uid,
email: user.email,
roles: {
author: true
},
displayName: user.displayName || 'someDefaultValue',
photoURL: user.photoURL
};
return userRef.set(data, { merge: true }); // without {merge:true} it will overwrite nor update.
}
signOut() {
this.afAuth.auth.signOut().then(() => {
this.router.navigate(['/']);
});
}
///// Abilities and Roles Authorizations
///// Assign roles to an ability method
canRead(user: User): boolean {
const allowed = ['admin', 'author', 'judge', 'partner'];
return this.checkAutorization(user, allowed);
}
// determines if user has matching role
private checkAutorization(user: User, allowedRoles: string[]) {
if (!user) { return false; }
for (const role of allowedRoles) {
if ( user.roles[role] ) {
return true;
}
}
return false;
}
}
Even if I go like this:
uid: string;
ngOnInit() {
this.auth.user.subscribe(user => {
this.uid = user.uid;
console.log(user.uid);
});
console.log(this.uid);
First console log works. Second one gives "undefined"
That's because it's an asynchronous method, considering this code block:
ngOnInit() {
this.auth.user.subscribe(user => {
this.uid = user.uid;
console.log(user.uid);
});
console.log(this.uid);
}
At first, subscribe
to the user observable is called,
then the second console.log(this.uid);
(where this.uid is still undefined) is called,
then when the value is pushed into the observable leading to the block inside the suscription callback being called:
this.uid = user.uid;
console.log(user.uid);
It's all about being async!