Angular2 authguards encountering issues when trying to run asynchronous functions

I need a way to safeguard my routes by verifying if a user is logged in from the server, but I'm facing issues with asynchronous functions not executing properly.

Below is the code snippet that's causing trouble:

canActivate (route: ActivatedRouteSnapshot , state: RouterStateSnapshot): Observable<any> {
  let permission = route.data[ "permission" ];
   if(permission){
       ..execute another function which works
    )
  }else{
    return this.checkLogin();
  }
}

Regarding the checkLogin function:

checkLogin (url?: string): any {
  this.authService.checkLoggedin()
    .subscribe(
      res=>{
       if(res){
         return true;
       }else{
          this.router.navigate ( [ '/login' ] );
          return false
       }

    }
  )
}

Moving on to the auth service:

checkLoggedin():Observable<any> {
//validate user's login status using server call
  return this._httpclient.get(this.authurl + "/default/is-loggedin")
    .map(res => {

        return res.json().data;
    },error=>{
      return Observable.of(false);
      }
    );
}

Could someone point me in the right direction regarding where I might be making mistakes?

Answer №1

validateLogin should always return either an Observable<boolean> or a Promise<boolean> (or simply a boolean if it operates synchronously). Your current implementation is not returning anything.

To rectify this issue, consider the following approach. Instead of using subscribe, utilize map to transform the value emitted by checkLogStatus() and then encapsulate the boolean value in the returned Observable.

validateLogin(url?: string): Observable<boolean> {
    return this.authService.checkLogStatus()
    .map(
      res=>{
       if(res){
         return true;
       }else{
          this.router.navigate(['/login']);
          return false;
       }
    });
}

Additionally, it's advisable to refrain from declaring functions as returning any; specify the actual return type instead. This practice enables the compiler to detect instances where a return statement is missing when one is required.

Similarly,

checkLogStatus(): Observable<any>
ought to be written as
checkLogStatus(): Observable<boolean>
for improved error detection (potentially necessitating JSON data conversion).

Answer №2

When the navigation is successful, this.router.navigate() resolves to true, meaning that you are indeed returning true.

https://angular.io/api/router/Router

It is advisable to place the router.navigate method within the else block of your canActivate function after calling checklogin and evaluating its outcome.

Answer №3

Here is an alternative approach to consider:

function verifyAccess(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        let permission = route.data[ "permission" ]; //permissions are assigned to routes
       return !permission ? true : this.checkLoggedin()
                    .map((res: any) => {
                        if (res) {
                            return true;
                        }

                        throw new Error('User not logged in!');
                    })
                    .catch(() => {
                        this.router.navigate(['/login']);
                        return Observable.of(false);
                    });
            }

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 the mat-tree collides with a stylish css grid

Is there a way to transform a lengthy checkbox tree into a more manageable grid layout? The main issue is the lack of grouping wrappers, with only partial padding indicating group relationships. Check out this StackBlitz link for reference It seems that ...

Is there a way to establish a boundary for the forEach function in TypeScript?

In my web-based game, I use the forEach command to retrieve the team players in the lobby. However, for a specific feature in my game, I need to extract the id of the first player from the opposing team. How can I modify my current code to achieve this? T ...

html td elements are breaking due to the application of ngFor

<table> <tr> <th>Date</th> <th>Products</th> </tr> <tr *ngFor="let x of orderdetails"> <td>{{x.orderdate}}</td> <td *ngFor="let y of x.orderproducts"> <span class="break">{{y}}</s ...

What is the process for obtaining the result of an asynchronous function triggered by an event in HTML?

I am currently working on an Angular application where I have a button that triggers a click event. The method being called is asynchronous and involves subscribing to an observable. My goal is to call player.start() only after the listItems.getData() meth ...

Found a minor syntax problem in an Angular service related to error handling declaration

As I was working on customizing the Angular tutorial to fit my needs, I found myself wanting to merge the two error handler methods showcased in the tutorial into one. I appreciate the functionality of both methods and believe combining them will be benefi ...

