What is the best way to implement an Angular Guard that utilizes an API service for validation and redirects in case of failure?

Hello there!

I am currently working on an Angular 7 application that deals with time cards. One of the main features I have implemented is a CanActivate Guard for controlling access to certain components. The CanActivate code utilizes Observables to decide whether a user should be allowed entry or redirected.

  timecardID: number;
  constructor(private globals: Globals, private router: Router, private securityService: SecurityService) { }
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | boolean {

    if (next.params.timecardId) {
      this.timecardID = +next.params.timecardId;
      return this.hasAccessToTimecard();
    }

    return this.empNumber === this.globals.empNumber;
  }


  //Checking if current user has access to specific timecard
  hasAccessToTimecard(): Observable<boolean | UrlTree> {
    return this.securityService.hasRightsToTimecard(this.timecardID);
  }

The following snippet shows the service being called:

  private readonly HasRightsToTimecardURI = 'api/Security/HasRightsToTimecard';
  private readonly HasRightsToEmployeeURI = 'api/Security/HasRightsToEmployee';

  constructor(private http: HttpClient, @Inject('BASE_URL') private baseUrl: string, private router: Router) { }

  //I don't like the use of router to navigate here. But without it, on false return the UrlTree isn't used for redirections.
  public hasRightsToTimecard(timecardID: number): Observable<boolean | UrlTree> {
    let parameters = new HttpParams();
    parameters = parameters.set('timecardID', String(timecardID));

    return this.http.get<boolean | UrlTree>(this.baseUrl + this.HasRightsToTimecardURI, { params: parameters }).pipe(
      tap((result) => {
        this.router.navigate(['/home']);
        return  result ? result : this.router.createUrlTree(['/home']);
      })
    );
  }

I have confirmed that the logic works correctly, creating a UrlTree when the API returns false and handling true results properly.

However, I am facing issues with accessing the route through different methods:

  1. When using controls within the app's component, I have proper access as the guard allows me through
  2. If incorrect access is detected using controls in the component, the guard prevents me from proceeding to the route, which is expected behavior
  3. Directly typing the route URL in the browser results in a blank screen, instead of redirecting or showing content

If anyone could provide assistance, I would greatly appreciate it.

In addition, here's a relevant part of the route setup (excluding other details):

const routes: Routes = [
  {
    path: 'timecards', canActivateChild: [RightsGuard], children: [
      { path: 'edit/:timecardId', canActivate: [TimecardGuard], component: TimecardNewComponent }
    ]
  }
];

Answer №1

After spending some time working on it, I finally figured out the solution to my problem. It turns out that I was using tap() incorrectly. According to the documentation, tap does not change the value; it always returns the original one. In this case, map() was the correct function to use.

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

Enhancing the type safety of TypeScript Generics

Uncertainty looms over me - am I committing an error, or is this all part of the plan... Within my academic domain class Collection<E> { ... } Lies a function public Insert(item: E): void { ... } I construct a specific instance of my list const ...

Aligning Bootstrap Buttons

How do I create a gap between my Bootstrap4 button and the top of the table, while also aligning it to the edge of the table? <div class="container"> <div class="table-title"> <div class="row"> ...

Issue: The function "MyDocument.getInitialProps()" needs to return an object containing an "html" prop with a properly formatted HTML string

Check out my project on GitHub at https://github.com/Talita1996/NLW4 To start the project, I used the command yarn create next-app project_name I made changes to some files by modifying their extensions and adding new code Next, I added typescript to the ...

Steps to duplicate the package.json to the dist or build directory while executing the TypeScript compiler (tsc)

I am facing an issue with my TypeScript React component and the package.json file when transpiling it to es5 using tsc. The package.json file does not get copied automatically to the dist folder, as shown in the provided screenshot. I had to manually copy ...

Error TS2307 - Module 'lodash' not found during build process

Latest Update I must apologize for the confusion in my previous explanation of the issue. The errors I encountered were not during the compilation of the Angular application via Gulp, but rather in the Visual Studio 'Errors List'. Fortunately, I ...

