Issue with Angular2+'s redirectTo directive not functioning properly when attempting to redirect to a link that includes

I encountered an issue with the redirectTo not redirecting to a link with canActivate when I logged in.

The redirectTo functions correctly when I log out, redirecting to my /login component and then to /index after logging in.

However, it remains stuck on '' when I am logged in.

I added console.log to my authGuard, and noticed that the redirect URL "/index" does enter that function during the 'stuck' situation without causing any crashes in the development tool.

Interestingly, after commenting out the canActivate, the redirectTo resumes functioning properly as before.

For reference, my authGuard with canActivate works fine in other situations excluding the use of redirectTo.

Below is my app-routing.module.ts:

/* import... */

const appRoutes: Routes = [
    { path: 'login', component: LoginComponent },
    { path: '', redirectTo : '/index', pathMatch: 'full' },
    { path: '**', component: PageNotFoundComponent }
];

/* ngmodel and export ... */

and here's my index-routing.module.ts:

/* import ... */

const indexRoutes: Routes = [
    {
        path: 'index',
        component: IndexComponent,
        canActivate: [AuthGuard], //<- if comment this will work
    },
];

/*   ngmodel and export ... */

Here's my auth-guard.module.ts:

/* import ... */

@Injectable()
export class AuthGuard implements CanActivate {
    constructor(
        private authService: AuthService,
        private router: Router
    ) { }
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
        let url: string = state.url;
        //redirectTo did get in here
        console.log(url); 

        return this.checkLogin(url);
    }

    checkLogin(url: string): boolean {
        if (this.authService.login_data && (this.authService.login_data.userprofile || !this.authService.login_data.need_login)) {
            return true;
        }
        this.authService.get_login_data()
         .subscribe(
            data => {
                this.authService.login_data = data;
                if (data.userprofile || !data.need_login) {
                    return true;
                }
                this.authService.redirectUrl = url;
                this.router.navigate(['/login']);
                return false;
            },
            error => { this.authService.errMsg = <any>error;}
        );
    }
}

Recently, I updated my project to Angular 4.0.1. Thank you for your assistance.

UPDATE:

I have modified my guard return from boolean to Observable but unfortunately, the issue persists. Here is the updated code snippet:

checkLogin(url: string): Observable<boolean> {
        if (this.authService.login_data && (this.authService.login_data.userprofile || !this.authService.login_data.need_login)) {
            console.log('gonna return observable true');
            return Observable.of(true);
        }
        this.authService.get_login_data()
        .subscribe(
            data => {
                this.authService.login_data = data;
                if (data.userprofile || !data.need_login) {
                    
                    return Observable.of(true);
                }
                this.authService.redirectUrl = url;
                this.router.navigate(['/login']);
                return Observable.of(false);
                
            },
            error => { this.authService.errMsg = <any>error;}
        );
    }

In the console, I receive "in subscribe and gonna return observable true". Any insights would be appreciated.

UPDATE:

Upon exploring the issue further, I came across a post mentioning that canActivate may not wait for the subscription to complete. This could be causing the problem at hand.

Answer №1

When implementing the checkLogin() function in your AuthGuard:

checkLogin(url: string): boolean {
    if (this.authService.login_data && (this.authService.login_data.userprofile || !this.authService.login_data.need_login)) {
        return true;
    }
    this.authService.get_login_data()
     .subscribe(
        data => {
            this.authService.login_data = data;
            if (data.userprofile || !data.need_login) {
                return true;
            }
            this.authService.redirectUrl = url;
            this.router.navigate(['/login']);
            return false;
        },
        error => { this.authService.errMsg = <any>error;}
    );
}

The issue lies in not returning anything immediately, causing the function to return undefined which affects the canActivate check.

[Updated] To set user data from the result, utilize do() in authService.get_login_data(). Use .map() instead of subscribe() in checkLogin() to map the login result data to boolean.

In such cases, it is recommended to return an Observable type:

checkLogin(url: string): Observable<boolean> {
if (this.authService.login_data && (this.authService.login_data.userprofile || !this.authService.login_data.need_login)) {
    return Observable.of(true); // wrap true in Observable
}
return this.authService.get_login_data()
 .map(
    data => {
        if (data.userprofile || !data.need_login) {
            return true;
        }
        this.authService.redirectUrl = url;
        this.router.navigate(['/login']);
        return false;
    },
    error => { this.authService.errMsg = <any>error;}
);

}

Answer №2

I managed to resolve my issue by switching from using subscribe to map.

Angular2 canActivate() calling async function

Here is the updated version of my code.

checkLogin(url: string): Observable<boolean>|boolean {
    if (this.authService.login_data && (this.authService.login_data.userprofile || !this.authService.login_data.need_login)) {
        console.log('Going to return observable true');
        return Observable.of(true);
    }
    return this.authService.get_login_data()
    .map(
        data => {
            this.authService.login_data = data;
            if (data.userprofile || !data.need_login) {
                console.log('In map and going to return observable true');
                return true;                                                                                                                                                
            }
            this.authService.redirectUrl = url;
            this.router.navigate(['/login']);
            return false;
        },  
        error => { this.authService.errMsg = <any>error;}
    );  
}  

I encountered an error in the map when trying to return Observable(true).

Type 'Observable<Observable<boolean>>' is not assignable to type 'boolean | Observable<boolean>'.

