The header component does not update properly post-login

I am currently developing a web-app using Angular 8.

Within my app, I have a header and login page. My goal is to update the header after a user logs in to display information about the current logged-in user. I attempted to achieve this using a BehaviorSubject but unfortunately, it seems to be ineffective.

The issue lies within my authentication service where the BehaviorSubject is implemented

@Injectable()
export class AuthService {

  private readonly GRANT_TYPE = 'password';

  logged: BehaviorSubject<UserDataModel> = new BehaviorSubject<UserDataModel>(null);

  //private auth$: Observable<Auth>;

  constructor(private httpClient: HttpClient, private router: Router) { }

  login(credentials: CredentialsModel) {
    this.httpClient.post('http://localhost:8080/api/oauth/token',
      this.prepareParams(credentials),
      { headers: this.prepareHeaders() })
      .subscribe(token => {
        let userData = new UserDataModel();
        userData.token = token['access_token'];
        this.getUserInfo(userData);
      });



    //this.saveAuth();
  }

  autoLogin() {
    const userData = JSON.parse(localStorage.getItem('user'));
    if (!userData) {
      return;
    }


    if (userData.token) {
      this.logged.next(userData);
    }
  }

  private prepareHeaders(): HttpHeaders {
    let headers = new HttpHeaders();
    headers = headers.append('Authorization', 'Basic ' + btoa('frontendClientId:frontendClientSecret'));
    headers = headers.append('Content-Type', 'application/x-www-form-urlencoded');
    return headers;
  }

  private prepareParams(credentials: CredentialsModel) {
    let params = new HttpParams();
    params = params.append('username', credentials.username);
    params = params.append('password', credentials.password);
    params = params.append('grant_type', this.GRANT_TYPE);
    return params;
  }

  private getUserInfo(userData: UserDataModel) {
    this.httpClient.get('http://localhost:8080/api/user/user/current',
      {headers: new HttpHeaders().append('Authorization', 'Bearer ' + userData.token)})
      .subscribe(data => {
        userData.email = data['name'];
        userData.role = data['authorities'][0]['authority'];
        this.saveUser(userData);
        this.logged.next(userData);
        this.router.navigate(['../']);
      })
  }
private saveUser(userData: UserDataModel) {
        localStorage.setItem('user', JSON.stringify(userData))
  }
}

Here is the code for my header component where I subscribe to the BehaviorSubject from the auth service

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit, OnDestroy, DoCheck {

  loggedIn: boolean = false;
  username: string ='';
  private subscriptions: Subscription[] = [];

  constructor(private authService: AuthService) { }

  ngOnInit() {
    this.subscriptions.push(this.authService.logged.subscribe(this.onLogged));
  }

  ngDoCheck(): void {
    this.authService.autoLogin();
  }

  onLogout() {
    this.loggedIn = false;
  }

  onLogged(userData: UserDataModel) {
    if(userData) {
      this.loggedIn = true;
      this.username = userData.email;
    }
  }

  ngOnDestroy(): void {
    this.subscriptions.forEach(sub => sub.unsubscribe());
  }

}

Below is some HTML code that fails to update after a user logs in:

<div class="header-actions" *ngIf="!loggedIn">
    <a routerLink="/login" class="nav-link nav-icon-text">
      <clr-icon shape="user"></clr-icon>
      <span class="nav-text">Log In</span>
    </a>
    <a href="" class="nav-link nav-icon-text">
      <clr-icon shape="plus"></clr-icon>
      <span class="nav-text">Sign Up</span>
    </a>
  </div>

  <div class="header-actions" *ngIf="loggedIn">
    <clr-dropdown>
      <button class="nav-text" clrDropdownTrigger>
        {{username}}
        <clr-icon shape="caret down"></clr-icon>
      </button>
      <clr-dropdown-menu *clrIfOpen clrPosition="bottom-right">
        <a routerLink="#" clrDropdownItem>Profile</a>
        <a routerLink="#" clrDropdownItem (click)="onLogout()">Logout</a>
      </clr-dropdown-menu>
    </clr-dropdown>
  </div>

Within the login component, the 'login' method in the auth.service is correctly invoked, navigating to the dashboard, however, the header remains unchanged.

Can you provide insights into what might be causing this issue?

Answer №1

Upon examination, I have identified an issue with the code snippet below where 'this.onLogged' is subscribed:

  ngOnInit() {
    this.subscriptions.push(this.authService.logged.subscribe(this.onLogged));
  }

The problem arises because when the observer method - this.onLogged - is registered as an observable, it loses its method scope (which is the this context). Consequently, the Observable fails to invoke the this.isLogged method. To resolve this issue, update the code as follows:

  ngOnInit() {
    this.subscriptions.push(this.authService.logged.subscribe((value) => {
            this.onLogged(value);
    }));
  }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating a unique Elastic IP address for a single EC2 instance with the AWS CDK

I'm having an issue with my AWS CDK Stack where multiple Elastic IPs are being created for each public subnet in my VPC instead of just one. I only want one Elastic IP to be associated with a single EC2 instance. My simplified code snippet is as foll ...