Trigger a click event on a nested Angular 13 component to remove a class from its grandparent component

In my Angular 13 project, I am working with 3 components: Child Component : Burger-menu Parent Component : Header Grand-Parent Component : app.component.html Within the burger-menu component, there is a close button. When this button is clicked, I want t ...

Updating the background color using typescript

Before transitioning to angular development, I had experience working with vanilla Javascript. I encountered a challenge when trying to modify the css properties of specific elements using Typescript. Unfortunately, the traditional approach used in Javascr ...

Acquiring and resetting Angular states: A beginner's guide

I'm facing a situation where I need to perform a route jump (essentially a refresh) on the same page, but this jump includes state data. However, even though the state contains valuable information, I am only able to access it through history and cann ...

Creating a dynamic return statement in typescript: A step-by-step guide

I am looking to dynamically set a return value to a variable based on values retrieved from an API. The current function in question uses static values: this.markDisabled = (date: NgbDate) => { return (this.calendar.getWeekday(date) !== 5 && ...

Utilizing Google Sheets as a secure, read-only database for Angular applications without the need to make the sheet accessible to the

Seeking a way to utilize Google Sheets document as a read-only database for my Angular application, I have attempted various methods. However, the challenge with all these approaches is that they necessitate public sharing of the Sheet (accessible to anyon ...

Guide to showcasing associated information in HTML using Angular 7

I am a beginner with Angular 7 and I am attempting to showcase a product's color on the HTML side using Angular 7 but have not been successful. Below are my tables; Product Id Name Color Id Name ProductColorRelation Id ProductId ColorId In ...

When I attempt to conceal the filter within mat-table using *ngIf, I encounter an issue where I am unable to read the property 'value' due to it being

After creating a mat-table, I encountered an issue when trying to show and hide my input filter area using a button. If I use *ngIf="showInputFilter" to hide the filter area, I receive the error message Cannot read property 'value' of u ...

Getting a string output from a Typescript promise

Here is some Typescript code that I thought would be simple. public showDialog(theNickname: string): string { var req = { method: 'POST', url: '/Q/GetUserDetails', data: { nickname ...

What are the steps to integrate the aws-iot-device-sdk NPM module with Angular 11? I am encountering errors related to fs, path, and tls during the build process

I manage a browser-based Angular application that was previously on version 5.6. This app consists of two components that subscribe to an IOT topic and listen for updates without publishing. The task at hand is to upgrade to Angular 11.0.3, which I have c ...

Issues may arise in TypeScript when you are working with an array of objects along with other properties within a type

I am encountering an issue with an object structure similar to the one below: let Obj = { ['0'] : { mode: 'x' }, getMode: () => 'x' } The problem arises when I attempt to create a type definition as shown here: type Obj = ...

Node.js, sigma.js, and the typescript environment do not have a defined window

When attempting to set up a sigma.js project with node.js in TypeScript, I encountered a reference error after starting the node.js server: ts-node index.ts The problem seems to be located within the sigma\utils\index.js file. <nodejsproject& ...

The module './login/servcioprueba1.service' is missing the exported member 'prueba'. Kindly add this member to resolve the issue

I am working on an Angular 8 project that involves a service file. To generate the service, I used the command: ng g s servicioprueba1 After generating the service, I imported it into my code as shown below. Included in Block 2 is the line where I impor ...

Functionality not functioning within Shadow DOM

After creating and exporting an Angular Element as a single script tag (user-poll.js), using the element on a host site is simple. Just include the following two lines: <user-poll></user-poll> <script src="path/to/user-poll.js"></sc ...

how to send both the useState setter and object as props to a child component in React using TypeScript

Having an issue with passing useState setter and object (both together) to the child component. Successfully passed the object by spreading it like this {...object}, but unsure of the syntax to pass the setter along as well. Here's a code example: < ...

Capacitor and Angular: Trouble with appStateChange listener functionality

In my quest to solve a KPI, I am attempting to trigger a logEvent using the Firebase SDK when the user closes the application (specifically in an Ionic/Capacitor/Angular environment). However, I am facing numerous challenges trying to access the appStateCh ...