'Angular CanActivate guard - createUrlTree relative navigation

I currently have a route guard such as

export class EntityGuard implements CanActivate {
  constructor(private readonly router: Router, ...) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean | UrlTree> {

  ...

This guard is activated for the URL

basePath/select/10/123

which means

basePath/select/:type/:id

When a certain condition is met, I need to force navigation back to

basePath/select/:type

How can I do that using createUrlTree? E.g.

if (...) {
   return of(this.router.createUrlTree([../', type]));
}

I'd need to set the

{ relativeTo: parent }

option. However I can't seem to find a way to do it.


My current solution is

private navigateBack(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
  const end = state.url.indexOf(route.url[route.url.length - 1].path);
  const parentUrl = state.url.slice(0, end);
  return of(this.router.createUrlTree([parentUrl]));
}

Which I really don't like. String manipulation is big no for me.



Solution 1:[1]

I have a workaround to get the URL Segment for current route:

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot,
  ): boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree> {
    const currentUrlFragments = route.pathFromRoot.flatMap((s) => s?.url ?? []).map((s) => s.path);
    return this.router.createUrlTree([...currentUrlFragments, '../']);
  }
}

Solution 2:[2]

There is one more workaround getting the url from Router like this this.router.getCurrentNavigation()?.extractedUrl.toString()

Full example below:


@Injectable({
  providedIn: 'root',
})
export class MyGuard implements CanActivate, CanLoad {
  constructor(private router: Router) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ):
    | Observable<boolean | UrlTree>
    | Promise<boolean | UrlTree>
    | boolean
    | UrlTree {
    return this.redirect();
  }

  canLoad(
    route: Route,
    segments: UrlSegment[]
  ):
    | Observable<boolean | UrlTree>
    | Promise<boolean | UrlTree>
    | boolean
    | UrlTree {
    return this.redirect();
  }

  private redirect() {
    let url = this.router.getCurrentNavigation()?.extractedUrl.toString() || '/';
    return this.router.createUrlTree([url, 'other', 'relative','path']);
  }
}

Guarding a path like hello/:name with the above guard would result navigating to hello/:name/other/relative/path, e.g. hello/world/other/relative/path.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nicolas
Solution 2