George
George

Reputation: 263

Router guard skip location change

We are using Angular 12 and trying to skip location change inside Router guard.Even if skipLocationChange = true, the location is always getting changed.

import { Injectable } from '@angular/core';
import {
  ActivatedRouteSnapshot,
  CanActivate,
  RouterStateSnapshot,
  Router
} from '@angular/router';

@Injectable()
export class TestGuard implements CanActivate {
  
  constructor( private router: Router) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        
    this.router.getCurrentNavigation().extras.queryParamsHandling = "merge";    
    this.router.getCurrentNavigation().extras.skipLocationChange = true;
    return true;
  }
}

skipLocationChange is not working. The location is always getting changed.

Upvotes: 3

Views: 6562

Answers (2)

wordsandnumbers
wordsandnumbers

Reputation: 1

Angular 18 has added a new way of doing this using a RedirectCommand and functional route guards:

import {
  ActivatedRouteSnapshot,
  CanActivateFn,
  RouterStateSnapshot,
  RedirectCommand,
  Router,
} from "@angular/router";
import {inject} from "@angular/core";

export function TestGuard: CanActivateFn = (
  next: ActivatedRouteSnapshot,
  state: RouterStateSnapshot,
) => {
  const router: Router = inject(Router);
  return new RedirectCommand(router.parseUrl("/new/location"), {
    skipLocationChange: true,
  });
}

Upvotes: 0

Daniel Gimenez
Daniel Gimenez

Reputation: 20589

What you're doing right now has no chance of working. The value of the currentNavigation field returned by Router.getCurrentNavigation() is always set from a copy of an internal variable. So any changes to the returned value won't have a significant impact to the function of Router.

If you're looking for a way to prevent location changes for particular routes then the guard is a good way of attacking the problem. Instead of trying to modify the navigation commands, stop the navigation and rewrite it with skipLocationChange set to true.

export class EnsureChangeSkippedGuard implements CanActivate {
  constructor(private router: Router) {}

  canActivate(_: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    const extras = this.router.getCurrentNavigation()?.extras;
    if (extras?.skipLocationChange) {
      return true;
    }

    const url = this.router.parseUrl(state.url);
    this.router.navigateByUrl(url, { ...extras, skipLocationChange: true, });
    return false;
  }
}

What this does is cancel the current navigation and recreate the route url but with skipLocationChange as true in the extras param. Extras is checked beforehand so an infinite loop doesn't occur.

I'm not sure if the way the new url is created is correct (though it worked in my testing). There could be some scenarios not covered, like with separate routing outlets.

Upvotes: 4

Related Questions