Intro.js is not compatible with React and Remix.run

I am currently working on implementing onboarding modals for header links using intro.js within a React environment. Below is the code snippet: import { useState, type FC } from 'react' import type { Links } from '../types' import &apo ...

To handle a 400 error in the server side of a NextJS application, we can detect when it

I'm facing a situation where I have set up a server-side route /auth/refresh to handle token refreshing. The process involves sending a Post request from the NextJS client side with the current token, which is then searched for on the server. If the t ...

The power of absolute paths in React Native 0.72 with TypeScript

Hi everyone! I'm currently having some difficulty setting absolute paths in react native. I tried using babel-plugin-module-resolver, as well as configuring 'tsconfig.json' and 'babel.config.js' as shown below. Interestingly, VS Co ...

Creating JPEG images with specified dimensions. How can you add W x H sizing to an image?

I have been searching for a Deno/TypeScript code snippet that can create basic images with dimensions embedded on them. I have provided an example of the code below, which generates images in JPEG format, base64, and dataURL. The code works by adding RGB ...

Uncertainty surrounding the combination of observables due to their varying outcomes

Currently, I am developing an angular2 application that implements the ngrx store approach for state management. The source code for the app is available on github here The Issue at Hand The specific challenge I am encountering with this method involves ...

The element 'PROGRAM_ID' is not recognized within the 'import @metaplex-foundation/mpl-token-metadata' type

I am currently in the process of creating a token within the Solana network, but I've encountered a particular issue. I have successfully installed @metaplex-foundation/mpl-token-metadata and integrated it into my code; however, an error is persisting ...

When attempting to select dates from the picker options, the array is found to be devoid of any entries

My challenge lies in working with an array of dates retrieved from the server to determine which dates should be disabled on the datepicker. getStaffAvailability(){ let x = this; this.$http.get(this.weeklyAvailabilityUrl + "GetAv ...

Tips for accessing the app instance within a module in Nest.js

Currently, I am involved in a project that relies on multiple Nest repositories, approximately 4 in total. Each repository must integrate logging functionalities to monitor various events such as: Server lifecycle events Uncaught errors HTTP requests/resp ...

Having trouble getting the React form validation to work using Material UI TextField and TypeScript

I'm having trouble implementing validation on a "sign up" page using the MUI library in React with TypeScript. I've added the "required" attribute to each TextField tag, but the validation doesn't seem to be working upon submission. I'v ...

Customizable TypeScript interface with built-in default key value types that can be easily extended

One common pattern that arises frequently in my projects involves fetching values and updating the UI based on the 'requestStatus' and other associated values. type RequestStatus = | 'pending' | 'requesting' | 'succ ...

Troubleshooting: After Updating to Angular 8.3.5, App Module and Components Fail to Load in Angular Application

Recently, I attempted to upgrade our Angular 4 project to Angular 8. Following the migration guide provided by Angular, I made syntax changes. However, I encountered issues with styles not loading properly both locally and on Azure. To resolve this, I deci ...

Identify when a click occurs outside of a text input

Whenever text is typed into the textarea, the window changes color. The goal is to have the color revert back when clicking outside the textarea. <textarea class="chat-input" id="textarea" rows="2" cols="50" ...

converting JSON data into an Angular 2 object

I'm encountering a certain problem. The issue lies in a JSON string that contains all the variables from an object. Here's the object: export class UserInfo { ssn: string; userId: string; firstName: string; lastName: string; ...

Having trouble implementing the ternary operator (?) in TypeScript within a Next.js project

Trying to implement a ternary operator condition within my onClick event in a Next.js application. However, encountering an error indicating that the condition is not returning any value. Seeking assistance with resolving this issue... https://i.stack.img ...

How do I retrieve and display all the locally stored variables in Angular 2/JavaScript and calculate the total number of keys present in the localStorage?

Currently, I'm developing a project in Angular2 that involves the storage of user-added items to a shopping cart. To accomplish this, I have opted to utilize local storage to temporarily save the items. Each category (such as shoes, clothes, etc.) is ...

Searching with Mat-autocomplete across multiple fields simultaneously

I am struggling with a mat-autocomplete that contains 5000 objects, each consisting of a first name and a last name. My goal is to search for both the first name and last name simultaneously regardless of the input order. Currently, I can only search one ...

Sending emails using Angular 4 and PHP

Having some trouble sending email from the PHP send function. It's sending an email, but not populating it with any data - it's coming through as null. This is my Send Service in Angular. The message here contains all the data from my form: ...

Connecting table checkboxes to buttons in Angular 4.x: A step-by-step guide

Exploring Angular 4.x for the first time and faced with a challenge. I have created an HTML table where each row contains a checkbox and buttons. My goal is to link the checkboxes with the buttons in such a way that when a checkbox is checked, the correspo ...

Karma test encounters the absence of a defined Error Zone, causing an issue to

I have been encountering an error while trying to test a service in Angular. The error message reads: An error was thrown in afterAll Uncaught ReferenceError: Zone is not defined ReferenceError: Zone is not defined Despite visiting various forums and ...