23

So I have these 2 buttons:

<a class="router-link nav-item" routerLink="/login" *ngIf="!isLoggedIn$ | async">
  Login
</a>
<a class="router-link nav-item" (click)="onLogout()" *ngIf="isLoggedIn$ | async">
  Logout
</a>

And the logout button works perfectly, as soon as the user is logged in the button appears. But the login button never appears.

This is the code behind the isLoggedIn$:

isLoggedIn$: Observable<boolean>;

ngOnInit() {
  this.isLoggedIn$ = this.authService.isLoggedIn;
}

AuthService:

private loggedIn = new BehaviorSubject<boolean>(false);

get isLoggedIn() {
  return this.loggedIn.asObservable();
}

Hope this is enough information and the problem is clear, thanks in advance!

RiesvGeffen
  • 1,369
  • 1
  • 8
  • 25

2 Answers2

49

Put the async pipe in parenthesis.

<a class="router-link nav-item" routerLink="/login" *ngIf="!(isLoggedIn$ | async)">
  Login
</a>
<a class="router-link nav-item" (click)="onLogout()" *ngIf="isLoggedIn$ | async">
  Logout
</a>
Tomasz Kula
  • 13,215
  • 1
  • 51
  • 71
  • Works perfect! Normally it would work right? But because I use async I have to use the parenthesis. – RiesvGeffen Apr 03 '18 at 13:53
  • 2
    Yes, but here you want the pipe to be applied first and then the negation :) – Tomasz Kula Apr 03 '18 at 13:53
  • @SjaakvBrabant check out my edit with another possible refactor :) – Tomasz Kula Apr 03 '18 at 14:13
  • Yes, I was just looking at it. But what's the reason for the and not just a
    ? EDIT: It actually doesn't work, the login button never shows up.
    – RiesvGeffen Apr 03 '18 at 14:14
  • 1
    If you use the `` it will not insert any DOM nodes. It will keep your markup as is. It might not make a difference here, but in some cases it will. For example you might have some css styles applied to the parent of your link, and another div there would mess it up. Basically the `` will disappear at runtime, but you can still target it with *ngIf, *ngFor and so on :) – Tomasz Kula Apr 03 '18 at 14:17
  • 1
    @TomaszKula your solution works perfectly except page is reloaded. When I hard reload the page it will show Login button initially and when the page will be focused using keyboard or mouse then it will be updated to Logout. I can understand that the initial value of the observer is false so, the Login button will be displayed first. But, Don't you think it should be updated to Logout as soon as the value of the observer gets updated? Do you have any idea why that happens? – Darpan Jun 11 '19 at 10:04
  • I use the exact same code, but i couldn't make this work (Angular 6). My ng-container doesn't draw it's content, I suspect because isLoggedIn translates to false. So the anchors don't have a chance to check their *ngIfs. I ended up using the ;else templateName method. But I rather use the ng-container. Am I doing something wrong? It also happened on another occasion where the observable was a object or null => same result. – Robin Jun 25 '19 at 07:42
  • The second example is wrong, once `isLoggedIn$` emits `false`, entire `` is removed. – isevcik Dec 03 '19 at 08:50
10

You can also refactor to use the else part of ngIf directive:

<a class="router-link nav-item" (click)="onLogout()" *ngIf="isLoggedIn$ | async; else loginBlock">
    Logout
</a>
<ng-template #loginBlock>
    <a class="router-link nav-item" routerLink="/login">
        Login
    </a>
</ng-template>

You can see more examples in the docs.

Adrian Fâciu
  • 11,776
  • 3
  • 50
  • 66
  • 1
    I don't know why, but before I didn't understand that. Because I looked at the docs but didn't understand it. But now you've made it in my context I understand it and I'm gonna keep this solution in mind. Thank you for your help! – RiesvGeffen Apr 03 '18 at 14:12