The BehaviorSubject does not update its value right away

I designed a custom login service using the AuthGuard feature in Angular. My implementation involves utilizing a SessionService that offers methods like login() and onUserLoggedIn(), which essentially returns a BehaviorSubject containing the current user status (logged in/not logged in). To enhance this service, I developed an implementation of AuthGuard implements CanActivate service. In this implementation, I invoke the onUserLoggedIn method to verify the value in the subject at that moment. A challenge arises where the value changes in the login method after the AuthGuard calls onUserLoggedIn. Consequently, during the initial attempt, I receive a false value from the BehaviorSubject; however, upon retrying, I get the true value.

How can I modify the implementation of these services to achieve the correct value on the first try?

AuthGuard:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
    : Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    console.log('auth');

    return this.sessionService.onUserLoggedIn()
      .pipe(
        map(res => {
          console.log('res', res);
          return res;
        }),
        take(1),
        tap(allowed => {
          console.log(allowed);
          if (!allowed) {
            this.router.navigate(['/login']);
          }
        })
      );
  }

SessionService:

private isLoggedIn = new BehaviorSubject(false);

  constructor(private apiService: ApiService) {
  }

  login(user: User): Observable<any> {
    console.log('hello before');
    return this.apiService.post(`${BASE_URL}/login`, user)
      .pipe(
        tap((token: Token) => {
          this.isLoggedIn.next(true);
          localStorage.setItem('token', token.token);
          console.log('hello');
        })
      );
  }

  onUserLoggedIn() {
    return this.isLoggedIn;
  }

The log outputs for the first attempt are as follows:

  • SessionService.ts:19 hello before
  • AuthGuard.ts:17 auth
  • AuthGuard.ts:22 res false
  • AuthGuard.ts:27 false
  • SessionService.ts:25 hello

For the second attempt (which ideally should have been the initial one):

  • SessionService.ts:19 hello before
  • AuthGuard.ts:17 auth
  • AuthGuard.ts:22 res true
  • AuthGuard.ts:27 true
  • SessionService.ts:25 hello

Answer №1

When you subscribe to a BehaviorSubject, it immediately emits the given value.

If this behavior aligns with your use case, consider using Subject instead. You can also utilize the skip operator to skip the first value.

return this.sessionService.onUserLoggedIn()
      .pipe(
        take(1),
        map(res => {
          console.log('res', res);
          return res;
        }),
        tap(allowed => {
          console.log(allowed);
          if (!allowed) {
            this.router.navigate(['/login']);
          }
        })
      );
  }

In other components, make use of startsWith(false).

Answer №2

Have you attempted to return it as an Observable?

getUserStatus() {
        return this.userLoggedIn.asObservable();
      }

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

When sending an http.post request in Angular 2, the req.body parameter may sometimes

