【问题标题】:How to use ngIf without reloading page如何在不重新加载页面的情况下使用 ngIf
【发布时间】:2019-12-15 12:03:58
【问题描述】:

我有导航栏组件,我的目标是根据用户登录显示两个不同的导航栏,即如果用户登录,他们将看到一个导航栏;如果没有,另一个。我为此目的使用 ngIf 并且一切正常,除了登录用户在手动刷新页面之前仍然可以看到未登录用户的导航栏。

import {Component, OnInit} from '@angular/core';
import {User} from '@models/user.model';
import {AuthenticationService} from '@services/auth.service';
import {Observable} from 'rxjs';

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
  user: User;
  authObs: Observable<User>;

  constructor(private auth_service: AuthenticationService) { }

  ngOnInit() {
    this.authObs =  this.auth_service.currentUser;
  }
<nav *ngIf="authObs | async as auth; else elseBlock" class="navbar navbar-expand-lg navbar-dark bg-dark">
  <div class="container">

    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="navbarSupportedContent">

      <ul class="navbar-nav">
        <li class="nav-item sub">
          <a class="nav-link unselectable" (click)="gt_myprofile()"><span class="icon icon-profile"></span> my
            profile</a>
        </li>
        <li class="nav-item sub">
          <a class="nav-link unselectable" (click)="gt_messages()"><span class="icon icon-message"></span> messages
            <span
              class="icon-notif"></span> </a>
        </li>
        <li class="nav-item sub">
          <a class="nav-link unselectable" (click)="gt_contacts()"><span class="icon icon-contacts"></span>
            contacts<span
              class="icon-notif"></span> </a>
        </li>
      </ul>
    </div>
  </div>
</nav>

<ng-template #elseBlock>
  <nav  class="navbar navbar-expand-lg navbar-dark bg-dark">
    <div class="container">
      <a class="navbar-brand" href="#"><img src="assets/static" alt=""></a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
              aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <!-- start navbar-nav -->
        <ul class="navbar-nav">
          <li class="nav-item">
            <a class="nav-link" href="#">about<span class="sr-only">(current)</span></a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">cooperation</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">terms</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">contacts</a>
          </li>
        </ul>
      </div>
    </div>
</nav>
</ng-template>
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { User } from '@models/user.model';

@Injectable({ providedIn: 'root' })

export class AuthenticationService {
  private currentUserSubject: BehaviorSubject<User>;
  public currentUser: Observable<User>;

  constructor(private http: HttpClient) {
    this.currentUserSubject = new BehaviorSubject<User>(JSON.parse(localStorage.getItem('currentUser')));
    this.currentUser = this.currentUserSubject.asObservable();
  }

  public get currentUserValue(): User {
    return this.currentUserSubject.value;
  }
}

login(email: string, password: string) {
  return this.http.post<any>(`${environment.apiUrl}/api/auth/`, { email, password })
    .pipe(map(user => {
      // store user details and jwt token in local storage to keep user logged in between page refreshes
      localStorage.setItem('currentUser', JSON.stringify(user));
      this.currentUserSubject.next(user);
      this.currentUser = this.currentUserSubject.asObservable();
      console.log("TCL: AuthenticationService -> login -> user", user)
      return user;
    }));
}

【问题讨论】:

  • 你什么时候更新currentUserSubject
  • 抱歉,我应该如何以及何时更新它?用户登录后?
  • 好吧,如果你想让消耗 observable 的东西获得新值,那将是这样做的好时机。
  • 我添加了一个答案,我在其中展示了如何添加一种方法来更新已登录用户的值。
  • 尝试清除本地存储。您是否在注销时从本地存储中调用 removeItem?我没有在您的服务中看到注销功能。如果本地存储为空,您的代码应该可以工作

标签: angular


【解决方案1】:

我认为问题在于 authService 没有发出新值,否则 *ngIf 和异步管道使用看起来不错。

如何调用/使用 authService 来更新登录信息?

如果您更新 localStorage 信息以反映用户是否已登录,您应该为主题发出新值,例如:

updateUserAuth(newValue) {
    this.currentUserSubject.next(newValue);
    this.currentUser = this.currentUserSubject.asObservable();
}

您可以在用户登录后或想要更新 currentUser 状态时调用此方法。这取决于您的代码逻辑,但发出新值很重要,否则您的主题将永远不会通知其订阅者可以使用新值。


您是否尝试过调试 authObs 变量并在模板中打印出它的值?

   <.. *ngIf="authObs | async as auth; else elseBlock">
     Auth: {{auth}} 

我认为您也可以跳过构造函数中的 currentUser 初始化(或者您是否始终将用户信息存储在本地,直到显式注销?):

constructor(private http: HttpClient) {
    this.currentUserSubject = new BehaviorSubject<User>(JSON.parse(...));

   // currentUser will be falsy for not logged in users. 
   // this.currentUser = this.currentUserSubject.asObservable();
  }

您最终能否使用您的代码创建一个 stackBlitz 示例?

【讨论】:

  • 我忘记将登录功能从 aurhService 添加到我的问题中,现在添加。用户登录后我已经发出了新值,但没有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-22
  • 2012-02-23
  • 2013-08-20
  • 2011-10-22
  • 2021-07-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多