Dealing with errors when implementing an Angular 2 route guard that returns an Observable of type boolean can be a

My route guard is implemented as follows:

@Injectable()
export class AuthGuard implements CanActivate {

constructor(private router: Router, private authenticationSvc: AuthenticationService) { }

canActivate(): Observable<boolean> {
    return this.authenticationSvc.getAuthenticatedUser().map(
        r => {
            if (this.authenticationSvc.isAuthenticated()) {
                // User is logged in, so return true
                return true;
            }
            this.router.navigateByUrl('/login');
            return false;
        })
}

However, I am facing an issue where sometimes getAuthenticatedUser returns a 401 error. I have an HTTP interceptor that handles the 401 error and redirects to the login page. The problem arises when the .map function never resolves due to the error thrown by the HTTP request. This causes the Angular router to get stuck on the initial routing request and fails to handle subsequent requests from the interceptor. How can I manage this error and ensure that the Observable returned resolves to false without interrupting the flow?

  getAuthenticatedUser() {
         let getUserObservable = this.http.get(ApiUrl + 'security/getAuthenticatedUser')
            .map((res: any) => res.json())
            .share()

        // Get the result for the cache
        getUserObservable.subscribe(
            r => {
                if (r.success) {
                    this.authenticatedUser = r.result.user;
                }
            }); 

        // Return the observable
        return getUserObservable;
  } 

Here is the HTTP interceptor implementation:

export class HttpInterceptor extends Http {
    authSvc: AuthenticationService;
    lastClicked: any = 0;
    constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private _router: Router, private injector: Injector) {
        super(backend, defaultOptions);
    }
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.request(url, options));
}

get(url: string, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.get(url, options));
}

post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.post(url, body, this.getRequestOptionArgs(options)));
}

put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.put(url, body, this.getRequestOptionArgs(options)));
}

delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.delete(url, options));
}

getRequestOptionArgs(options?: RequestOptionsArgs): RequestOptionsArgs {
    if (options == null) {
        options = new RequestOptions();
    }
    if (options.headers == null) {
        options.headers = new Headers();
    }
    options.headers.append('Content-Type', 'application/json');
    return options;
}

 intercept(observable: Observable<Response>): Observable<Response> {
    return observable.catch((err, source) => {
        // Handle 401 error - clear auth cookie and navigate to login page
        if (err.status == 401) {
            this._router.navigateByUrl('/login');
        }

        return Observable.throw(err);
    });
}

Answer №1

To handle errors and return an Observable<bool>, you can use the following code:

