Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to refresh a component

Tags:

angular

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?

like image 766
George Edwards Avatar asked Mar 28 '16 22:03

George Edwards


1 Answers

Use Events or Observables.

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.

like image 123
Abimael Martinez Avatar answered Nov 15 '22 05:11

Abimael Martinez