The second guard in Angular 5 (also known as Angular 2+) does not pause to allow the first guard to complete an HTTP request

In my application, I have implemented two guards - AuthGuard for logged in users and AdminGuard for admins. The issue arises when trying to access a route that requires both guards. The problem is that the AdminGuard does not wait for the AuthGuard to finish making an HTTP request to fetch user information from the API before checking the role of the user. This results in the application breaking as the user object is undefined. I am seeking a solution to ensure that the second guard waits for the first one to finish.

{
    path: 'admin',
    component: AdminComponent,
    canActivate: [AuthGuard, AdminGuard]
},

@Injectable()
export class AuthGuard implements CanActivate {
    constructor(
    private authService: AuthService,
    private http: HttpClient) { }

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

        return this.http.get('https://jsonplaceholder.typicode.com/users').map(res => {
            console.log('Auth Guard.');
            console.log(res);
            this.authService.user = {role: 'admin'};

            return true;
     });

         return false;
    }
}

@Injectable()
export class AdminGuard implements CanActivate {
    constructor(private authService: AuthService) { }

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

        console.log('Admin Guard.');
        console.log(this.authService.user);

        if (this.authService.user.role === 'admin') {
             return true;
        }

        return false;
   }

}

Here is a plnker link - http://plnkr.co/edit/EqgruNjogTJvsC1Zt5EN?p=preview

Answer №1

An important concept to grasp is the asynchronous nature of calls in the AuthGuard. These calls may not be resolved immediately, unlike synchronous code which executes without waiting for them to complete (resulting in the user being undefined).

To make AdminGuard wait for the resolution of your HTTP call, you can store an Observable Subscription (or a promise) to the AuthService within the AuthGuard where the call is made:

this.authService.subscription$ = this.http.get('https://jsonplaceholder.typicode.com/users');

Once the subscription is stored in AuthService, all that's left is to subscribe to it in both guards using .map():

AuthGuard:

return this.authService.subscription$.map(res => {
  this.authService.user = {role: 'admin'};
  return true;
});

AdminGuard:

return this.authService.subscription$.map(res => {
  if (this.authService.user.role === 'admin') {
    return true;
  }
});

You can see a functioning example at the following link: http://plnkr.co/edit/R2Z26GsSvzEpPdU7tOHO?p=preview

If you observe "AuthGuard returns TRUE!" and "AdminGuard returns TRUE!" in your console, then everything should be working properly. I also included logs of the this.authService.user variable from both guards.

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

Tips for downloading a file in React using raw file data

I've been struggling with a particular issue for the past couple of days and just can't seem to find a solution. It involves retrieving data from an API on our outdated system related to Attachments and other information. When I execute the query ...

Ways to conceal a column within columnSelection

Can anyone help me with setting the Column selection for Sender and Receiver in bootgrid without including Id in the column selection dropdown? I need some guidance on how to achieve this. Check out the image below for reference https://i.sstatic.net/4EEW ...

Are there any better methods for transforming a class component into a hook component?

After some attempts, I'm working on getting this code to function properly using useState: https://codesandbox.io/s/rdg-cell-editing-forked-nc7wy?file=/src/index.js:0-1146 Despite my efforts, I encountered an error message that reads as follows: × ...

What are the benefits of using material-ui@next without the need for

Thinking about creating a project using material-ui@next, but trying to avoid using withStyles. However, encountering issues with the draft of TypeScript that includes the decorator @withStyles. This leads to one question - is it possible to use material ...

The average duration for each API request is consistently recorded at 21 seconds

It's taking 21 seconds per request for snippet.json and images, causing my widget to load in 42 seconds consistently. That just doesn't seem right. Check out this code snippet below: <script type="text/javascript"> function fetchJSONFil ...

Searching for a method to retrieve information from an API using jQuery in Node.js?

I'm currently working on fetching data from an api to display on the front-end. This is my server-side code - app.get('/chats',function(req,res){ User.find({}).exec(function(err,user){ res.send(user); }); }); On the clie ...

Is it possible to alter the parent scope from an AngularJS directive?

I am currently in the process of constructing my initial Angular application, but I am encountering some difficulties while attempting to achieve a specific functionality. The issue revolves around a video container which is supposed to remain hidden until ...

Conceal any errors and warnings from appearing in the console

Many programming languages, such as PHP, provide methods to suppress error and warning messages. Is there a similar approach in JavaScript or jQuery to stop errors and warnings from appearing in the console log? ...

Is there a way to access an Excel file with JavaScript without relying on the ActiveX control?

Is there a way to access an Excel document using JavaScript code without relying on an ActiveX control object such as shown below: var myApp = new ActiveXObject("Excel.Application"); myApp.workbooks.open("test.xls"); ...

` `issues with fmt:massage tag` `

When I try to update my page elements using ajax, I encountered a problem: the fmt:message tag doesn't work when I set it in javascript. In the JSP page everything works fine: <div id="div"> <fmt:message key="search_select_country"/> & ...

What is the method to retrieve Response Headers in cases of an empty response?

Currently, I am working with Angular2 and dotcms. My goal is to retrieve response headers after making a call to subscribe. const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) .append('Access ...

Unexpected errors are encountered when using ng serve

When I run the ng serve command, unexpected errors are occurring on my system. The errors include: PS C:\Users\SAYED-SADAT\Desktop\data\coding\itsm-frontend\itsm-frontend> ng serveYour global Angular CLI version (13.0 ...

Attempting to update Typescript on Linux Mint using npm

I am currently using typescript 2.1.4 and npm version 6.7.0. Realizing that 2.1.4 is quite outdated, I decided to try and update it. Here are the steps I took, which unfortunately did not work: $ sudo npm update -g typescript $ tsc --version Vesion 2.1. ...

Unable to properly zoom in on an image within an iframe in Internet Explorer and Google Chrome

My image zoom functionality works perfectly on all browsers except for IE and Google Chrome when opened inside an iframe. Strangely, it still functions flawlessly in Firefox. How can I resolve this frustrating issue? The image link was sourced from the i ...

Double invocation of useEffect causing issues in a TypeScript app built with Next.js

My useEffect function is set up with brackets as shown below: useEffect(() => { console.log('hello') getTransactions() }, []) Surprisingly, when I run my app, it logs "hello" twice in the console. Any thoughts on why this might be ...

Removing properties of an object or a mapped type in Typescript by their values

Can we exclude specific properties from an object using a mapped type based on their value? Similar to the Omit function, but focusing on the values rather than the keys. Let's consider the following example: type Q = {a: number, b: never} Is there ...

What is the best way to determine which component/service is triggering a method within an Angular 2 or 4 service?

Is there a way to determine which component or service is triggering the method of a specific service, without the need to pass additional parameters? This information must be identified directly within the service. If you have any insights on how this c ...

utilizing jQuery to iterate through JSON data with a random loop

Is there a way to modify this code to display only one image randomly selected from a JSON file that contains multiple images? Here is the code in question: $(document).ready(function() { $.getJSON('https://res.cloudinary.com/dkx20eme ...

Selectize Fails to Populate Options Using Ajax

ExpressJS is the platform I am using to develop a management dashboard for a community project. Right now, my main concern is integrating a modal that allows users to add new games to a database. Although I am able to fetch data remotely, I am facing diffi ...

Is it possible for the sum to turn into NaN in Bootstrap Table JavaScript?

I used bootstrap to create a table that links with phpmyadmin. I need to show the total current amount in the table, which should update when using the search function. However, I keep getting NaN as my result. Below is the relevant code: // PART OF CODE ...