【问题标题】:Angular: How to update queryParams without changing routeAngular:如何在不更改路线的情况下更新 queryParams
【发布时间】:2017-09-27 14:59:31
【问题描述】:

我正在尝试从组件中更新(添加、删除)queryParams。在 angularJS 中,它曾经是可能的,这要归功于:

$location.search('f', 'filters[]'); // setter
$location.search()['filters[]'];    // getter

我有一个应用程序,其中包含用户可以过滤、订购等的列表,我想在 url 的 queryParams 中设置所有激活的过滤器,以便他可以复制/粘贴 url 或与其他人共享。

但是,我不希望每次选择过滤器时都重新加载我的页面

新路由器可以做到这一点吗?

【问题讨论】:

    标签: angular query-parameters angular-router


    【解决方案1】:

    您可以使用新的查询参数导航到当前路线,这不会重新加载您的页面,但会更新查询参数。

    类似的东西(在组件中):

    constructor(private router: Router) { }
    
    public myMethodChangingQueryParams() {
      const queryParams: Params = { myParam: 'myNewValue' };
    
      this.router.navigate(
        [], 
        {
          relativeTo: activatedRoute,
          queryParams: queryParams, 
          queryParamsHandling: 'merge', // remove to replace all query params by provided
        });
    }
    

    请注意,虽然它不会重新加载页面,但它会将新条目推送到浏览器的历史记录中。如果您想在历史记录中替换它而不是在那里添加新值,您可以使用{ queryParams: queryParams, replaceUrl: true }

    编辑: 正如 cmets 中已经指出的那样,[]relativeTo 属性在我的原始示例中丢失了,因此它也可能更改了路由,而不仅仅是查询参数。在这种情况下,正确的 this.router.navigate 用法将是:

    this.router.navigate(
      [], 
      {
        relativeTo: this.activatedRoute,
        queryParams: { myParam: 'myNewValue' },
        queryParamsHandling: 'merge'
      });
    

    将新参数值设置为 null 将从 URL 中删除参数。

    【讨论】:

    • 我必须使用 [] 而不是 ['.'] 才能使其工作
    • 需要使用queryParams['relativeTo'] = this.activatedRoute;使导航相对于当前页面
    • 解决 OP 问题的好方法。除非我遗漏了什么,否则它无法让您在当前页面的历史记录中前后移动(例如,更改过滤器或订购 5 次,每个都有自己的 URL 但相同的组件)并拥有如果您直接访问这 5 个 URL,页面的内容会如何显示。我认为您可以通过this.activatedRoute.queryParams.subscribe 手动完成此操作并在您的组件中进行各种更新,但是是否有一种简单的 Angular 方法来加载路由,以便自动前后工作?
    • 这实际上会破坏组件并在每次更改 url 参数时调用 ngOnit()。有没有办法避免调用 ngOnit() ?
    • 在使用 router.navigate 时,它​​会滚动窗口顶部,有什么办法可以禁用它吗?
    【解决方案2】:

    @Radosław Roszkowiak 的答案几乎是正确的,除了relativeTo: this.route 是必需的,如下所示:

    constructor(
        private router: Router,
        private route: ActivatedRoute,
    ) {}
    
    changeQuery() {
        this.router.navigate(['.'], { relativeTo: this.route, queryParams: { ... }});
    }
    

    【讨论】:

      【解决方案3】:

      在 Angular 5 中,您可以通过解析当前 url 轻松获取和修改 urlTree 的副本。这将包括查询参数和片段。

        let urlTree = this.router.parseUrl(this.router.url);
        urlTree.queryParams['newParamKey'] = 'newValue';
      
        this.router.navigateByUrl(urlTree); 
      

      修改查询参数的“正确方法”可能是 createUrlTree 如下所示,它从当前创建一个新的 UrlTree,同时让我们使用 NavigationExtras 对其进行修改。

      import { Router } from '@angular/router';
      
      constructor(private router: Router) { }
      
      appendAQueryParam() {
      
        const urlTree = this.router.createUrlTree([], {
          queryParams: { newParamKey: 'newValue' },
          queryParamsHandling: "merge",
          preserveFragment: true });
      
        this.router.navigateByUrl(urlTree); 
      }
      

      要以这种方式删除查询参数,您可以将其设置为undefinednull

      【讨论】:

      【解决方案4】:

      投票最多的答案部分对我有用。浏览器 url 保持不变,但我的 routerLinkActive 在导航后不再工作。

      我的解决方案是使用 lotation.go:

      import { Component } from "@angular/core";
      import { Location } from "@angular/common";
      import { HttpParams } from "@angular/common/http";
      
      export class whateverComponent {
        constructor(private readonly location: Location, private readonly router: Router) {}
      
        addQueryString() {
          const params = new HttpParams();
          params.append("param1", "value1");
          params.append("param2", "value2");
          this.location.go(this.router.url.split("?")[0], params.toString());
        }
      }
      

      我使用 HttpParams 来构建查询字符串,因为我已经使用它通过 httpClient 发送信息。但你可以自己构建它。

      this._router.url.split("?")[0],是从当前url中删除所有以前的查询字符串。

      【讨论】:

      • 这应该是公认的答案,router.navigates 也会刷新 ngOnit,location.go 不会这样做!这非常重要,因为如果您的组件执行一些 ngOnit 逻辑(HTTP 调用等),它们将在您使用 router.navigate 时再次被调用。你不想要这个。
      • 为什么需要路由器,只用于 url? this.location.path().split... 不是更好吗?
      • @Vladimir 你可能是对的,我在我的组件中将它用于其他目的,所以不仅仅是为了那个。不过我没时间验证。
      • 如果您想保留查询参数,例如促销或谷歌跟踪参数,这将不起作用
      • 这是唯一对我有用的答案,而且实际上是有道理的。
      【解决方案5】:

      试试

      this.router.navigate([], { 
        queryParams: {
          query: value
        }
      });
      

      将适用于除单引号之外的相同路线导航。

      【讨论】:

        【解决方案6】:

        如果您想更改查询参数而不更改路由。见下文 示例可能会帮助您: 当前路线是:/search & 目标路线是(没有重新加载页面):/search?query=love

            submit(value: string) {
              this.router.navigate( ['.'],  { queryParams: { query: value } })
                .then(_ => this.search(q));
            }
            search(keyword:any) { 
            //do some activity using }
        

        请注意:您可以使用this.router.navigate( ['search'] 代替this.router.navigate( ['.']

        【讨论】:

        • 我不确定 [.] 是不是比 relativeTo: 更好的方法,但 .then() 很有帮助 - 不知道 navigate() 返回了一个承诺,很高兴你发布了!
        • 不用['.']或['search'],我们可以简单地使用[]
        【解决方案7】:

        我最终将urlTreelocation.go 结合在一起

        const urlTree = this.router.createUrlTree([], {
               relativeTo: this.route,
               queryParams: {
                   newParam: myNewParam,
               },
               queryParamsHandling: 'merge',
            });
        
            this.location.go(urlTree.toString());
        

        不确定toString 是否会导致问题,但不幸的是location.go 似乎是基于字符串的。

        【讨论】:

        • 这不会触发对queryParamMap observable的观察者的更新
        【解决方案8】:

        更好 - 只是 HTML:

        <a [routerLink]="[]" [queryParams]="{key: 'value'}">Your Query Params Link</a>

        注意空数组,而不是只做routerLink=""[routerLink]="''"

        【讨论】:

        • 为什么是空数组? [routerLink]="" 有效。
        【解决方案9】:

        首先,我们需要从 Angular 路由器中导入路由器模块并声明其别名

        import { Router } from '@angular/router'; ---> import
        class AbcComponent implements OnInit(){
        constructor(
            private router: Router ---> decalre alias name
          ) { }
        }
        

        1。您可以使用“router.navigate”函数更改查询参数并传递查询参数

        this.router.navigate([], { queryParams: {_id: "abc", day: "1", name: "dfd"} 
        });
        

        它将更新当前即激活路由中的查询参数

        1. 下面将重定向到带有_id,day的abc页面 并命名为查询参数

          this.router.navigate(['/abc'], { queryParams: {_id: "abc", day: "1", name: “dfd”} });

          它将更新“abc”路由中的查询参数以及三个查询参数

        获取查询参数:-

            import { ActivatedRoute } from '@angular/router'; //import activated routed
        
            export class ABC implements OnInit {
        
            constructor(
                private route: ActivatedRoute //declare its alias name
              ) {}
        
            ngOnInit(){
               console.log(this.route.snapshot.queryParamMap.get('_id')); //this will fetch the query params
            }
        

        【讨论】:

          【解决方案10】:

          Angular 的定位服务应该在与浏览器的 URL 交互时使用,而不是用于路由。这就是为什么我们要使用Location 服务。

          Angulars HttpParams 用于创建查询参数。请记住 HttpParam 是不可变的,这意味着在创建值时必须将其链接起来。

          最后,使用this._location.replaceState更改为URL而不重新加载页面/路由和原生js location.path获取不带参数的url每次重置参数。

          constructor(
              private _location: Location,
          ) {}
          
          ...
          
          updateURLWithNewParamsWithoutReloading() {
              const params = new HttpParams().appendAll({
                  price: 100,
                  product: 'bag'
              });
          
              this._location.replaceState(
                  location.pathname,
                  params.toString()
              );
          }
          

          【讨论】:

            猜你喜欢
            • 2019-10-14
            • 1970-01-01
            • 2018-01-14
            • 1970-01-01
            • 2010-09-17
            • 1970-01-01
            • 1970-01-01
            • 2021-01-10
            • 1970-01-01
            相关资源
            最近更新 更多