"CanDeactivate Implementation Failure: Why isn't the Generic Function Being Called

I am currently working on implementing a guard to prevent users from navigating to the login page once they have authenticated themselves. This guard should apply to all page components in my app except for the login page.

Below is the code snippet I am using:

import { Injectable } from '@angular/core';
import { Router, ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree, CanDeactivate } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthenticationService } from '../services/authentication.service';


@Injectable({ providedIn: 'root' })
export class AuthGuard<T> implements CanActivate, CanDeactivate<T> {

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

  canActivate(
    _route: ActivatedRouteSnapshot,
    _state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    return this.auth.isAuthenticated() || this.router.navigate(['/login']);
  }

  canDeactivate(
    _component: T,
    _currentRoute: ActivatedRouteSnapshot,
    _currentState: RouterStateSnapshot,
    nextState: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {

    if (nextState && nextState.url.includes('/login')) {
      return !this.auth.isAuthenticated();
    }

    return true;
  }

}
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from './guards/auth.guard';
import { HomeComponent } from './pages/home/home.component';
import { LoginComponent } from './pages/login/login.component';

const routes: Routes = [
  {
    path: 'login',
    component: LoginComponent
  },
  {
    path: 'home',
    component: HomeComponent,
    canActivate: [AuthGuard],
    canDeactivate: [AuthGuard]
  },
  {
    path: '**',
    redirectTo: 'home',
  }
];


@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers: [AuthGuard]
})
export class AppRoutingModule { }

I have also experimented with implementing a new canActivate guard specifically for the login component, which works but I am not fully satisfied with this approach.

I have come across examples like the one at . It seems using an interface in this context may not be the best practice as TypeScript does not support default method implementation. I seek a solution where I do not have to repeat the validation on every component.

Why is my current implementation not being called? How can I better approach this?

Any suggestions or guidance on this matter would be highly appreciated.

Additional information: Angular v14.1.3

Sample: https://stackblitz.com/edit/angular-ivy-hvz4mc

Answer №1

There are two injectable decorators in the authentication guard. See the example code snippet below for a working stackblitz.

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, CanDeactivate, Router, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthenticationService } from '../services/authentication.service';

@Injectable()
// @Injectable({ providedIn: 'root' }) // <-- mistake here
export class AuthGuard implements CanActivate, CanDeactivate<any> {

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

Forked StackBlitz

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

Exploring Angular 2's EventEmitter for Event Handling and Debugging

My attempt at creating a basic event emitter doesn't seem to be functioning properly. Here's the code snippet: Main Component This is the main app component I have been working on: @Component({ selector:'my-app', templateUrl: ...

Angular 6 Subscription Issue: Problems with Variable Assignments

Currently, I am working on a map feature that utilizes the mapbox API and relies on the longitudinal and latitudinal coordinates obtained from a geocoder. There is a particular service in place that calls an endpoint with certain parameters. Upon subscrib ...

The addControl function inside a for loop and async function is not properly assigning a value to the form

My goal is to iterate through an array, make a HTTP request, retrieve another array from it, and assign the selected object from the fetched array to a newly added Form Control in the form. This is how I approached it: for (let i = 0; i < typeaheadFiel ...

Generate a blueprint for a TypeScript interface

In my coding project, I've been noticing a pattern of redundancy when it comes to creating TypeScript interfaces as the code base expands. For example: interface IErrorResponse { code: number message: string } // Feature 1 type FEATURE_1_KEYS = ...

Troubleshooting nested form controls in Angular v12

When populating a dynamic form with data retrieved from the backend API, I encountered an issue with my code: sections: this.formBuilder.array([]) Within this code block, there is a nested array that is populated as follows: result.formSections.forEach(x ...

The 'RouterLink' JSX element type is missing any construct or call signatures

While researching this issue on the internet and Stack Overflow, I've noticed a common theme with problems related to React. An example can be found here. However, I am working with Vue and encountering errors in Vue's own components within a new ...

react state change not triggering re-render of paragraph

I recently started learning react and web development. To streamline my work, I've been using ChatGPT, but I'm facing an issue that I can't seem to solve. I'm trying to fetch movie descriptions from the TMDB API using movie IDs, but des ...

Angular Universal in combination with AngularFire server experiences a hanging issue due to the first() pipe

I am currently developing an angular/firestore application that requires SSR capabilities. I have integrated angular universal into the project and everything seems to be functioning properly until I utilize the first() pipe on any of the firestore calls, ...

Incorporating DevExtreme into an Angular application

After following the suggested command to add DevExtreme to my angular project using npx -p devextreme-cli devextreme add devextreme-angular, I encountered an issue related to node-modules/sass/embedded or a self-signed certificate problem. Despite trying s ...

Ensuring Function Parameter Usage in Typescript and Angular 5

Currently, I am developing a component using Angular 5 and Ionic 4. My objective is to include a Refresher event to hide the refresh spinner whenever the user triggers the final function to conceal the spinner. Provided below is an excerpt of my code: e ...

Is it feasible to add to an ID using ngx-bootstrap's dropdown feature?

In the documentation for ngx dropdown, there is a feature called "append to body." I recently tried changing this to append to a table element instead and it worked successfully. Now, on another page, I have two tables displayed. If I were to assign each ...

transformed an Angular 2 web application into a sleek and functional mobile application

I am looking to convert my basic angular2 web application into a mobile app using cordova. Is there a way to achieve this without relying on Ionic or nativeScript? ...

Tips for embedding HTML/CSS snippets in backticks when using TypeScript with AngularJS

Does anyone else experience the issue of their Angular 2 templates showing up as gray text in Visual Studio Code? I'm unable to use autocomplete or see my CSS properly. Is this a settings problem or is there a plugin that can solve this? BTW, I am us ...

Utilizing an Angular Service within the main.ts script

My main.ts file currently has the following code snippet: declare const require; const translations = require("raw-loader!./locale/messages.de.xlf"); platformBrowserDynamic().bootstrapModule(AppModule, { providers: [ { provide: TRANSLATIONS, useVa ...

Troubleshooting Problems with Angular Localization in EJ2 Syncfusion

I have been utilizing the Syncfusion Spreadsheet component to display data similar to an Excel spreadsheet. I successfully implemented all the necessary functionalities with Syncfusion documents, however, I am encountering a challenge. My current issue i ...

Typescript error: Cannot access property "status" on type "never".ts(2339)

Currently, I have a method that utilizes nextjs/auth to sign in with credentials from a form. However, I am encountering a type checking error Object is possibly 'undefined'.ts(2532) const doStuff = async (values: any) => { const result: S ...

What is the best way to have text wrap around an icon in my React application?

I am facing an issue while trying to display the note description over the trash icon in a React app. I have tried various methods but can't seem to achieve the desired effect. Can anyone guide me on how to get this layout? Here is what I intend to a ...

Jasmine encountered an error while trying to compare the same string: 'Expected the values to match.'

I'm encountering an error message, despite verifying that the strings are identical: Expected { $$state : { status : 1, value : { customerNumber : 'customerNumber', name : 'name', userId : 'buId', customerType : 'ty ...

What is the best way to utilize derived types in TypeScript?

Given object A: interface A { boolProp: boolean, stringProp: string, numberProp: number, ...other props/methods... } Now, I need objects that contain one of the properties from A and set a default value for it, with other properties being irre ...

Utilizing React Bootstrap with TypeScript for Styling Active NavItem with Inline CSS

Is it possible to change the background color of the active NavItem element to green using inline CSS in React Bootstrap and React Router Dom? I am currently using TypeScript 2.2 and React. If not, should I create a CSS class instead? Here is the code sni ...