Search code examples
angularrxjsangularfireangular-ng-if

*ngIf async pipe issue


I'm working on the Authentication of my Angular 11 project with AngularFire. I don't know why but I can't make *ngIf with the async pipe react to the auth state when refreshing the page.

Here is my code:

AuthService:

[...]
export class AuthService {
  public isAuth$ = new BehaviorSubject<boolean>(false);

  constructor(private angularFireAuth: AngularFireAuth,
              public router: Router) {

    this.angularFireAuth.onAuthStateChanged((user: any) => {
      if (user) {
                                                           // On reflesh
                                                           // when signed in
        console.log('signed in');                          //display signed in
        console.log('isAuth$:', this.isAuth$.getValue());  //display false

        this.isAuth$.next(true);                           

        console.log('isAuth$:', this.isAuth$.getValue()); //display true

      } else {
        console.log('signed out');
        this.isAuth$.next(false); 
      }
    });
  }

// Some Auth functions

}

Component .ts

[...]
export class HeaderComponent implements OnInit {

  constructor(public authService: AuthService) {}

  public isAuth$ = new BehaviorSubject<boolean>(this.authService.isAuth$.getValue());

  ngOnInit(): void {
    this.isAuth$ = this.authService.isAuth$;
  }

}

Component html:

<div>
   <a *ngIf="!(isAuth$ | async)">Sign in</a> 
   <a *ngIf="(isAuth$ | async)">Sign out</a>
<div>

What is appening is that when i m signed in and refresh. Angular display the Signed Out state until i click on a field or a button...

On refresh from signed in state the console log display:

auth.service.ts:19 signed in
auth.service.ts:20 isAuth$: false
auth.service.ts:22 isAuth$: true

The value change on refresh so i was assuming the async pipe of *ngIf should react to those changes and display the good set of button right away. Hopping on your light to understand the issue.


Solution

  • Should be like:

    export class HeaderComponent implements OnInit {
    
      constructor(public authService: AuthService) {}
    
      public isAuth$ = this.authService.isAuth$
    
      ngOnInit(): void {
        //this.isAuth$ = this.authService.isAuth$; --> remove this
      }
    }
    
    

    When you use getValue() on the BehaviorSubject, it will only get the value for that change detection cycle. You don't need to (actually shouldn't) reassign isAuth$ on ngOnInit

    Also html

    <div>
       <a *ngIf="!(isAuth$ | async)">Sign in</a> 
       <a *ngIf="(isAuth$ | async)">Sign out</a> <!-- missing a $ here -->
    <div>
    

    You can also group the result like:

    <div *ngIf="isAuth$ | async as isAuth>
       <a *ngIf="!isAuth">Sign in</a> 
       <a *ngIf="isAuth">Sign out</a>
    <div>