【问题标题】:Angular2 relative route navigate in a guardAngular2 相对路径在警卫中导航
【发布时间】:2017-04-21 02:28:02
【问题描述】:

我们在此处提供了子路由定义,其中我们使用保护来检查用户在使用我们的服务之前是否已接受条款。

account/secret/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'],但它不起作用,就像警卫不知道“从哪里”开始相对导航一样。

【问题讨论】:

    标签: angular angular2-routing


    【解决方案1】:

    你要使用的是你的守卫的canActivate方法的RouterStateSnapshot参数。

    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 {
            // user can view the specific route
            if (...) {
                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 是一个 url 段数组,我们想要最后一个,因为那将是 form。我们在我们试图去account/secret/formslice的当前路线中找到它的索引。此时,我们有当前路线的“父”,我们试图导航到account/secret,我们可以将兄弟添加到form,即terms

    注意:当您在 url 中重复出现 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 {
            // user can view the specific route
            if (...) {
                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;
        }
    }
    

    【讨论】:

      【解决方案2】:

      另一种方法是调整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);
        }
      }
      

      【讨论】:

        【解决方案3】:

        如果您想在 Resolve&lt;T&gt; 方法中执行此操作,您可以这样做。

        我认为这同样适用于任何类型的守卫——使用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,因为那是行不通的。

        【讨论】:

          【解决方案4】:

          您应该能够从 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,这样它就不会删除最后一段。

          【讨论】:

            猜你喜欢
            • 2017-06-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-05-21
            • 2017-05-08
            • 1970-01-01
            • 2016-07-10
            • 1970-01-01
            相关资源
            最近更新 更多