The data retrieved from the API requires a page refresh to display properly

I've encountered an issue with my authentication flow. After logging in with a user, I have to refresh the page to see the data correctly. Even after logging out and logging in with another user, the view still shows data from the previous user. It seems like it's always one step behind. I attempted to fix this by destroying the subscription but that didn't resolve the issue. Additionally, since the problem starts when I need to refresh the page for the first user's data, destroying the subscription may not be the correct solution.

Here is the code snippet:

auth.service: This is where users' credentials are posted, tokens are received, and data is stored for authenticated users.


import { Storage } from '@ionic/storage';
import { JwtHelperService } from '@auth0/angular-jwt';

export const TOKEN_KEY = 'access_token';
export const USERNAME_KEY = 'username_key';
export const USER_ID = 'user_id';
// Remaining code...

page.ts: This is where I retrieve and display the data in my view. The user service fetches a single user and the subscription is destroyed at the end.


import { Storage } from '@ionic/storage';
import { USER_ID } from 'src/app/services/auth.service';
import { SubscriptionLike } from 'rxjs';

// Remaining code...

login.ts: Manages routing to the main page.


// get return url from route parameters or default to '/'
// Remaining code...

authGuard


export class AuthGuard implements CanActivate {
  // Constructor and canActivate function...
}

Answer №1

It's recommended to subscribe to the observable instead of checking for

if (this.authService.authenticationState)
. Additionally, keep in mind that interacting with Ionic Storage is asynchronous, so it's crucial to wait for actions to complete before proceeding. Instead of directly calling next on your observable, consider using checkToken() to perform the check and then trigger next on the BehaviorSubject.

Take a look at this revised version:

Service:

import { BehaviorSubject, of, forkJoin } from 'rxjs';
import { tap, switchMap, map } from 'rxjs/operators;

// ...

private authenticationState = new BehaviorSubject(false);
public authenticationState$ = this.authenticationState.asObservable();

checkToken() {
  this.storage.get(TOKEN_KEY).then(access => {
    if (access) {
      this.authenticationState.next(true);
    } else {
      this.authenticationState.next(false);
    }
  });
}

apilogin(username: string, password: string) {
  return this.http.post<any>(`${this.url}`, { username, password }).pipe(
    // switch to inner observable
    switchMap((data: any) => {
      // run all in parallel
      return forkJoin(
        this.storage.set(TOKEN_KEY, 'access'),
        this.storage.set(USERNAME_KEY, 'username'),
        this.storage.set(USER_ID, 'id'),
      )
    }),
    // ensure storage values are set before calling checkToken()
    tap(() => this.checkToken()),
  )
}

// Subscribe to this function in the component for desired behavior
apilogout() {
  forkJoin(
    this.storage.remove(USER_ID),
    this.storage.remove(REFRESH_TOKEN_KEY),
    this.storage.remove(USERNAME_KEY),
    this.storage.remove(TOKEN_KEY)
  ).subscribe(() => this.checkToken())
}

Component should subscribe to the BehaviorSubject:

ngOnInit(): void{
  this.sub = this.authService.authenticationState$.pipe(
    switchMap((data) => {
      return data ? this.storage.get(USER_ID) : of(null)
    }),
    switchMap((id: any) => {
      this.id = id;
      return id ? this.userService.getUserDetails(id) : of(null)
    })
  ).subscribe(val => {
    // Perform necessary actions here!
  })
}

ngOnDestroy(){
  this.sub.unsubscribe();
}

Avoid using any, make sure to type your data properly to models :)

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

The module '@material-ui/lab' could not be located

I'm currently developing a front-end page that requires the use of @material-ui/lab. I encountered an issue after installing the package using npm, where I received a typescript error during compilation: TS2307: Cannot find module '@material-ui/l ...

A guide for finding a specific string within a subset of an array

