Angular 订阅要么不更新值,要么不识别值更改

问题描述 投票:0回答:1

我对 Angular 相当陌生,目前正在使用它构建一个 Web 应用程序。我的问题在于更新一个组件中的值,然后在另一个组件中更改该值,而这两个组件彼此无关。为了实现这一目标,我尝试使用不起作用的订阅。

我的根组件的 html (app.component.html) 看起来像这样:

<app-navbar></app-navbar>
<router-outlet></router-outlet>

在路由器出口内,除非服务器设置并验证了用户 ID 和令牌,否则用户会自动重定向到登录页面(每个页面都是一个组件)。设置用户 ID 和令牌并将其存储为 Cookie 后,我希望在导航栏中显示一个注销按钮。

navbar.component.html:

<nav class="bg-dark border-bottom border-body" data-bs-theme="dark">
    <a routerLink="">Home</a>
    <button *ngIf="isAuthenticated" routerLink="login" class="logout">Log out</button>
</nav>

navbar.component.ts:

import { Component, OnDestroy, OnInit } from '@angular/core';
import { AuthService } from '../auth.service';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.scss']
})
export class NavbarComponent implements OnInit, OnDestroy {

  isAuthenticated: boolean = false
  authSubscription: Subscription

  constructor(private authService: AuthService) {
  }

  ngOnInit(): void {
    this.authSubscription = this.authService.isAuthenticated$.subscribe((isAuthenticated) =>
      {
        this.isAuthenticated = isAuthenticated
      }
    )
  }

  ngOnDestroy(): void {
    this.authSubscription.unsubscribe()
  }
}

我正在使用 auth.service.ts 来验证用户身份:

import { Injectable } from '@angular/core';
import { CookieService } from 'ngx-cookie-service';
import { AUTHENTICATE } from './graphql/graphql.queries';
import { Apollo } from 'apollo-angular';
import { BehaviorSubject, Observable, firstValueFrom } from 'rxjs';

@Injectable({
  providedIn: "root",
})
export class AuthService {

  isAuthenticated = false;
  error: any

  private isAuthenticatedBS = new BehaviorSubject<boolean>(this.isAuthenticated)
  public isAuthenticated$ : Observable<boolean> = this.isAuthenticatedBS.asObservable()

  constructor(private cookieService: CookieService, private apollo: Apollo) {
    this.checkAuthentication()
  }

  async checkAuthentication(): Promise<boolean> {
    this.isAuthenticated = await this.authenticate()
    return this.isAuthenticated;
  }

  async authenticate()
  {
    if(this.cookieService.get("userId") && this.cookieService.get("token"))
    {
      const response = await firstValueFrom(this.apollo.query({
        query: AUTHENTICATE,
        variables: {
          userId: +this.cookieService.get("userId"),
        },
        fetchPolicy: 'network-only',
      }));

      if(<number>(<any>response.data).authenticate != null)
      {
        if(<number>(<any>response.data).authenticate.id > 0)
        {
          return true
        }
      }
      return false
    }
    else
    {
      return false
    }
  }
}

问题是 navbar.component.ts 中的“isAuthenticated”属性似乎从未更新。

我的尝试和期望

应该发生的事情是,一旦我使用正确的电子邮件和密码登录,我就会收到一个令牌并将令牌和用户 ID 存储为 cookie(这部分肯定有效),然后重定向到主页。每次用户尝试导航到需要身份验证的页面时,auth.guard 都会调用 auth.service 的 checkAuthentication 方法来检查具有给定 id 和令牌的用户是否存在。登录后,注销按钮应出现在导航栏中并一直保留,直到用户决定注销并删除存储用户 ID 和令牌的 Cookie。

我尝试手动触发更改检测并使用控制台日志检查身份验证是否成功。根据 chatgpt 的建议,如果您想了解有关组件状态更改的更多详细信息,我已经安装了 chrome 的 Angular devtools 扩展。

以下是 Angular devtools 向我展示的内容的一个小概述: app-navbar's properties as shown in angular devtools

angular typescript observable subscription
1个回答
0
投票

在您的 AuthService 中,布尔值

isAuthenticated
未连接到
isAuthenticatedBS
。您可以使用
isAuthenticated
所具有的值(即
false
)初始化 BehaviourSubject,但对
isAuthenticated
的更改不会触发主题。主题有其自己的内部值,您无需将其“连接”到现有变量就这样。

相反,如果您希望 BehaviourSubject 发出新值,则需要对其调用

next(value)
。因此,我建议从 AuthService 中删除
isAuthenticated
布尔值,并在
isAuthenticatedBS.next(await this.authenticate())
方法中调用
checkAuthentication

如果您需要当前值而不是可观察值,您可以只查询

isAuthenticatedBS.value

© www.soinside.com 2019 - 2024. All rights reserved.