Monomoni
Monomoni

Reputation: 435

AngularFire retrieving document id base on user authentication

I'm setting up a customized user database in firebase where the document id will be stored using the user authentication uid.

The issue I'm currently facing now is storage the current user document to display on my dashboard when the user logs in.

Currently, on my authService.ts I'm storing the data from firebase.user which on my dashboard will display only information from the default array. This is what I have in my auth.service.ts

export class AuthService {
  userData: any; 
  userCollection: AngularFirestoreCollection<User>;
  constructor(

    public afs: AngularFirestore,   // Inject Firestore service
    public afAuth: AngularFireAuth, // Inject Firebase auth service
    public router: Router,  
    public ngZone: NgZone, // NgZone service to remove outside scope warning

  ) {    
    /* Saving user data in localstorage when 
    logged in and setting up null when logged out */
    this.afAuth.authState.subscribe(user => {
      if (user) {
        this.userData = user;
        localStorage.setItem('user', JSON.stringify(this.userData));
        JSON.parse(localStorage.getItem('user'));
        this.UserID = this.userData.uid;
      } else {
        localStorage.setItem('user', null);
        JSON.parse(localStorage.getItem('user'));
      }
    })
  }

  SignUp(username, email, password) {
    return this.afAuth.auth.createUserWithEmailAndPassword(email, password)
      .then((result) => {
        // set account  doc 
          let created_data = JSON.parse(JSON.stringify(result.user));
          const account = {
          uid: result.user.uid,
          created_time: created_data.createdAt,
          email:  result.user.email,
          display_name: username,
          photoURL: result.user.photoURL,
        }
        this.SetUserData(account);
      }).catch((error) => {
        window.alert(error.message)
      })
  }

  /* Setting up user data when sign in with username/password, 
  sign up with username/password and sign in with social auth  
  provider in Firestore database using AngularFirestore + AngularFirestoreDocument service */
  SetUserData(user) {
    const userRef: AngularFirestoreDocument<User> = this.afs.doc(`users/${user.uid}`);
    const userData: User = {
      bio: null,
      country: {
        country: null,
        country_code:null,
        symbol:null
      },
      gender: "unspecified",
      languages: null,
      profile_pic: user.photoURL,
      username: user.display_name,
    }
    return userRef.set(userData, { 
      merge: true
    })
  }
}

and on my dashboard.component.ts

export class DashboardComponent implements OnInit {

  isLoggedIn$: Observable<boolean>;
  isLoggedOut$:Observable<boolean>;

  constructor(
    public afAuth: AngularFireAuth,
    public authService: AuthService
    ) { }

  ngOnInit() {
    this.isLoggedIn$ = this.afAuth.authState.pipe(map(user => !!user));
    this.isLoggedOut$ = this.isLoggedIn$.pipe(map(loggedIn => !loggedIn));
  }
}

with this, I can only get details from whatever is stored in firebase.user and not my customized DB. How do I get into the specific document based on the authenticated user's UID so that I can display the information like bio, gender, and languages?

this is how I'm parsing in the information on my dashboard.html

<!-- Main content -->
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4">
  <div class="inner-adjust">
    <div class="pt-3 pb-2 mb-3 border-bottom">
      <h1 class="h2">User Profile</h1>
    </div>
    <!-- Show user data when logged in -->
    <div class="row" *ngIf="authService.userData as user">
        <div class="col-md-12">
        <div class="media">
          <img class="align-self-start mr-5 img-thumbnail rounded-circle" src="{{(user.photoURL) ? user.photoURL : '/assets/placeholder-user.jpg'}}"
            alt="{{user.displayName}}">
          <div class="media-body">
            <h1>Hello: <strong>{{(user.username)}}</strong></h1>
            <p>Email: <strong>{{user.email}}</strong></p>
            <p>Gender: <strong>{{user.gender}}</strong></p>
            <p>Languages: <strong>{{user.languages}}</strong></p>
          </div>
        </div>
      </div>

      <!-- </div> -->
    </div>

  </div>
</main>

Upvotes: 2

Views: 2123

Answers (1)

AVJT82
AVJT82

Reputation: 73357

I don't see the need to use localStorage, firebase will emit the authstate as long as app is running and if user does not happen to be logged in, authState returns null.

By the way - Also you are using JSON.parse(JSON.stringify(...)) in one place, which makes little sense ;)

Anyway, I have a similar setup and this is how I do it:

in the auth service:

user$ = this.afAuth.authState.pipe(
  switchMap(user => {
    if (user) {
      return this.afs.doc<any>(`users/${user.uid}`).valueChanges();
    } else {
      return of(null);
    }
  })
);

Then I just subscribe to the user$ where I need it. Either do that by manually subscribing or using async pipe. If you want to manually subscribe you need to remember to unsubscribe also on component destroy.

Here sample using async pipe:

user$ = this.authService.user$;

constructor(private authService: AuthService) { }

Template:

<div *ngIf="(user$ | async) as user">
   <h1>Hello: <strong>{{ user.username }}</strong></h1>
</div>

Also, DON'T use any. Please create models (interface is my preference) for your data. We are working with TypeScript after all ;)

Upvotes: 5

Related Questions