簡體   English   中英

Angular:如何在 RouteGuard 中相對於目標路由調用 router.navigate()?

[英]Angular: how to call router.navigate() relative to target route in a RouteGuard?

我有一個使用 Angular 4 開發的現有項目。我需要根據用戶權限控制對特定路由的訪問。 簡化的路由配置如下所示:

[
    { path: '', redirectTo: '/myApp/home(secondary:xyz)', pathMatch: 'full' },
    { path: 'myApp'
      children: [
        { path: '', redirectTo: 'home', pathMatch: 'full' },
        { path: 'home', ... },
        ...
        { path: 'product'
          children: [
            { path: '', redirectTo: 'categoryA', pathMatch: 'full' },
            { path: 'categoryA', component: CategoryAComponent, canActivate: [CategoryACanActivateGuard]},
            { path: 'categoryB', component: CategoryBComponent},
            ...
          ]
        },
        ...
      ]
    },
    ...
]

現在,我想控制對www.myWeb.com/myApp/product/categoryA的訪問。 如果用戶沒有足夠的權限,他/她將被重定向到... /product/CategoryB 我寫了一個CanActivate RouteGuard 來做到這一點,保護 class 看起來像這樣:

import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot, ActivatedRoute } from '@angular/router';
import { MyService } from '... my-service.service';

@Injectable()
export class CategoryACanActivateGuard implements CanActivate {
    constructor(private myService: MyService, private router: Router) { }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
        return this.myService.checkPermission()
            .then(result => {
                if (!result.hasAccess) {
                    //redirect here

                    this.router.navigate(['./myApp/product/categoryB']); 
                    //works, but I want to remove hardcoding 'myApp'

                    //this.router.navigate(['../../categoryB']);
                    //doesn't work, redirects to home page

                    //this.router.navigate(['./categoryB'], { relativeTo: this.route});
                    //do not have this.route object. Injecting Activated route in the constructor did not solve the problem

                }
                return result.hasAccess;
            });
    }
}

一切正常,但我希望相對於目標路由進行重定向,如下所示:

this.router.navigate(['/product/categoryB'], { relativeTo: <route-of-categoryA>});
// or 
this.router.navigate(['/categoryB'], { relativeTo: <route-of-categoryA>});

不幸的是, relativeTo只接受ActivatedRoute對象,而我所擁有的只是ActivatedRouteSnapshotRouterStateSnapshot 有沒有辦法相對於目標路線進行導航(在這種情況下為 categoryA )? 任何幫助將不勝感激。

筆記:

  • 除了添加一些路由保護之外,我無法更改路由配置。
  • 我不是在尋找this.router.navigateByUrl使用state.url 我想使用router.navigate([...], { relativeTo: this-is-what-need})

事實證明,與Component等其他地方相比,構造函數注入ActivatedRouteRouteGuard中的工作方式有所不同。

在組件中, ActivatedRoute對象指向激活該組件的路由。 例如,在CategoryAComponent類中,以下代碼將導航到CategoryB

this.router.navigate([ '../CategoryB' ], { relativeTo: this.route });

但是,以上相同代碼在添加到CategoryA路由配置的RouteGuard類中RouteGuard 在我的測試中,我發現構造函數注入的ActivatedRoute對象指向根路由。 另一方面, ActivatedRouteSnapshot對象(在canActivate函數中作為參數傳遞)指向目標路由(在我的情況下為categoryA )。 但是,我們無法在this.router.navigate(...)函數中傳遞此ActivatedRouteSnapshot對象。

我找不到解決此問題的更好方法,但是以下代碼對我有用:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
    return this.myService.checkPermission()
        .then(result => {
            if (!result.hasAccess) {
                //redirect here

                let redirectTo = route.pathFromRoot
                    .filter(p => p !== route && p.url !== null && p.url.length > 0)
                    .reduce((arr, p) => arr.concat(p.url.map(u => u.path)), new Array<string>());

                this.router.navigate(redirectTo.concat('categoryB'), { relativeTo: this.route });
            }
            return result.hasAccess;
        });
}

我可以為您提供一個更精簡的解決方案:

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): true | UrlTree {
    const urlTree = createUrlTreeFromSnapshot(route, ['categoryB']);
    return result.hasAccess || urlTree;
  }

使用此解決方案,您可以輕松設置所有其他可能需要的道具 - 命名插座導航、查詢參數、片段...

如果您位於/ product / CategoryA,並且想要導航到/ product / CategoryB,則可以使用相對導航:

this.router.navigate([ '../CategoryB' ], { relativeTo: this.route });

您可以使用 Angular 14 中的新createUrlTreeFromSnapshot() function,如下所示:

const urlTree = createUrlTreeFromSnapshot(routeSnapshot, ['../categoryB']);
this.router.navigateByUrl(urlTree);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM