我对angular还很陌生,目前正在使用它构建一个web应用程序.我的问题在于,当一个组件中的值在另一个组件中被更改后,两个组件中的值都是不相关的.为了实现这一点,我试图使用一个订阅不工作.

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

<app-navbar></app-navbar>
<router-outlet></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"属性似乎从未更新过.

What I've tried and expected

应该发生的是,一旦我用正确的邮箱和密码登录,我会收到一个令牌,并将令牌和用户ID存储为Cookie(这部分肯定有效),然后被重定向到主页.每次用户try 导航到需要身份验证的页面时,Auth.Guard都会调用auth.service的判断身份验证方法,以判断具有给定ID和令牌的用户是否存在.登录后,注销按钮应该出现在导航栏中,并一直保持到用户决定注销并删除存储用户ID和令牌的Cookie.

我try 手动触发更改检测,并使用控制台日志(log)判断身份验证是否成功.根据chatgpt的建议,如果你想了解更多关于组件状态变化的细节,我已经为chrome安装了angular devtools扩展.

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

推荐答案

在AuthService中,布尔值isAuthenticated没有连接到isAuthenticatedBS.您使用isAuthenticated的值初始化BehaviourSubject(即false,但更改为isAuthenticated不会触发该主题).Subject有它自己的内部值,你不能用这种方式将它"连接"到现有的变量.

相反,如果希望BehaviourSubject发出新值,则需要对其调用next(value).所以我建议从您的AuthService中删除isAuthenticated个布尔值,并在您的checkAuthentication方法中调用isAuthenticatedBS.next(await this.authenticate()).

如果需要当前值而不是可观测的值,只需查询isAuthenticatedBS.value即可

Typescript相关问答推荐

为什么在TypScript中写入typeof someArray[number]有效?

类型断言添加到类型而不是替换

即使子网是公共的,AWS CDK EventBridge ECS任务也无法分配公共IP地址

在Angular中注入多个BrowserModules,但在我的代码中只有一个

类型{}上不存在属性&STORE&A;-MobX&A;REACT&A;TYPE脚本

如何在深度嵌套的Reaction路由对象中隐藏父级?

按函数名的类型安全类型脚本方法包装帮助器

声明文件中的类型继承

在Cypress中,是否可以在不标识错误的情况下对元素调用.Click()方法?

ANGLE NumberValueAccessor表单控件值更改订阅两次

TS2739将接口类型变量赋值给具体变量

在单独的组件中定义React Router路由

如何将对象的字符串文字属性用作同一对象中的键类型

导航链接不触发自定义挂钩

如何使用IsEqual创建断言类型相等的实用程序

在对象数组中设置值

Typescript泛型-键入对象时保持推理

如何在由函数参数推断的记录类型中具有多个对象字段类型

如何为字符串模板文字创建类型保护

为什么我无法在 TypeScript 中重新分配函数?