从 BehaviorSubject 中获取用户名并在 header 部分显示用户名需要在 Angular 11 中登录后刷新

Get the username from BehaviorSubject and show the username in the header section needs refresh after login in Angular 11

我正在创建一个 angular 应用程序。我有 AuthenticationService class。登录后,我将帐户 object 放入 BehaviorSubject 可观察对象中。这样我就可以订阅可观察对象并获取帐户 object 的必要信息。这是我的代码:

private accountSubject: BehaviorSubject<AccountInfo>;
    public account: Observable<AccountInfo>;

    constructor(
        private router: Router,
        private service: ApplicationService) {

        // behaviour subject
        this.accountSubject = new BehaviorSubject<AccountInfo>(JSON.parse(localStorage.getItem('account')));
        this.account = this.accountSubject.asObservable();
    }

    public get accountValue(): AccountInfo {
        return this.accountSubject.value;
    }

    login(username: string, password: string) {
        return this.service.post<any>(`${this.apiPATH}login`, { username, password })
            .pipe(map(user => {             
                localStorage.setItem('account', JSON.stringify(user.account));
                this.accountSubject.next(user);
                return user;
            }));
    }

登录后我想在 header 部分显示用户名。因此,在 header 组件中,我订阅了观察者并尝试通过字符串插值来显示用户名。这是我的 Header 组件代码:

account: AccountInfo;
    username: string;
    userPhotoUrl: string;

    constructor(private authService: AuthenticationService) {
        this.authService.account.subscribe(x => this.account = x);      
    }

    logout() {
        this.authService.logout();
    }

    ngOnInit() {        
        this.username = this.account.name;
    }

查看

<h5 class="mb-0 text-white nav-user-name">{{username}}</h5>

现在我的问题是成功登录后用户名没有显示在 header 部分。

但是,如果我重新加载页面,则用户名会显示在 header 部分中。

我不知道为什么会这样。任何人都可以帮助我理解这个问题并获得解决方案。 我不想将信息放在本地存储中,也不想 session。

我也试过这种方法。而不是在构造函数中订阅可观察对象,我将代码放在 ngInit 中,如下面的代码所示。但这也行不通。

ngOnInit() {
    this.authService.account.subscribe(x => {
       this.account = x;
       this.username = x.name;
      }); 
}

这可能只是一个时间问题,可能 ngOnInit 在设置 account 之前被调用,或者未触发更改检测。尝试在构造函数中对订阅进行以下更新

constructor(private cd: ChangeDetectorRef) {
 this.authService.account.subscribe(x => {
   this.account = x
   this.userName = this.account.name;
   // log the result to be sure it's actually being received
   console.log('account: ', x)
   // in case it's not detecting changes
   this.cd.detectChanges()
 })
}

就像@Drenai 提到的,这看起来像是一个时间问题。当您使用行为主题时,您设置了一个初始值,该值在开头为空,因为存储中没有设置任何内容,这可能就是为什么您在开头看不到任何内容的原因(您可以调试并查看存储或该变量是否真的为空只是为了确认)。
现在您可以执行以下操作:在您的 header 组件中,定义一个可观察对象:

accountInfo$: Observable;

之后,在ngOnInit中初始化这个obersavble。

ngOnInit() {        
        this.accountInfo$= this.authService.account;
    }

然后在您的 html 文件中,使用异步管道,以便 angular 处理订阅:
HTML:

<div *ngIf="accountInfo$ | async as accountInfo">
<h5 class="mb-0 text-white nav-user-name">{{accountInfo.name}}</h5>
</div>

所以你基本上可以删除你的帐户变量和你在构造函数和 ngOnInit 中编写的代码 body。只需使用从 ngOnInit 中的依赖项注入/服务获得的可观察值来初始化变量 accountInfo$。