I have a simple Angular2 based web app, with authentication. I am running into an issue, where the navigation bar looks different based on whether the user is logged in or not, and also some components won't display when the user isn't logged in.
The issue is, for example, when a user clicks logout
, the navbar changes, but the other component doesn't disappear until the page is refreshed. How can I trigger a component refresh when the LogOut button is pressed?
//user.service.ts
logout() {
localStorage.removeItem('id_token');
this.loggedIn = false;
}
//nav.component.ts
import { Component, Inject } from 'angular2/core';
import { RouteConfig, ROUTER_DIRECTIVES } from 'angular2/router';
import { UserService } from '../user/services/user.service';
@Component({
selector: 'nav-bar',
template: `
<div class="nav">
<a [routerLink]="['LoginComponent']" *ngIf="!_userService.isLoggedIn()">Login</a>
<a [routerLink]="['SignupComponent']" *ngIf="!_userService.isLoggedIn()">Sign Up</a>
<a [routerLink]="['TodoComponent']" *ngIf="_userService.isLoggedIn()">ToDo</a>
<button (click)="_userService.logout($event)" *ngIf="_userService.isLoggedIn()">Log Out</button>
</div>
`,
styleUrls: ['client/dev/todo/styles/todo.css'],
directives: [ROUTER_DIRECTIVES],
providers: [ UserService ]
})
export class NavComponent {
constructor(@Inject(UserService) private _userService: UserService) {}
}
The nav component renders above whatever the router generates.
How can I trigger components to reset?
It is necessary (I think) because Angular 2 no longer has two-way-binding
.
In my LoginService I use ReplaySubject (it is similar to the Observable object, but 'stores' the last value and 'replays' it whenever it's subscribed to) from RxJS, then I subscribe to that ReplaySubject from the components that I want to update.
Example Login Service
import {ReplaySubject, Observable} from 'rxjs/Rx';
import {Injectable} from 'angular2/core';
@Injectable()
export class LoginService {
private logged = new ReplaySubject<boolean>(1); // Resend 1 old value to new subscribers
// isLoggedIn checks with server if user is already logged in.
// Returns true if logged in, and caches the result and user data.
isLoggedIn(): ReplaySubject<boolean> {
return this.logged;
}
// logIn attempts to log in a user, returns attempt result.
// Caches login status.
logIn(user: string, password: string): Observable<boolean> {
return Observable.timer(100).map(() => { // emulate a 100ms delay on login
this.logged.next(true);
return true;
})
}
logOut() {
// need api call to logout here
this.user = null;
this.logged.next(false);
}
}
Example Component
import {Component} from 'angular2/core';
import {LoginService} from "../user/login.service";
@Component({
selector: 'an-menu',
templateUrl: 'app/user/menu.html',
})
export class MenuComponent {
loggedIn: boolean;
constructor(private _loginService: LoginService) {
this._loginService.isLoggedIn()
.subscribe(r => {
this.loggedIn = r;
});
}
onLogout() {
this._loginService.logOut();
}
}
This way you can use the loggedIn
variable in your template, you can also subscribe to the the ReplaySubject
from different components.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With