6

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 を作成しました。ガード クラスは次のようになります。

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、私が持っているのはActivatedRouteSnapshotandだけですRouterStateSnapshotターゲット ルート (この場合はcategoryA )に対してナビゲートする方法はありますか? どんな助けでも本当に感謝します。

ノート:

  • いくつかのルート ガードを追加する以外に、ルート構成を変更できません。
  • this.router.navigateByUrlを使用して探しているわけではありませんstate.url。使いたいですrouter.navigate([...], { relativeTo: this-is-what-need})
4

1 に答える 1

14

Componentのような他の場所と比較して、 RouteGuard ではActivatedRoute注入されたコンストラクターの動作が異なることが判明しました。

コンポーネントでは、ActivatedRouteobject はそのコンポーネントをアクティブ化したルートを指します。たとえば、CategoryAComponentクラスでは、次のコードはCategoryBに移動します。

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

ただし、上記の同じコードは、 CategoryAルート構成RouteGuardに追加されたクラスでは機能しません。私のテストでは、コンストラクターによって注入されたオブジェクトがルート ルートを指していることがわかりました。一方、オブジェクト ( canActivate関数のパラメーターとして渡される) は、ターゲット ルート (私の場合はcategoryA ) を指します。ただし、このオブジェクトを関数に渡すことはできません。ActivatedRouteActivatedRouteSnapshotActivatedRouteSnapshotthis.router.navigate(...)

この問題を解決するより良い方法を見つけることができませんでしたが、次のコードはうまくいきます。

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;
        });
}
于 2018-04-13T18:15:38.870 に答える