Tips for successfully interacting with dynamic text areas using Protractor:

My current project involves e2e testing for an Angular 4 application with Protractor. Despite my efforts, I am struggling to locate a unique id, class, name or text identifier for a specific textarea within the application code. I need assistance in find ...

Merge arrays values with Object.assign function

I have a function that returns an object where the keys are strings and the values are arrays of strings: {"myType1": ["123"]} What I want to do is merge all the results it's returning. For example, if I have: {"myType1": ["123"]} {"myType2": ["45 ...

Issue with NGXS Selector Observable not reflecting updated state

My issue is that when I update the state, my selector does not pull the new values. I have defined the selector in my state and I can see the state values getting updated. However, the selector in my component is not fetching the latest values. Even though ...

Example of binding a popup to a geoJSON feature

Currently, I have successfully overlayed geojson data on a map, but I would like to enhance the user experience by allowing them to click on an area and view detailed information in a popup. I tried using the example provided on Leaflet's website: L.g ...

``Is there a specific scenario where the use of getInitialProps is recommended when automatically redirecting from one

Within my application, I have set up an auto-redirect from the root directory '/' to '/PageOne' with the following code: const Home = () => { const router = useRouter(); useEffect(() => { router.push('/pageone', ...

Guide on navigating to a specific step within a wizard using Vue and TypeScript

In this wizard, there are 6 steps. The last step includes a button that redirects the user back to step 4 when clicked. The user must then complete steps 5 and 6 in order to finish the wizard. step6.ts <router-link to="/stepFour" ...

Nextjs 13 brings exciting new features, one of which is the ability to call getStatic

I am working on a Next.js 13 application where I have organized my files in the 'app' directory instead of the usual 'pages'. All pages are statically generated during build time and data is fetched from an external API. Everything wor ...

Updating the button text in Angular 7

Here's a question: <button (click)="activateMotion(1)"> <img class="emotion-icon" id="positive-icon" src="" /> </button> <button (click)="activateMotion(-1)"> <img class="emotion-icon" id="negative-icon" src="" /&g ...

Troubleshooting Angular 2 Submodule Import Problem

I am facing an issue with a submodule that is using NgSemanticModule. The submodule works fine without the NgSemantic tags inside its components' templates, but fails when trying to use NgSemantic Components within the submodule. Interestingly, if I u ...

Creating a Mocha+Chai test that anticipates an exception being thrown by setTimeout

Here is what I have: it('invalid use', () => { Matcher(1).case(1, () => {}); }); I am trying to ensure that the case method throws an exception after a delay. How can I specify this for Mocha/Chai so that the test passes only if an exce ...

Enhancing TypeScript Native Interface Properties in TypeScript 2.4

After discovering an error in the native Typescript interface for HTMLTextAreaElement, I realized the need to make a correction. The current interface looks like this: interface HTMLTextAreaElement { setSelectionRange(start: number, end: number): void; ...

Utilizing an Observable in an Angular 6 service to ensure proper synchronization with Okta token present in local storage

Within my application, I have implemented third-party authentication to facilitate user login and store a token in their local storage. To enhance the user experience, I am developing a service to cache profile information. This service utilizes the user&a ...

Error TS2488 in React TypeScript: The data type 'IStateTypes' is required to have a method called '[Symbol.iterator]()' that returns an iterator

At the moment, I am working on implementing a global state in React Hooks but have run into an issue. https://i.stack.imgur.com/DN83K.png The current problem I'm facing is with [Symbol.iterator](. I am uncertain about how to resolve this as I am in ...

Testing the angular unit for a partially functioning ternary condition

Can you help me troubleshoot an issue with my test case for a ternary function? It works fine for true conditions, but not for false ones. I'm not sure what's wrong with my logic. What changes should I make to fix it? public getData(ball: any) ...

Implement new interface methods on-the-fly

I am seeking a way to dynamically incorporate methods that are defined in an interface. Initially, I considered using the index signature approach, but unfortunately, not all methods have the same signature. My objective is to preserve all type information ...