Reputation: 263
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
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
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