Using an Angular Promise and Conditional Statement for Authentication Guard

I am trying to implement a guard that determines whether a user can access the login page, but I suspect my approach is flawed due to my use of Promises. Here is the relevant code snippet:

  canActivate(): boolean | Observable<boolean> | Promise<boolean> {
    if (!this.localStorage.getObject('isInitialized')) {
      this.router.navigate(['/locations']);
      return true;
    }
    return false;
  }

I understand that my current implementation is incorrect, but I lack understanding of how to properly work with Promises in this scenario. Any guidance on what steps I need to take to correct this issue?

This is the function localstorage.getObject() that I am using:

  // Returns object
  async getObject(key: string) {
    const ret = await Storage.get({ key: key });
    return JSON.parse(ret.value);
  }

Answer №1

When implementing an async result based condition in your canActivate method, consider utilizing a Promise. If you are working with a direct value stored in local storage, there is no need to use a promise. Take the following approach to incorporate a promise...

canActivate(): Promise<boolean> {
  return new Promise((resolve) => {
    if (!this.localStorage.getObject('isInitialized')) {
      this.router.navigate(['/locations']);
      // Deny access to the route
      resolve(false);
    } else {
      // Grant access to the route
      resolve(true);
    }
  });
}

Answer №2

There are a few issues to address here, but the promise itself doesn't seem to be the main problem. Your function signature suggests the possibility of returning three different types,

canActivate(): boolean | Observable<boolean> | Promise<boolean>

However, you only ever return a boolean value. So in reality, you could simplify this to,

canActivate(): boolean

The real issue lies elsewhere. Without seeing your route configuration, it seems like you might be redirecting the user unnecessarily if they are allowed access to the requested route. Route guards should only trigger when a user is attempting to navigate to a page. If the guard allows the navigation (returns true), the user proceeds to the protected page.

But what happens if the guard denies access? You need to specify where to redirect the user in such cases.

A typical implementation might look something like this,

@Injectable()
export class AuthGuard implements CanActivate {
    constructor(private router: Router) {}

    canActivate(state: RouterStateSnapshot): boolean {
        if (!this.localStorage.getObject('isInitialized')) {
            //Allow user to proceed to requested page
            return true;
        } else {
            //Redirect user to '/anotherpage' if not logged in
            this.router.navigate(['/anotherpage']);
            return false;
        }
    }
}

Next, define your routes as follows,

export const appRoutes: Routes = [
    {
        path: 'pageProtectedByAuthGuard',
        component: YourComponent,
        canActivate: [AuthGuard]
    }
];

Finally, ensure that you import these routes in your module,

@NgModule({
    imports: [RouterModule.forRoot(appRoutes, { enableTracing: false })],
    ...
})

For more information on CanActivate, visit: https://angular.io/api/router/CanActivate

Answer №3

The solution presented here involves checking if the localStorage object 'isInitialized' is true, and then navigating to a specific route if it is.

    this.localStorage.getObject('isInitialized').then((response) => {
      if (response == true) {
        this.router.navigate(['/locations']);
        return false;
      }
    });
    return true;
  }

It's important to remember that the auth guard is triggered when the user tries to access a certain page - keeping things simple is key!

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

I'm confused why this particular method within a class is not being inherited by the next class. Rather than seeing the expected extension, I am presented with - [Function (

