Angular:如何在不更改路由的情况下更新queryParams


124

我正在尝试从组件更新(添加,删除)queryParams。在angularJS中,由于以下原因,它曾经可以实现:

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

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

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

这对新路由器可行吗?

Answers:


269

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

类似于(在组件中):

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 }

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

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

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


30
我不得不使用[]而不是['.']使其起作用
JaimeGómez17年

5
需要使用queryParams ['relativeTo'] = this.activatedRoute; 使导航相对于当前页面
klonq '18

3
解决OP问题的不错的解决方案。除非我丢失了某些内容,否则您无法获得的是能够在您当前页面的历史记录中前进和后退(例如,更改过滤器或顺序5次,每次都有自己的URL,但组件相同),并且能够页面内容的显示方式与直接访问这5个URL时的显示方式相同。我认为您可以通过手动完成此操作this.activatedRoute.queryParams.subscribe并在组件中进行各种更新,但是有没有一种简单的Angular方式可以仅加载路线以使前进和后退自动进行?
jmq

1
当使用router.navigate时,它将在窗口顶部滚动,有什么想法如何禁用此功能?
Hese

1
@Hese,您确定吗?我认为它不会滚动到顶部。请看以下示例:stackblitz.com/edit/angular-sdtsew?file=src
app / ... –RadosławRoszkowiak

23

@RadosławRoszkowiak的答案几乎是正确的,除了relativeTo: this.route以下要求:

constructor(
  private router: Router,
  private route: ActivatedRoute,
) {}

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

14

在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


2
navigateByUrlnavigate-不仅仅与UrlTree参数有关。请参阅stackoverflow.com/a/45025432/271012
Drenai,


7

大多数投票的答案部分对我有用。浏览器的网址保持不变,但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中删除所有先前的查询字符串。


4
这应该是可接受的答案,router.navigation也刷新ngOnit,location.go不这样做!这真的很重要,因为如果您的组件执行某些ngOnit逻辑(HTTP调用等),则在使用router.navigate时会再次调用它们。你不要这个
丹尼·霍夫,

为什么需要路由器,仅用于URL?this.location.path().split...好不好
弗拉基米尔(Vladimir)

@Vladimir,您可能是对的,我在组件中将其用于其他目的,所以它不仅用于此目的。我没有时间来验证。
moi_meme

如果您想保留查询参数(例如促销或Google跟踪参数),则此方法将无效
Jon Tinsman

5

我最终urlTreelocation.go

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

    this.location.go(urlTree.toString());

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


4

如果要更改查询参数而不更改路由。参见下面的示例可能对您有所帮助:当前路径为:/ 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()很有帮助-并不知道Navigation()返回了诺言,很高兴您发布!
德雷奈

0

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

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和name作为查询参数重定向到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
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.