Angular: как обновить queryParams без изменения маршрута


128

Я пытаюсь обновить (добавить, удалить) queryParams из компонента. В angularJS это было возможно благодаря:

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

У меня есть приложение со списком, который пользователь может фильтровать, заказывать и т. Д., И я хотел бы установить в queryParams URL-адреса все активированные фильтры, чтобы он мог скопировать / вставить URL-адрес или поделиться им с кем-то другим.

Однако я не хочу, чтобы моя страница перезагружалась каждый раз при выборе фильтра.

Возможно ли это с новым маршрутизатором?

Ответы:


274

Вы можете перейти к текущему маршруту с новыми параметрами запроса, которые не будут перезагружать вашу страницу, но будут обновлять параметры запроса.

Что-то вроде (в компоненте):

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
Мне пришлось использовать []вместо того, ['.']чтобы заставить его работать
Хайме Гомес

5
Необходимо использовать queryParams ['relativeTo'] = this.activatedRoute; чтобы сделать навигацию относительно текущей страницы
klonq 01

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/…
Радослав Рошковяк

23

@ Radosław Roszkowiak ответ почти правильный, за исключением того, что relativeTo: this.routeтребуется, как показано ниже:

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

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

14

В Angular 5 вы можете легко получить и изменить копию urlTree, проанализировав текущий URL. Это будет включать параметры и фрагменты запроса.

  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); 
}

Чтобы удалить параметр запроса таким образом, вы можете установить для него значение undefinedили null.


2
navigateByUrlотличается navigate- не только с параметром UrlTree. См stackoverflow.com/a/45025432/271012
Drenai

9

Пытаться

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

будет работать для навигации по тому же маршруту, кроме одинарных кавычек.


Я искал именно эту вещь. Спасибо!!!
cevaris

7

Ответ с наибольшим количеством голосов частично сработал для меня. 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.


4
Это ДОЛЖЕН быть принятым ответом, router.navigates также обновляет ngOnit, location.go этого НЕ делает! Это действительно важно, потому что если ваш компонент выполняет некоторую логику ngOnit (HTTP-вызовы и т. Д.), Они будут вызываться снова, когда вы используете router.navigate. Вы этого не хотите.
Дэнни

Зачем нужен роутер, только для url? Не this.location.path().split...лучше?
Владимир

@Vladimir, возможно, вы правы, я использовал его для других целей в своем компоненте, так что это было не только для этого. Но у меня нет времени проверять.
moi_meme

Это не сработает, если вы хотите сохранить параметры запроса, например параметры продвижения или отслеживания Google,
Джон Тинсман,

6

В итоге я объединился urlTreeсlocation.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()был полезен - не знал, что navigate () вернул обещание, так что рад, что вы опубликовали!
Дренай 03

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. Ниже приведено перенаправление на страницу abc с _id, днем ​​и именем в качестве параметров запроса.

    this.router.navigate (['/ abc'], {queryParams: {_id: "abc", день: "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
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.