Angular2相对路线在守卫中导航

时间:2016-12-06 12:34:18

标签: angular angular2-routing

我们在此处提供了儿童路线定义,我们使用警卫来检查用户是否在使用我们的服务之前接受了条款。

  

帐户/秘密/ secret.routes.ts:

import { Routes } from '@angular/router';
import { SecretFormComponent } from './secret-form.component';
import { SecretTermsComponent } from './secret-terms.component';
import { TermsGuard } from './services/terms-guard.service';

export const secretRoutes: Routes = [
  {
    path: '',
    redirectTo: 'form'
  },
  {
    path: 'form',
    component: SecretFormComponent,
    canActivate: [TermsGuard]
  },
  { path: 'terms', component: SecretTermsComponent }

  // otherwise redirect to form
  { path: '**',  redirectTo: 'form' }
];

在我们的术语守护中,我们已经定义了这段代码:

this.router.navigate(['/account/secret/terms']);
return false;

有没有办法在"路由组内使用相对路线导航重定向"?因为如果有一天我们的帐户网站仪表板被重命名为my-account等其他任何东西,那么定义绝对路径可能会中断。我们希望我们的秘密模块可以重复使用。

我希望能够在我的警卫中导航到['./terms'],但它不起作用,就像警卫不知道"从哪里" ;开始相对导航。

6 个答案:

答案 0 :(得分:10)

您要使用的是警卫RouterStateSnapshot方法的canActivate参数。

RouterStateSnapshot包含您正在路由到的当前路径,而Router.url是您路由的当前路径(这就是为什么@Günter Zöchbauer的答案没有在这种情况下工作得很好。

为了完全适用于没有附加代码的用例,您需要将路由更改为

/account/secret/form/account/secret/form/terms

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

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

    canActivate(_route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
        if (// user can view the specific route) {
            return true;
        }

        // else route them to a variation of the route
        this.router.navigate([state.url, 'terms']);

        return false;
    }
}

编辑1

您还可以利用ActivatedRouteSnapshot(如下所示)来保持当前的网址结构

假设路线如account/secret/formaccount/secret/terms

route.url是一个网址段数组,我们想要最后一个,因为它将是form。我们在当前路线中找到了我们尝试转到account/secret/formslice的索引。此时我们正在尝试导航到account/secret的当前路线的“父级”,我们可以将兄弟添加到form terms

注意:当您在网址中重复出现form时,此模式会中断。

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

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

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
        if (// user can view the specific route) {
            return true;
        }

        let parentUrl = state.url
            .slice(0, state.url.indexOf(route.url[route.url.length - 1].path));

        this.router.navigate([parentUrl, 'terms']);

        return false;
    }
}

答案 1 :(得分:1)

你应该能够从state.url获取你试图导航到的url,使用提供的urlSerializer解析它,然后在你需要的新urlSegment中拼接相对于守卫匹配的内容。

export class TermsGuard implements CanActivate<SecretFormComponent>{
    constructor(private router: Router, private urlSerializer: UrlSerializer) { }
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        let routerStateUrlTree = this.urlSerializer.parse(state.url);
        let newSegment = new UrlSegment('terms', {});
        routerStateUrlTree.root.children.primary.segments.splice(-1, 1, newSegment);
        this.router.navigateByUrl(routerStateUrlTree);
        return false;
    }
} 

你说“我希望能够导航到['./terms']”但根据你的路线,我认为你的意思是['../terms'],但如果你的意思是['。 / terms']只需将拼接的第二个参数更改为0,这样就不会删除最后一个段。

答案 2 :(得分:0)

您需要使用当前路线(例如ActivatedRoute)来创建相对于此路线的UrlTree。然后,您可以将此UrlTreethis.router.navigateByUrl(...)

一起使用
let urlTree = this.router.createUrlTree(['./terms'], {relativeTo: this.route});
this.router.navigateByUrl(urlTree);

答案 3 :(得分:0)

路由器具有 url 属性,用于保存当前网址。 你可以追加你的。

 
 this.router.navigate([this.router.url,'terms']);

答案 4 :(得分:0)

如果您想以Resolve<T>方法进行操作,可以这样做。

我认为对于任何类型的警卫都应采用相同的方法-使用pathFromRoot

此示例删除了最后一个“段”(即-1),并添加了"XXXXXXXX"

resolve(route: ActivatedRouteSnapshot) {

   const fullPathFromRoot = route.pathFromRoot.reduce<string[]>((arr, item) => ([...arr, ...item.url.map(segment => segment.path)]), []);
   const newUrl = [ ...fullPathFromRoot.slice(0, -1), "XXXXXXXX" ];

   this.router.navigate(newUrl);
}

route是给予您的路线-不要尝试注入ActivatedRoute,因为那样行不通。

答案 5 :(得分:0)

另一种方法是调整 url 并使用 navigateByUrl

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

import { AuthService } from "../services/auth.service.ts";

@Injectable({
  providedIn: "root",
})
export class AuthGuard implements CanActivate {
  constructor(
    private authService: AuthService,
    private router: Router
  ) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): true | Promise<boolean> {
    if (this.authService.isLoggedIn) {
      return true;
    }

    const urlParts = state.url.split("/");
    urlParts[urlParts.length - 1] = "login";
    const newUrl = urlParts.join("/");

    return this.router.navigateByUrl(newUrl);
  }
}