Working fine with the Person class, the register() function displays the correct return statement when logged in the console. However, upon extending it to the Employee class, instead of the expected return statement, the console logs show [Function (anon ...

Issue with Angular ngFor: displaying only one name instead of all names in the loop

In my component.ts file, I have retrieved this data from an API call: [ [ { "name": "name one", "desc": "something here", }, { "name": &quo ...

Accessing the observable's value by subscribing to it

There is a defined observable called imageOptions$ in my code: imageOptions$: Observable<BoundImagesToProject[]> = this.imagesService .getBoundImages({ projectId: this.projectId }) .pipe(map((images) => (images.data))); and it is used in the temp ...

Angular is constantly on the lookout for the assets folder located in the directory above

I am currently working on a project using Angular 5 that I am deploying on my server at /var/www/html/myproject . I am able to access it at 192.168.1.1/myproject without any issues. However, there seems to be an issue with the 'assets' folder. W ...

Delete the option "x" from the kendo combobox

Is there a way to eliminate or hide the clear ("x") action from a Kendo combobox using TypeScript? I have attempted to find a solution through SCSS/CSS, but I have not been successful. Alternatively, I would be fine with preventing the event triggered by ...

What is the best way to execute a task once the observable is finished with its actions?

I am facing a challenge where I need to execute a specific action on the outcome of an observable nested within another observable. Component checkIn(room: Room) { this.roomService.checkIn(room.number).subscribe( response => { t ...

The directive subscription remains inactive even when the subject triggers the next function

Plunkr: https://plnkr.co/edit/KfPfVSbZm087uIPvFEkM?p=preview I have developed a service that serves as an API for a modal component. In addition, there is a directive available that can be used to apply a class to any element when the modal is open. Howev ...

In Angular, make a call to a second API if the first API call times out after a specified period

In the event that my API does not return data within 5 seconds, I need to call a different one. Attempted implementation: this.service.returnData1(param1, param2) .pipe(timeout(5000), finalize(() => this.callSecondApi())) .subscribe( data => { ...

NgrxStore - An initial item has been added twice to the array

Currently experimenting with ngrx store and manipulating elements within an array, such as deleting, fetching, and editing, works smoothly. However, a challenge arises when inserting an object into the array for the first time, duplicating the entry unless ...

Unable to append item to document object model

Within my component, I have a snippet of code: isLoaded($event) { console.log($event); this.visible = $event; console.log(this.visible); this.onClick(); } onClick() { this.listImage = this.imageService.getImage(); let span = docu ...

Utilizing process.env in TypeScript can be a bit tricky as dot notation is not effective for accessing its properties

When I set my scripts to: "start": "NODE_ENV=development nodemon dist/Server.js", I am encountering an issue when trying to access NODE_ENV in my code. Both dot and bracket notation return undefined: The dependencies in my project are: "@types/node": "^8. ...

Exploring the operation sequence within asynchronous functions

Here is a code snippet extracted from this URL: return new Promise((resolve, reject) => { const req = https.request(URL, options, res => { let rawData = ''; res.on('data', chunk => { rawData ...

Switch over tslint to @angular-eslint/schematics: Cannot resolve dependency tree: @angular/[email protected] due to ERESOLVE

I am in the process of transitioning from tslint to eslint in my Angular 11 library by following the official documentation here. After running the command ng add @angular-eslint/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail=" ...

TypeScript Redux Thunk: Simplifying State Management

Seeking a deeper understanding of the ThunkDispatch function in TypeScript while working with Redux and thunk. Here is some code I found: // Example of using redux-thunk import { Middleware, Action, AnyAction } from "redux"; export interface ThunkDispatc ...

Experiencing a hitch when attempting to deploy an Angular 2 application on Heroku

Encountering the sh: 1: tsc: not found Error when attempting to deploy an Angular 2 app on Heroku. Using Node version: v7.2.0 and npm Version: v4.0.3. View the error on Heroku Any suggestions on how to resolve this issue? ...

Encountering a TypeScript error in MUI 5 when attempting to spread values in props

I am encountering an issue with a typescript error related to the MUI sx prop. The problem arises when I attempt to merge or spread multiple sx values into an sx prop, resulting in an error. It seems to work fine if only one item is present in the sx prop, ...

Is it possible to extract Apollo type guards from a package?

I came across a helpful Apollo type guard that I want to integrate into my app. Here is the code snippet: export function isField(selection) { return selection.kind === 'Field'; } You can find it in node_modules/@apollo/client/utilities/grap ...

The ng-model used within an *ngFor loop is not displaying the correct value

I am working with a JSON file in my Angular2 App. The specific JSON object I am referring to is named tempPromotion and I am trying to access the data within ['results'] like this: tempPromotion['response_payload']['ruleset_list ...

Creating a secure API that is accessible exclusively by the front-end: A step-by-step guide

I've been scouring the internet for a while now, trying to understand the concept of creating a private API exclusively between the front-end and back-end. What I really want is an API that can only be accessed through the front-end interface, not via ...

Typescript's ability to have Enums with dynamic keys

Suppose I define: enum Sort { nameAsc = 'nameAsc', nameDesc = 'nameDesc' } Is it possible to do the following? const key = 'name' + 'Desc'; Sort[key] Appreciate any help in advance ...