【问题标题】:Angular router: how to replace param?角度路由器:如何替换参数?
【发布时间】:2018-06-10 13:42:22
【问题描述】:

假设我有 3 个网址: /:projectId/info, /:projectId/users, /:projectId/users/:userId/profile。他们都有参数projectId。 UI 有一个组件可以从一个项目切换到另一个项目。所以我需要:

  1. 获取当前网址
  2. 按名称更改参数(例如 projectId)
  3. 导航到新网址

所以我需要this.router.replaceParam(currentUrl, {projectId: 'project_id_2'}) 之类的东西,它将/project_id_1/users/user_id_1/profile 转换为/project_id_2/users/user_id_1/profile(以及任何其他带有:projectId 参数的URL)

我认为这是一个简单而常见的问题,但在 1 小时内没有找到解决方案。建议的here 解决方案不像最后一条评论中提到的那样工作

【问题讨论】:

  • 不确定是什么问题。如果你在那个 URL 上,路由组件可能已经使用了 projectId(否则这个参数就没用了,不是吗?),所以只需使用 this.router.navigate([this.projectId, 'users']) 为例。
  • @JBNizet 我更新了我的问题,请检查清楚吗?
  • @fedor.belov 你试过 router.navigate(['/'+yourprojectId + '/users/' + youruserId + '/profile' ]) 吗?

标签: angular angular2-routing angular-routing


【解决方案1】:

要从当前网址导航到特定链接,您可以执行以下操作,

 constructor(private route: ActivatedRoute, private router: Router){}
 ngOnInit() {
     this.route.params.subscribe(params => {
         // PARAMS CHANGED ..    

         let id = params['projectid'];    
     });
 }
 navigate(){
     this.router.navigateByUrl(this.router.url.replace(id, newProjectId));
     // replace parameter of navigateByUrl function to your required url
 }

在 ngOnInit 函数上,我们订阅了 params,因此我们可以观察并执行我们的语句,以了解 url 参数的任何变化。

编辑

案例:id 可以相同的地方

constructor(private route: ActivatedRoute, private router: Router){}
     projectId:string;
     userId: string;
     ngOnInit() {
         this.route.params.subscribe(params => {
             this.projectId = params['projectid']; 
             this.userId = params['userId'];
         });
     }
     navigate(){
         // for /project/:projectId/users/:userId/profile
         this.router.navigate(['/project', this.projectId, '/users', 
         this.userId, '/profile']);
     }

【讨论】:

  • 这是最接近的解决方案,但我不能接受,因为它需要 URL 中的唯一 ID
  • 你能简单介绍一下你到底想要做什么吗?
  • 如果你的 rute 是 'location/:id/business/:id' 并且两个 id 都是 1,我只想更改第二个,你的解决方案如何工作?
  • 这是在做string.replace吗? ...如果您的 url 是 /account/123/project/123 怎么办?这不会把事情搞砸..这只是假设 id 在整个 url 字符串中是唯一的。
  • -1 即使参数名称不同,也是错误的。例如:如果路由参数是/:projectId/users/:userId,并且项目的id恰好与用户的id相同,它将替换两者,这是不希望的。
【解决方案2】:

您可以使用 HTML 或 Ts

1> 在 HTML 中

[routerLink]="['../info']"
        Or
[routerLink]="['../users']"
    like this etc....

2> 在打字稿中

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

【讨论】:

  • 如果您在路由 :projectId/items/:itemId 中,则在标头中使用您的解决方案不起作用,并且当来自基本路由 /:projectId -> Navigate to ../items-> /items 时,它也不起作用所需的/:projectId/items
【解决方案3】:

你可以使用:

this.router.navigate(
      [],
      {
        relativeTo: this.activatedRoute,
        queryParams: {projectId: 'project_id_2'},
        queryParamsHandling: "merge", // remove to replace all query params by provided
      });

【讨论】:

  • 这将是最优雅的解决方案。不幸的是,它仅在数据通过 queryParams 传递时才有效。
  • 我非常同意@thomai 的评论
【解决方案4】:

我今天遇到了 angular 9 的这个问题。 就我而言,我有树 url-scenario:

  1. something/i-ignore/../my-path 我在哪里显示一个预定义的值,(例如:最新值)
  2. something/i-ignore/../my-path -> something/i-ignore/../my-path/1 我明确要求从基本 url 开始的 /1 资源
  3. something/i-ignore/../my-path/1 -> something/i-ignore/../my-path/2 我在哪里更改我请求的资源

一种有趣的方法是proposed by Omkar Jadhav,他以编程方式从activatedRoute 倒退了一步

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

我用code proposed by Michael的简化版本对参数更改事件做出了反应

this._route.params
  .subscribe((params) => {
    console.log(params) // prints {resourceId: "1"}
  });

结合上面所说的一切,我可以开始我的导航处理情况 2. 和 3。

const url = this.router.url.split('my-path');
if (url[1] && 0 < url[1].length) {
  this.router.navigate(['../' + this.newResourceId],{relativeTo: this.activatedRoute});
} else {
  this.router.navigate([this.newResourceId], {relativeTo: this.activatedRoute});
}