@Injectable()
export class AuthGuard implements CanActivate {

constructor(private router: Router, private authenticationSvc: AuthenticationService) { }

canActivate(): Observable<boolean> {
    return this.authenticationSvc.getAuthenticatedUser().map(
        r => {
            if (this.authenticationSvc.isAuthenticated()) {
                // User is authenticated, so return true
                return true;
            }
            this.router.navigateByUrl('/login');
            return false;
        })
        .catch((error: any) => {
            this.router.navigateByUrl('/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

Is there a way to ensure that @angular/core is utilizing the most up-to-date version of zone.js in its peerDependencies configuration?

This code passes the test, but there is an issue: it('should successfully retrieve data when getDownloadProgress() is called', (done: DoneFn) => { let response = { 'process': {}, 'success': 'success ...

Styling with react-jss based on intricate conditionals

After experimenting with react-jss for a few weeks, I am faced with the challenge of styling components efficiently. With numerous conditionals in these components, I am striving to avoid creating an excess of new components that essentially share the same ...

The Main Page is always the default destination when navigating with Angular Router

Having an issue with Angular Router (Angular 11). Here is my routing configuration: {path: '', redirectTo: '/login', pathMatch: 'full'} {path: 'login', component: LoginComponent} {path: 'verdicts', componen ...

Navigating the correct way to filter JSON data using HttpClient in Angular 4

Struggling with transitioning from Http to HttpClient, here's the code in question: constructor(public navCtrl: NavController, public http: HttpClient, private alertCtrl: AlertController) { this.http.get('http://example.com/date.php') .su ...

Storing data with Laravel 5.3 using Storage::put and XMLHttpRequest

Attempting to send a file using DRAG & DROP with XMLHttpRequest. $images = $_FILES['images']; When I use foreach: foreach($images["name"] as $file => $name) and move_uploaded_file($images["tmp_name"][$file], $images_dir . $name it works ...

A TypeScript interface creating a type with optional keys of various types while enforcing strict null checks

I am attempting to devise an interface in typescript that resembles the following: type MoveSpeed = "min" | "road" | "full"; interface Interval { min?: number, max?: number } interface CreepPlan { [partName: string] : Interval; move?: MoveSpe ...

Error: Trying to use Router without providing a middleware function. Please make sure to pass a valid middleware function while using Router

While working on my express application with MongoJS, I encountered an issue where despite returning a function, it was showing that an object has been returned instead. To address this, I made sure to include module.exports=router in my JavaScript file. H ...

Display the table upon completion of the form submission

I am trying to create a form where the table #mytable is only displayed after the form has been submitted. If nothing is entered in the form, the table should remain hidden. Any suggestions on how I can achieve this? <form action="" id="myform" method ...

Error 2300 in Vetur: Identical identifier found for '(Missing)'

Recently, I've been encountering a strange issue with Vetur in my typescript nuxt.js project. Every component, whether it's just an empty line or contains code, displays an error message on the first line. I can't pinpoint when this problem ...

What could be the reason for receiving no file input after submitting the form?

One of the functions triggers the input file and displays previews: $(document).on("change", "#Multifileupload", function() { var MultifileUpload = document.getElementById("Multifileupload"); if (typeof FileReader != & ...

Typescript challenge: Implementing a route render attribute in React with TypeScript

My component has props named project which are passed through a Link to a Route. Here's how it looks (the project object goes in the state extended property): <Link to={{ pathname: path, state: { project, }, }} key={project. ...

Discovering the precise location of the required() file

When using the require function in the `node` console with commands such as require('path') or require('assert'), how can I determine the absolute path of the file that was loaded? I have searched everywhere for a clear answer without ...

Is there an issue with my JavaScript append method?

Within the following method, an object named o gets appended to a list of objects called qs. The section that is commented out seems to be causing issues, while the uncommented section is functional. What could possibly be wrong with the commented part? on ...

Utilizing jQuery for easy drag-and-drop functionality in web development

I have two lists which are currently using jQuery for functionality. An example can be found here. I need the same basic functionality but with some modifications: Instead of just getting all sortable items by clicking "Get items," I want to be able to dr ...

Switching from AngularJS to vanilla JavaScript or integrating AngularJS and Flask on a single server

It is common knowledge that angular has the ability to create a project and convert it into pure HTML, CSS, and js code. Similarly, I am looking to do the same for my AngularJS application. When I execute the app using npm start it works perfectly fine. My ...

typescript: the modules with relational paths could not be located

As part of a migration process, I am currently converting code from JavaScript to TypeScript. In one of my files 'abc.ts', I need to import the 'xyz.css' file, which is located in the same directory. However, when I try to import it usi ...

Employing the Eclipse Palantir TypeScript Plug-in in conjunction with JSPM

I currently utilize the Palantir Eclipse TypeScript Plug-in (v1.8.0.v20160223-1645), which functions flawlessly when my d.ts files are stored in the same source folder /src. However, due to JSPM, these files reside in a different folder now, causing issues ...

Angular: A module in the library declares an HttpInterceptor that intercepts requests that are made outside of the

I am encountering an issue with Angular where a custom instance of HttpInterceptors within an Angular library is intercepting requests for HttpClient calls made outside the library (i.e. in the consuming application). I'm finding it difficult to gras ...

I feel like I'm stuck in a never-ending loop of COR issues that are blocking my progress on

My main focus is establishing a direct connection between a computer and a Raspberry Pi within a local network. It's important to clarify that this project will never have any connection to the internet. The Raspberry Pi is running a NodeJS server th ...

How do I incorporate global typings when adding type definitions to an npm module?

Suppose I create a node module called m. Later on, I decide to enhance it with Typescript typings. Luckily, the module only exports a single function, so the m.d.ts file is as follows: /// <reference path="./typings/globals/node/index.d.ts" /> decl ...