Making the UI reactive to the user authentication status
All right, so unauthorized users cannot access the task editor form component. However, having an unresponsive link in our main toolbar is definitely not good, so we should leverage the Observable features of the AuthenticationService
to flip the UI whenever there is a change in the user login status.
Right now, the nav bar features the Login
link that leads the user login form page. What we want to do is to hide the Publish Task
link and make sure we only display it when the user is logged in, no matter where and how this login procedure was undertaken. On the other hand, we also want to offer the end user a Logout
link when logged in, so they can shut down his session in confidence. This logout link should be made available for logged in users only. Access to the protected component by hardcoding URLs is not a concern, since the @CanActivate
decorator will do its job to keep undesired users away.
Now that we have described the requirements, let’s put them into practice. Open the top root component file and update its implementation (it remained empty until now). We will need the AuthenticationService
and the Router
dependencies to do so, so make sure to import them at the top of the file:
app/app.component.ts
import { Component } from '@angular/core'; import { SHARED_PROVIDERS, AuthenticationService } from './shared/shared'; import { HTTP_PROVIDERS } from '@angular/http'; import { ROUTER_PROVIDERS, RouteConfig, ROUTER_DIRECTIVES, Router } from '@angular/router-deprecated'; // Rest of import statements remain the same …
With the tokens properly declared in the import statements, we can move on and provide an implementation for the AppComponent
class:
app/app.component.ts
... export default class AppComponent { userIsLoggedIn: boolean; constructor( private authenticationService: AuthenticationService, private router: Router) { authenticationService.userIsloggedIn.subscribe(isLoggedIn => { this.userIsLoggedIn = isLoggedIn; }); } logout($event): void { $event.preventDefault(); this.authenticationService.logout().then(success => { if (success) { this.router.navigateByUrl('/'); } }); } }
We have declared a userIsLoggedIn
Boolean field, which will change its value every time the observable userIsloggedIn
member of the injected AuthenticationService
type changes its value. We also injected the Router
type and created a new component method named logout()
that will wipe out the user session and redirect the user to the root page upon signing out from the application.
This gives us the chance to wrap up the application UI by updating the root component template to make the sensible links fully reactive to these changes:
app/app.component.html
<nav class="navbar navbar-default navbar-static-top"> <div class="container"> <div class="navbar-header"> <strong class="navbar-brand">My Pomodoro App</strong> </div> <ul class="nav navbar-nav navbar-right"> <li><a [routerLink]="['TasksComponent']">Tasks</a></li> <li><a [routerLink]="['TimerComponent']">Timer</a></li> <li *ngIf="userIsLoggedIn"> <a [routerLink]="['TaskEditorComponent']">Publish Task</a> </li> <li *ngIf="!userIsLoggedIn"><a [routerLink]="['LoginComponent']">Login</a> </li> <li *ngIf="userIsLoggedIn"> <a href="#" (click)="logout($event)">Logout</a> </li> </ul> </div> </nav> <router-outlet></router-outlet>
Give it a try! Reload the application, check the links available at the nav bar, head over to the login page, proceed to login with the credentials, and check the nav bar again… Magic!