I have an array containing various substrings, and I want to pass if at least one of those substrings contains the specific value I am searching for. Value1 = [ "Grape | 100 |Food Catering Service", "Apple | 100,000m |Food Catering Servi ...

The MatInput component in Angular Material remains valid even after the page has finished loading

Can you explain how the required attribute functions with matInput in Angular Material? Here is an example I tried: <mat-form-field class="example-form-field"> <mat-label>Clearable input</mat-label> <input matInp ...

Choose characteristics based on attributes, where the value after the colons is undefined

Hey everyone, I've been exploring ways to select HTML elements like: <div attr:something="else">Random content</div> I discovered that you can target these by using: document.querySelectorAll('[attr\\3A something]') ...

What are the steps to leverage npm installed packages in my .js files?

I'm new to web development and I'm trying to incorporate node packages into my workflow. Specifically, I'm attempting to test out the axios ajax library. It seemed like this would be a simple task, but it's proving to be quite challeng ...

JavaScript code to output CSS styled text: "echo"

Implementing anti-adblock on my site was necessary, as my bitcoin faucet relies on ads to function. I wrote some code to detect adblock on the client's browser: function TestPage() { if ($('.advertisement').height() == 0) var advertisement ...

What is the best approach for implementing Vuex with TypeScript?

My research on the topic has primarily led me to this informative article. I am currently working on setting up a store with 2 modules. export interface RootState { /** root state props **/ } const store: StoreOptions<RootState> = { module ...

A guide to dynamically adjusting the overflow property for the body element within an AngularJS application

I am facing a challenge in my AngularJS application where I need to dynamically control the overflow on the body element. Specifically, when a side nav is opened, I want to disable scrolling on the body. Below is a snippet of my code and I would appreciate ...

Unable to cancel the setTimeout function by using clearTimeout as the value appears to be null for unknown reasons

Within my react-native application, I am attempting to halt the execution of a setTimeout function by utilizing clearTimeout. The instance of setTimeout is stored in a global variable. let timeoutId: any = null; const doOtp = () => { if(can ...

The error message "Property '...' is not found on the type 'ServerContextJSONValue'" pops up whenever I try to utilize the useContext() function

After creating a Provider and defining the type, I encountered a TypeScript error when using it with useContext(): "Property '...' does not exist on type 'ServerContextJSONValue'. I'm not sure what I am missing. Can anyone help me ...

Utilize a function within an AngularJS directive

I'm struggling to understand how to pass a function (delegate) to a directive in AngularJS and utilize it within the link-function. Any guidance or suggestions on the correct approach would be immensely appreciated. Below is the controller code: myA ...

Is it possible to convert ejs to jade?

I'm struggling with the conversion of this ejs code to jade: <h1>I’m planning on counting up to <%= counter %></h1> <p><% for(var i = 1 ; i <= counter ; i++) { %> <%= i %>... <% } %></ ...

Is there a way to integrate the AuthState TypeScript Interface into the react-oidc-context Node package for testing in Next.js?

We are currently working on a Next.js application that utilizes the react-oidc-context Node module for authentication with ADFS. During our testing phase using Vitest, we encountered the following error: TypeError: Cannot read properties of undefined (rea ...

When transitioning between steps in the mat-horizontal-stepper component, the content disappears momentarily

Observed some unusual behavior while using the Material Stepper in conjunction with container animations. When clicking on a step while the mat-stepper is animating, the content of the step disappears. HTML: <strong> reload - while the stepper is ...

"Filtering a JSON File Based on Button Data Attributes: A Step-by-

I am working with a set of buttons that have specific data-map attributes as shown below: <button class="btn btn-default mapper" data-map="2015-11-13">Monday</button> <button class="btn btn-default mapper" data-map="2015-11-14">Tuesday&l ...

The current status of the ajax call is set to 0

I am currently attempting to retrieve information from a remote server on my local machine. The readyState seems to be fine, equal to 4. However, the status is consistently showing as 0 instead of 200. When I click the button, it doesn't return anythi ...

Techniques for Utilizing MongoDB Aggregation to Extract Specific Fields from Results

Welcome, everyone! I'm diving into the world of MongoDB aggregation, and after running some queries, I've finally obtained the following result: "result" : [ { "_id" : "531d84734031c76f06b853f0" }, { "_id" : "5316739 ...

Creating a dynamic jstree from scratch

My goal is to dynamically generate a jstree when a button is clicked. The user will select the entities from the tree, and I want to display that tree in the selected tab in tree format. The code below works perfectly fine if I use the variable aka as it ...

Implementing Express.js allows for the seamless casting of interfaces by the body within the request

I have created a similar structure to ASP.NET MVC and uploaded it on my github repository (express-mvc). Everything seems fine, but I am facing an issue with casting the body inside the request object to match any interface. This is what I am aiming for: ...

Tips for retrieving a parameter from the oncomplete attribute of an a4j:jsFunction tag

Is it possible to access a parameter for an <a4j:jsFunction> in the oncomplete="" attribute without using the action="" attribute and assingTo="" of <a4j:param>? <a4j:jsFunction name="refreshTableFilter" render="table,scroller" execute="@fo ...