如何刷新组件

时间:2016-03-28 22:55:36

标签: angular

我有一个简单的基于Angular2的Web应用程序,带有身份验证。我遇到了一个问题,根据用户是否登录导航栏看起来不同,并且当用户没有登录时,某些组件也不会显示。

问题是,例如,当用户点击logout时,导航栏会更改,但其他组件在页面刷新之前不会消失。如何在按下LogOut按钮时触发组件刷新?

//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) {}

}

导航组件呈现在路由器生成的任何内容之上。

如何触发要重置的组件?

2 个答案:

答案 0 :(得分:6)

使用事件或可观察对象。

有必要(我认为)因为Angular 2不再有two-way-binding

在我的LoginService中,我使用了ReplaySubject(它类似于Observable对象,但是&#39;存储&#39;最后一个值,并且&#39;在它订阅的时候重放它)来自RxJS,然后我从我想要更新的组件订阅了ReplaySubject。

登录服务示例

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);
  }
}

示例组件

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();
  }
}

这样您就可以在模板中使用loggedIn变量,也可以从不同的组件订阅ReplaySubject

答案 1 :(得分:2)

您有几个选择。最简单的方法是触发router事件,该事件将导致角度重新评估您的绑定。这可能不是你想要的,因为你必须将路由器指向一个完全不同的“页面”。通常在这种情况下,我使用静态登录页面,该页面始终重定向回APP,而不是将登录逻辑构建到APP本身。从长远来看,这似乎在所有时间都有效。

但是,通过查看正在执行的操作,我们可以在触发该注销事件时更新您的组件。

  logout() {
    localStorage.removeItem('id_token');
    this.loggedIn = false;
  }

正如您所看到的,这是将该Model上的loggedIn属性设置为false。这个属性由APP(Angular)“观察”。更新后,由于导航栏模板中的以下指令

,它会更新导航栏
*ngIf="!_userService.isLoggedIn()

该指令对Angular说; “如果此属性为FALSE,则呈现此内容”。由于它包含在你的@Component模板中,它在渲染时由Angular渲染和评估,但是当该属性发生变化时,它将继续从Angular接收更新。

这是您需要为每个需要此逻辑的组件做的事情....

“但这很多工作和跟踪”

你在那句话中说得对。我将定义这些组件的公共集合,然后将组件作为更高级别的集合包含在内,这样您就可以轻松地在顶级组件中的单个点进行更新。然后,顶级组件将设置一个'DIV',其中这些组件在同一ngIf指令下进行模板化。