然后我只需要订阅参数

this.activatedRoute.params.subscribe(params => this.getResource(params['resourceId']));

完整代码:

ngOnInit(): void {
    this.activatedRoute.params.subscribe(params => this.getResource(params['resourceId']));
    this.getResource(this.activatedRoute.snapshot.params?.resourceId);
}

resourceRequestEvent(resourceId: number) {
    // this will trigger the page refresh
    const url = this.router.url.split('my-path');
    if (url[1] && 0 < url[1].length) {
        this.router.navigate(['../' + resourceId], {relativeTo: this.activatedRoute});
    } else {
        this.router.navigate([resourceId], {relativeTo: this.activatedRoute});
    }
}

【讨论】:

    【解决方案5】:

    看你的问题,你想改变2个参数。

    如中所述:

    https://angular.io/api/router/Router#navigatebyurl

    你可以实现router.navigate([yourprojectId, 'users', youruserId , 'profile'], {relativeTo: route});

    【讨论】:

    • 我不知道什么是当前页面(/:projectId/info/:projectId/users 或任何其他页面)/我不知道当前页面的 URL 结构(它可能有任何其他附加帕拉姆)。我只知道它有参数:projectId,我想将:projectIdA 替换为B
    • 嗨@fedor.belov didi 你找到了解决方案,我有同样的功能要实现吗?你能帮我解决一下吗?
    【解决方案6】:

    使用 Angular 7,我通过使用在每个 NavigationEnd 上存储路由器当前状态的服务来实现这一点。然后我可以遍历状态树并构造一个路径数组,以后可以使用这些路径来查找和替换像:projectId 这样的参数。

    获取路径数组:

    constructor(private router: Router) {
        this.router.events.subscribe(event => {
            if (event instanceof NavigationEnd) {
                this.pathArray = this.getPathArray(this.router.routerState.snapshot.root);
            }
        }
    }
    
    getPathArray(route: ActivatedRouteSnapshot) {
        let array = [];
    
        if (route.routeConfig && route.routeConfig.path !== '') {
            array.push(route.routeConfig.path);
        }
    
        if (route.firstChild) {
            array = array.concat(this.getPathArray(route.firstChild));
        }
    
        return array;
    }
    

    替换:projectId

    replacePathArrayId(id) {
        return this.pathArray.map(path => {
            return path.replace(':projectId', id);
        })
    }
    

    并使用router.navigate(service.replacePathArrayId(id)) 实际更改路线。

    【讨论】:

      【解决方案7】:

      此服务将使用当前路由配置重建当前 url。它的工作原理是重建 url 段并将以:开头的段替换为参数中的匹配键

      要更新当前网址,您只需调用该方法

      this.routingService.updateRoute({id: 123})
      
      import { Injectable } from '@angular/core';
      import { ActivatedRoute, NavigationEnd, Params, Router } from '@angular/router';
      import { Subject } from 'rxjs';
      import { filter } from 'rxjs/operators';
      
      @Injectable({
        providedIn: 'root'
      })
      export class RoutingService {
        routeChange: Subject<void> = new Subject<void>();
        params: Params;
      
        constructor(
          private router: Router,
          private activatedRoute: ActivatedRoute
        ) {
          this.router.events
            .pipe(filter(event => event instanceof NavigationEnd))
            .subscribe(() => {
              this.params = this.activatedRoute.firstChild.snapshot.params;
              this.routeChange.next();
            });
        }
      
      
        updateRoute(data: { [key: string]: string | number }) {
          const params = { ... this.params, ...data };
          const segments = this.activatedRoute.firstChild.snapshot.routeConfig.path.split('/');
          const commands = segments.map(v => v.indexOf(':') === 0 ? params[v.substr(1)] : v);
          if (commands.join('/') !== this.activatedRoute.firstChild.snapshot.url.join()) {
            return this.router.navigate(commands);
          }
        }
      }
      

      【讨论】:

        【解决方案8】:

        这将获取一个 url 字符串并更新 params 对象中的所有参数:

        constructor(private route: ActivatedRoute, private router: Router){}
        
        setRouteParams(url: string, route: ActivatedRoute, params: any): string {
          for (const p in params)  {
            const old = route.snapshot.paramMap.get(p);
            url = url.replace(`/${old}/`, `/${params[p]}/`);
          }
          return url;
        }
        

        它遍历params 的属性,从当前路由中获取每个属性p 的当前值,然后将其替换为属性params[p] 的值。我们想知道当前的路由参数值,以便我们知道需要替换什么。匹配 /${old}/ 而不是 old 将避免像想在 /aad/aa/ 中用 /bb/ 替换 /aa/ 但得到 /bbd/aa/ 的情况。

        可以这样称呼setRouteParams('/project_id_1/users/user_id_1/profile', this.activatedRoute, {projectId: 'project_id_2')

        这不会处理像/11/users/11/profile/params {userId: '22'} 这样的路由。它将代替projectId。为了处理这种情况,我们需要知道参数{userId: {value: '22', position: 3}} 的顺序(基于位置,因为下面的第一段将是空字符串)。

        setRouteParams(url: string, params: any): string {
          const segments = url.split('/');
          for (const p in params)  {
            segments[params[p].position] = params[p].value;
          }
          return segments.join('/');
        }
        

        如果你想同时导航:

        setRouteParamsAndNavigate(router: Router, params: any): void {
          const segments = router.url.split('/');
          for (const p in params)  {
            segments[params[p].position] = params[p].value;
          }
          router.navigateByUrl(segments.join('/')).then(() => {});
        }
        

        【讨论】:

          【解决方案9】:

          为了让@khush 的回答更完整,并解决需要id 唯一的问题,我做了这个调整:

          id: string;
          
          constructor(private route: ActivatedRoute, private router: Router) {}
          
          ngOnInit() {
              this.route.params.subscribe(params => {
                  this.id = params['id'];    
              });
          }
          
          navigate() {
              this.router.navigateByUrl(this.router.url.replace(`/${this.id}/`, `/${newId}/`));
          }
          

          【讨论】:

            【解决方案10】:

            这会有帮助吗?

            export class MyComponent {
            
              constructor(private router: Router, private route: ActivatedRoute){}
            
              public navigate(){
                const projectId = getNewProjectId(route.snapshot.params['projectId']);
                this.router.navigate([
                  projectId, 
                  this.router.url.substring(this.router.url.indexOf('/') + 1, this.router.url.length)
                ]);
              }
            }
            

            如果您需要更精细的控制(基本上,您不知道当前 URL 应该是什么样子),请尝试遍历路由树,处理路由配置路径。您可以在其中找到:projectId 配置,并且根据您在树中的位置,您可以了解您的router.url 结构。

            let route = activatedRoute.snapshot;
            while (route) {
              if (route.routeConfig && route.routeConfig.path) {
                // Do something with the path
              }
              route = route.parent;
            }
            

            希望这会有所帮助:-)

            【讨论】:

              【解决方案11】:

              在相应的组件中(即.ts文件)你需要添加

              import { Subscription } from 'rxjs/Subscription';
              

              Uder 进入你的@component 使用以下

              myVariable: {projectId: string, userId: string};
              paramsSubscription: Subscription;
              
              
              ngOnInit(){
              this.myVariable = {
                 projectId: this.route.snapshot.params['projectId'],
               // userId: this.route.snapshot.params['userId']
              };
              this.paramsSubscription = this.route.params
                .subscribe(
                  (params: Params) => {
                    this.myVariable.projectId = params['projectId'];
                  //  this.myVariable.userId = params['userId'];
                  }
                );
              }
              

              以及您有兴趣更改现有路线的方法。假设您想从以下方法更改路线

              changeRoute(): void{
                 this.router.navigate(['/curentUrl',this.project_id_2, 'users/user_id_1/profile']);
              }
              

              希望对你有帮助

              【讨论】:

                【解决方案12】:

                由于我也花了几个小时研究这个问题,所以我也想分享我的解决方案。

                我向应该能够在 accountNames(在您的情况下为 projectIds)之间切换的路由添加了一个自定义数据项:

                const routes: Routes = [
                 {
                   path: 'expenses/:accountName',
                   component: ExpenseListComponent,
                   data: { changeAccountUrl: ['expenses', ':accountName'] },
                 }
                ];
                

                这样任何组件都可以很容易地检查激活路由的数据是否存在该项目。如果存在,您可以使用它生成路由。

                另一个好处是您可以更好地控制生成的路线。

                【讨论】:

                  【解决方案13】:

                  这是您可以做到的一种方式。获取 url,获取当前参数(因为听起来您不知道它们是什么),如果您同时拥有 projectid 和 userid,那么您将路由到同时具有两者的那个。如果 url 以'o' 结尾,那么你在/info 路由上,如果它以's' 结尾,那么它就是/users 路由。

                  constructor(private activatedRoute: ActivatedRoute) {}
                  
                  replacePrarm(projectId) {
                    // get current url
                    const url = this.router.url;
                  
                    // get current params
                    this.activatedRoute.params.subscribe((params: Params) => {
                         if(params['projectId'] && params['userId']) {
                            router.navigate(projectId, 'users', params['userId'], 'profile'], {relativeTo: route});
                         } else if (url[url.length - 1] === 'o') {
                            router.navigate(projectId, 'info'], {relativeTo: route});
                         } else if (url[url.length - 1] === 's') {
                            router.navigate(projectId, 'users'], {relativeTo: route});
                         }
                    });
                  }
                  

                  这是假设您不知道自己在哪条路线上,但实际上您应该知道您是在用户、信息还是个人资料中。否则,您将在三个非常不同的页面上使用一个组件。

                  【讨论】:

                    猜你喜欢
                    • 2018-11-28
                    • 2015-11-03
                    • 2018-05-17
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-03-20
                    • 2021-11-12
                    • 1970-01-01
                    相关资源
                    最近更新 更多