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

Viewed 727

I am creating an angular application. I have AuthenticationService class. Here after login I am putting the account object into a BehaviorSubject observable. So that I can subscribe the observable and get the necessary information of Account object. Here is my code:

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;
            }));
    }

Now after login I want to show the username in my header section. So in header component I have subscribed the observer and trying to show the username by string interpolation. Here is my code of Header Component:

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;
    }

View

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

Now my problem is after successfully login the username is not shown in the header section. enter image description here

But if I reload the page then the username is showing in the header section. enter image description here

Why is this happening I don't know. Can anyone help me understand this problem and get the solution. I don't want to put the information in local storage or session either.

I also tried this way too. Instead subscribing the observable in constructor I put the code in ngInit like below code. But it's not working too.

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

It may just be a timing issue, possibly ngOnInit is being called before the account is set, or change detection isn't triggering. Try the following update to the subscription in the constructor

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()
 })
}

Like @Drenai mentioned, it looks like a timing issue. When you use a behaviour subject, you set an initial value which is at the beginning null because nothing was set in the storage, thats probably why you dont see anything at the beginning (you could debug and see if storage or that variable is really null just to confirm).
Now you could do the following which might work: In your header component, define an observable:

accountInfo$: Observable;

After that, initialize this obersavble in ngOnInit.

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

Then in your html file, use the async pipe, so that angular handles the subscription:
HTML:

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

So you can basically delete your account variable and the code you have written in the constructor and ngOnInit body. Just initialize your variable accountInfo$ with the observable you get from your dependency Injection/ Service in ngOnInit.

Related