为什么在标题模板中可观察到的isLoggedIn在用户登录和注销时不会更新?

时间:2018-10-15 11:16:50

标签: angular observable

我的AppModule导入了CoreModule

@NgModule({
  providers: [
    LoginService
  ],
})
export class CoreModule {

其本身在全局范围内提供LoginService

@Injectable()
export class LoginService {

    constructor(
        private router: Router,
        private authService: AuthService
    ) { }

    login(username: string, password: string) {
        this.authService.login(username, password).subscribe(
            response => {
                this.router.navigate(['users']); // TODO Check that all router.navigate don't use hard coded strings
            },
            error => {
                console.log(error);
            }
        );
    }

    logout() {
        this.authService.logout().subscribe(
            response => {
                this.router.navigate(['login']);
            },
            error => {
                console.log(error);
            }
        );
    }

}

还有一个AuthService用于服务器端登录或注销,并将登录状态保留在浏览器本地存储中。

public isAuthenticated(): Observable<boolean> {
  if (this.tokenService.accessTokenExpired()) {
    if (this.tokenService.refreshTokenExpired()) {
      return of(false);
    } else {
      return this.refreshAccessToken()
      .pipe(
        map(response => {
          if (response) {
            return true;
          }
        }),
        catchError((error, caught) => {
          return of(false);
        })
      );
    }
  }
  return of(true);
}

根据登录状态,应该显示或不显示标题模板。

<mat-toolbar color="primary" *ngIf="isLoggedIn$ | async as isLoggedIn">

此标头组件保持登录状态。

  isLoggedIn$: Observable<boolean>;

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

  logout(): void {
    this.loginService.logout();
  }

导航正常,但是页眉模板需要刷新页面才能与登录状态保持同步。

当登录状态更改时,感觉标题模板中的isLoggedIn并没有得到更新。

该代码已被删除。

编辑:我通过跳过ngIf方式并使用多种布局来解决此问题。

const routes: Routes = [
  {
    path: '',
    component: LoginLayoutComponent,
    children: [
      {
        path: '',
        redirectTo: 'login',
        pathMatch: 'full'
      },
      {
        path: 'login',
        component: LoginComponent
      }
    ]
  },
  {
    path: '',
    component: HomeLayoutComponent,
    canActivateChild: [AuthGuardService],
    children: [
      {
        path: 'users',
        component: UsersComponent,
      },
      {
        path: 'detail/:id',
        component: UserComponent,
      },
      {
        path: 'dashboard',
        component: DashboardComponent,
        data: {
          expectedRole: 'admin'
        }
      },
      {
        path: 'home',
        loadChildren: './views/home/home.module#HomeModule',
        data: {
          preload: true,
          delay: false
        }
      },
      {
        path: 'error',
        component: ErrorComponent
      },
    ]
  },
];

login布局:

@Component({
  selector: 'app-login-layout',
  template: `<router-outlet></router-outlet>`
})
export class LoginLayoutComponent { }

还有一个home布局:

@Component({
  selector: 'app-home-layout',
  templateUrl: './home.layout.component.html'
})
export class HomeLayoutComponent { }

及其模板:

<mat-sidenav-container class="example-container">
  <mat-sidenav #drawer mode="side" opened role="navigation">
    <mat-nav-list>
      <a mat-list-item routerLink='/first'>First Component</a>
      <a mat-list-item routerLink='/second'>Second Component</a>
    </mat-nav-list>
  </mat-sidenav>
  <mat-sidenav-content>
    <app-header></app-header>
  </mat-sidenav-content>
  <router-outlet></router-outlet>
</mat-sidenav-container>

1 个答案:

答案 0 :(得分:1)

我看到isAuthenticated有问题。它总是每次都返回新的Observable。您应该有一个Observable,通过它可以通知所有Subscription

AuthService

    private authSubject = new BehaviorSubject<boolean>(false);
    private isLoggedIn$ = this.authSubject.asObservable();

    updateLoggedInState(status: boolean){
        this.authSubject.next(status);
    }

    public isAuthenticated(): Observable<boolean> {
         return this.isLoggedIn$;
    }

LoginService

@Injectable()
export class LoginService {

    constructor(
        private router: Router,
        private authService: AuthService
    ) { }

    login(username: string, password: string) {
        this.authService.login(username, password).subscribe(
            response => {
                this.router.navigate(['users']); // TODO Check that all router.navigate don't use hard coded strings
             this.authService.updateLoggedInState(true);
            },
            error => {
                console.log(error);
                this.authService.updateLoggedInState(false);
            }
        );
    }

    logout() {
        this.authService.logout().subscribe(
            response => {
                this.router.navigate(['login']);
                this.authService.updateLoggedInState(false);
            },
            error => {
                console.log(error);
            }
        );
    }

}
  

注意:我没有介绍令牌,但是您可以按照自己的方式来处理它。