Thank you for the assistance and suggestions.

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

After routing, parameters are mistakenly being inserted into the URL

When working with Angular 5 and using routing to move between pages / components, I am facing an issue. Specifically, in the login component, after signing out I navigate to the Home component but unnecessary parameters are being added to the URL. Below i ...

Obtain the Enum's Name in TypeScript as a String

I am currently looking for a solution to transform the name of an enum into a string format. Suppose I have the following Response enum, how can I obtain or convert 'Response' into a string? One of my functions accepts any enum as input and requi ...

What is the best way to retrieve the current value of an *ngFor loop upon button click?

I have been attempting to retrieve the data.login value of the data item that the user has clicked on the avatar image. Despite my efforts, I have not been able to successfully achieve this through various methods found online. How can I access the current ...

ngx-slick-carousel: a carousel that loops infinitely and adjusts responsively

I have implemented ngx-slick-carousel to showcase YouTube videos in my project. However, I am facing two main issues. Firstly, the carousel is not infinite, and when the last video is reached, there appears to be white spaces before it loops back to the fi ...

Encountering an error while implementing a Typescript addEventListener for keydown events

Struggling with adding and removing event listeners to HTML elements capable of focus, such as buttons. encountering a typescript error specifically related to the lines of code responsible for adding and removing the event listener: focusableElements.fo ...

When attempting to create a generic key value interface, Typescript will throw an error if a mapped type is used that declares properties or methods

I am attempting to design an interface that can accept generic key-value pairs in the following format export interface GetModel<K extends string, T> { [key in K]: T; } However, I encountered this error message A mapped type may not declare prop ...

Angular's Viewchild isn't functioning properly

I am facing an issue in calling a method of a child component from the parent component to pass a property. export class PruebabookComponent implements OnInit { public identity; public token; public books: Book[]; public totalPages; public page ...

Continuing the operation following the closure of a modal

Exploring the unknown territory of transitioning from Ionic 1 to Ionic 4 brings about its fair share of challenges. In my previous Ionic 1 projects, I heavily relied on functions incorporating Ionic popups for seamless operations. Referring to a sample co ...

How to check all checkboxes in Angular using ngFor and ngIf?

Is there a way to select all checkboxes in an Angular form that uses ngFor and ngIf? I want to activate all checkboxes for the months when I click on "Select All". The list of months is stored in an array. Click here to see the HTML representation of the ...

Arranging Objects by Date in TypeScript

I came across a code snippet that helps sort objects in an array by date, but I'm having trouble converting it to TypeScript. this.filteredTxs.sort(function(a,b): any{ return new Date(b.date) - new Date(a.date); }); Here's the error mes ...

Switching from using Google Geocoding to integrating the Mapbox Places API within an Angular 2 application

I have been developing a web application that geocodes a point upon clicking on a map. The app was initially built in Angular 2, but I do not have a strong grasp of Angular. Currently, the app uses Google for geocoding and updates the text box automatica ...

Obtaining a phone number from a contact in Nativescript Angular: A step-by-step guide

Upon executing the following code: let desiredFields = ['display_name','phone','thumbnail','email','organization']; console.log('Loading contacts...'); let timer = new Date().getTime(); Contact ...

The configuration file for Typescript and Typeorm, specifically the .ts file, is encountering an error

Hello, I'm encountering an issue with my app.ts. When trying to load my settings from ormconfig.ts for the typeorm function that creates the connection, I receive the following error: No overload matches this call. Overload 1 of 3, '(name: stri ...

Encountered an issue while setting up ng-circle-progress in Angular: Unable to find an exported member in

I am currently working on incorporating the ng-circle-progress functionality by referring to the documentation at https://www.npmjs.com/package/ng-circle-progress. Here is a snippet from the .ts file: import { Component } from '@angular/core'; i ...

Creating rectangular shapes on the canvas with the help of react hooks

I have a React+Typescript web application and I am currently working on implementing the functionality to draw rectangles on a canvas. My goal is to utilize React hooks instead of classes in order to achieve this. The desired outcome is to enable the user ...

Retrieve all elements within an Angular6 Directive that share the same name as the Directive

I have created a custom Directive called isSelected and applied it to several elements in different components as shown below: <i isSelected class="icon"></i> <i isSelected class="icon"></i> <i isSelected class="icon"></i ...

What is the best way to loop through a template literal union type in JavaScript?

Is there a way to iterate over the different values in a string union type created with template literals? type Foo = "Foo" | "Foo2" | "Foo3"; type Bar = "Bar" | "Bar2" | `${Foo}Type`; One common approach is to use a <const> assertion, like this: c ...

Challenges managing errors in Angular unit tests

As I continue to learn Angular, my search for information has yielded minimal results. However, one resource that stood out was a post on Stack Overflow titled How to write a test which expects an Error to be thrown in Jasmine? After reviewing the aforeme ...

Troubleshooting problems encountered when duplicating an array in JavaScript

I am attempting to utilize properties and flatmap to modify an array without altering the original data. I have implemented this method in two different instances within a single dispatch call in Vue.js when transferring data from parent to children comp ...

Tips for validating the loading variable during testing of the mockservice in angular5

In the process of creating a test case suite for my application, I am faced with the challenge of verifying and validating the loading variable in my component spec file. The scenario involves calling an API service from my component to retrieve data, show ...