I'm currently facing an issue with my Angular 2 application. I'm attempting to send JSON objects to my MongoDB database. When I click the "post" button, it successfully sends the _id to my MongoDB, but my req.body remains empty. import { Inj ...

Incorporate a fresh attribute to the JSON data in an Angular API response

I'm currently working on updating my JSON response by adding a new object property. Below is an example of my initial JSON response: { "products": [{ "id": 1, "name": "xyz" }] } My goal is to include a new object property ca ...

challenges encountered while integrating an external library into Angular 8

I am currently experimenting with implementing a profitWell script in my angular application. Here is the script I am working with: <script id="profitwell-js" data-pw-auth="XXX"> (function(i,s,o,g,r,a,m){i[o]=i[o]||function(){(i[o].q=i[o].q| ...

Leveraging merge with lettable operators

I am currently facing an issue with mapping an array of items to observables and then combining them using the merge operator. My goal is to achieve this using lettable operators. Here's an example of what I've been attempting: // obs is an arra ...

Issue: Unable to locate a change supporting element '[object Object]' of the type 'object - Angular 7'

An angular service has been created for the specified purpose: CheckTicket(barcode, codEspec, diaHoraEspec):Observable<Ticket[]>{ //read ticket return this.http.get<Ticket[]>(`${this.checkticket_url}${barcode}?token=${this.token}&a ...

React component state remains static despite user input

I am currently in the process of developing a basic login/signup form using React, Typescript (which is new to me), and AntDesign. Below is the code for my component: import React, { Component } from 'react' import { Typography, Form, Input, But ...

Convert Time: segment time devoted to the main content from the time dedicated to advertisements

Can anyone assist me with solving a math problem? Let's consider two lists or arrays: Content Array 0-50 = C1 50-100 = C2 AD Array 10-20 = A1 30-60 = A2 80-140 = A3 The desired output should be: 0-10 = C1 10-20 = A1 20-30 = C1 30-60 = A2 60-80 = C ...

Issues with tracking changes in Vue.js when using reactive variables

After triggering a click event, I am attempting to choose a message from a json file. However, I am encountering an issue where the first click does not seem to select anything. Upon the second click, the selected messages are duplicated, and this pattern ...

Resolving undefined in Ionic 4: Returning Data from Modal

I'm attempting to create a modal window that utilizes a radio group. When a user selects a value from the radio group, I want the modal to return the selected object. Here is the code for the radio group page and HTML: export class PopoverstationsPa ...

Is it advisable to include auto-generated files in an npm package upon publication?

I have a TypeScript NPM package where my build process compiles all *.ts files into myLib.d.ts, myLib.js, and myLib.js.map. In order for my NPM package to function properly, it requires the src/*.ts files as well as the auto-generated myLib.* files. Howe ...

Ways to modify the input field value in my form based on the current page context

I am currently developing a website for a sports event organization company using Angular, HTML/CSS. The focus of this website is on the triathlon sport and it consists of several stages. On the home page, there are five image tags representing each stage ...

Connecting a hybrid/web client application to established remote web services outlined through a set of WSDL specifications

Summarizing the Problem I am faced with the task of integrating a mobile hybrid application, likely built on Ionic, that will need to indirectly consume several SOAP web services. My goal is for the TypeScript client in the mobile app to have knowledge of ...

Angular 4 prohibits certain special characters and the number zero

Currently, I am a beginner in Angular 4 and I am working on learning how to search for data from a text box. However, whenever I input special characters like "%" in my code, it triggers an error leading to a crash in my application. Is there any effectiv ...

What steps should I take to create a TypeScript generic class that is limited to only accepting types that are arrays of objects?

I'm working on creating a sample of a generic class in TypeScript. My goal is to have a generic class named RecordsProcessor that is limited to only accept types that are arrays of objects. If I try to pass a number to the constructor, TypeScript cor ...

Address the NPM alert regarding Bootstrap's 'unmet peer dependency' in Angular even if Bootstrap is not utilized

In my web project, I am using Angular 5.2.0 along with Bootstrap 4. To install Bootstrap 4, I used the command npm i bootstrap --save, which resulted in unmet peer dependencies warnings: npm WARN <a href="/cdn-cgi/l/email-protection" class="__cf_email_ ...

Encountering an issue while trying to integrate custom commands using the addCommand function in WebDriverIO

When using the addCommand function to add a new command, I encountered an error message that states: [ts] Property 'WaitForElementsAmount' does not exist on type 'Client<void>'. Here is an example of the code snippet I used: br ...

Troubleshooting image upload issues with AWS S3 in Next.js version 13

I encountered a consistent problem with using the AWS SDK in NextJS to upload images. I keep getting error code 403 (Forbidden). Could there be other reasons why this error is occurring besides the accessKeyId and secretAccessKey being invalid? Below is my ...

TypeScript: Defining a custom type based on values within a nested object

I'm attempting to generate a unique type from the value of a nested object, but encountering failure if the key is not present on any level of nesting. Can someone point out where I might be making a mistake? const events = [ { name: 'foo&apos ...

Click on an element in Angular to toggle it

A function in my codebase is responsible for toggling a specific section within a div element. Currently, there are a total of 3 sections available in the app. The functionality is implemented in the app.component.ts file: show = false; toggle() { ...

What causes a BehaviorSubject to update when modifying the [(NgModel)] values of a form without actually submitting the form?

When I work with a form that relies on a BehaviorSubject to load user information, I noticed that if I make changes to the inputs but navigate away from the page without submitting the form, the user information gets updated in the subject automatically. ...