Giannis Savvidis
Giannis Savvidis

Reputation: 772

Angularfire conditional logic in template with authState observable delay in template rendering

Hi I am building an angular application with @angular/fire. In the auth service I have a user observable which gets the value of the current user, if the user is authenticated, and the value of null if the user is not authenticated.

export class AuthService {
 user$: Observable<User>;

  constructor(private afAuth: AngularFireAuth, private afs: 
 AngularFirestore) {
    this.user$ = this.afAuth.authState.pipe(
      switchMap(user => {
        if (user) {
          return this.afs.doc<User>(`users/${user.uid}`).valueChanges();
        } else {
          return of(null);
        }
      })
    )
  }

It's in the service's constructor so all components that inject the service can see the user$ variable.Now lets say I have a navigation that shows different buttons based on if the user is authenticated or not.

<ul>

  <!-- user IS NOT logged in -->
  <li *ngIf="!(authService.user$ | async)">
    This is visible if user is NOT logged in
  </li>

  <!-- user IS logged in -->
  <li *ngIf="authService.user$ | async" fxHide.xs>
    This is visible if user IS logged in
  </li>
</ul>

The user$ observable is empty at the start and takes some time to take value which means even if the user is logged, in the template the "This is visible if user is NOT logged in" will be rendered for a couple of seconds before the observable takes the value of the current user and then switch to the other li tag. Is there any better way to check the authenticated user to prevent this? Note I cannot use route guard because i dont want to block a whole page but only some conditional logic between buttons and some other elements. This is a duplicate question to this one: Angular 6 AngularFireAuth check if user is logged in before page rendered where i did not find an answer. Thanks in advance

Upvotes: 1

Views: 491

Answers (1)

Debojyoti
Debojyoti

Reputation: 4841

In the auth service add a subject to which the components can subscribe and wait for some response

import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
@Injectable()
export class AuthService {

  userAccessSubject = new Subject();

  user$: Observable<User>;

  constructor(private afAuth: AngularFireAuth, private afs:
    AngularFirestore) {
    this.afAuth.authState.pipe(
      switchMap(user => {
        if (user) {
          this.userAccessSubject.next(this.afs.doc<User>(`users/${user.uid}`).valueChanges());
        } else {
          this.userAccessSubject.next(null);
        }
      })
    )
  }

  getUserAccess() {
    return this.userAccessSubject.asObservable();
  }
}

And in the component, get userAccess from the subscription block

constructor() {
  // Here add code to enable loader
  this.authService.getUserAccess()
    .subscribe(userAccessResponse => {
      this.userAccess = userAccessResponse;
      // Hide loader
    })
}

Upvotes: 1

Related Questions