Angular: como atualizar queryParams sem alterar a rota

125

Estou tentando atualizar (adicionar, remover) queryParams de um componente. No angularJS, isso era possível graças a:

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

Tenho um aplicativo com uma lista que o usuário pode filtrar, ordenar, etc e gostaria de colocar nos queryParams da url todos os filtros ativados para que ele possa copiar / colar a url ou compartilhá-la com outra pessoa.

No entanto, não quero que minha página seja recarregada sempre que um filtro for selecionado.

Isso é possível com o novo roteador?

Olivier
fonte

Respostas:

270

Você pode navegar para a rota atual com novos parâmetros de consulta, que não irão recarregar sua página, mas irão atualizar os parâmetros de consulta.

Algo como (no componente):

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

Observe que, embora não recarregue a página, ele enviará uma nova entrada ao histórico do navegador. Se quiser substituí-lo no histórico em vez de adicionar um novo valor lá, você pode usar { queryParams: queryParams, replaceUrl: true }.

EDIT: Como já foi apontado nos comentários, []e a relativeTopropriedade estava faltando no meu exemplo original, então poderia ter mudado a rota também, não apenas parâmetros de consulta. O this.router.navigateuso adequado será neste caso:

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

Definir o novo valor do parâmetro como nullremoverá o parâmetro do URL.

Radosław Roszkowiak
fonte
30
Tive que usar em []vez de ['.']fazer funcionar
Jaime Gómez
5
É necessário usar queryParams ['relativeTo'] = this.activatedRoute; para fazer a navegação relativa à página atual
klonq 01 de
3
Boa solução para resolver o problema do OP. O que isso não significa, a menos que esteja faltando alguma coisa, é a capacidade de voltar e avançar em seu histórico da página atual (por exemplo, filtro alterado ou pedido 5 vezes, cada um tendo seu próprio URL, mas o mesmo componente) e ter o o conteúdo da página aparece como se você acessasse esses 5 URLs diretamente. Eu acho que você poderia fazer isso manualmente por meio de this.activatedRoute.queryParams.subscribee fazer várias atualizações em seu componente, mas existe uma maneira simples de Angular carregar a rota de forma que o avanço e a retrocesso funcionem automaticamente?
jmq
1
ao usar router.navigate ele vai rolar o topo da janela, alguma ideia de como desabilitar isso?
Hese
1
@Hese, tem certeza? Eu não acho que vai rolar para o topo. Por favor, dê uma olhada neste exemplo: stackblitz.com/edit/angular-sdtsew?file=src/app/…
Radosław Roszkowiak
23

A resposta de @Radosław Roszkowiak está quase certa, exceto que relativeTo: this.routeé exigida conforme abaixo:

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

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

No Angular 5, você pode obter e modificar facilmente uma cópia do urlTree analisando o url atual. Isso incluirá parâmetros de consulta e fragmentos.

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

  this.router.navigateByUrl(urlTree); 

A "maneira correta" de modificar um parâmetro de consulta é provavelmente com o createUrlTree como abaixo, que cria um novo UrlTree a partir do atual enquanto nos permite modificá-lo usando 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); 
}

Para remover um parâmetro de consulta dessa forma, você pode defini-lo como undefinedou null.

bjornalm
fonte
2
navigateByUrlé diferente navigate- não apenas com o parâmetro UrlTree. Consulte stackoverflow.com/a/45025432/271012
Drenai de
9

Experimentar

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

funcionará para a mesma navegação de rota, exceto aspas simples.

Prudhvi Raj
fonte
Eu estava procurando exatamente por isso. Obrigado!!!
cevaris
7

A resposta com mais votos parcialmente funcionou para mim. O URL do navegador permaneceu o mesmo, mas meurouterLinkActive não estava mais funcionando após a navegação.

Minha solução foi usar 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());
  }
}

Usei HttpParams para construir a string de consulta, pois já o estava usando para enviar informações com httpClient. mas você mesmo pode construí-lo.

e this._router.url.split("?")[0], é remover todas as strings de consulta anteriores do url atual.

moi_meme
fonte
4
Essa DEVE ser a resposta aceita, o router.navigates também atualiza o ngOnit, location.go NÃO faz isso! Isso é realmente importante porque se o seu componente fizer alguma lógica ngOnit (chamadas HTTP etc.), eles serão chamados novamente quando você usar o router.navigate. Você não quer isso.
Danny Hoeve
Por que você precisa de um roteador, apenas para url? Não é this.location.path().split...melhor?
Vladimir de
@Vladimir pode ter razão, eu estava usando para outro propósito no meu componente, então não era só para isso. Mas não tenho tempo para validar.
moi_meme
Isso não funcionará se você quiser preservar os parâmetros de consulta, por exemplo, promoção ou parâmetros de rastreamento do Google
Jon Tinsman
5

Acabei combinando urlTreecomlocation.go

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

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

Não tenho certeza se toStringpode causar problemas, mas location.go, infelizmente , parece ser baseado em string.

Razze
fonte
4

Se você deseja alterar os parâmetros de consulta sem alterar a rota. veja o exemplo abaixo pode ajudá-lo: a rota atual é: / search & A rota de destino é (sem recarregar a página): / search? query = love

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

observação: você pode usar this.router.navigate (['pesquisar'] em vez de this.router.navigate (['.']

Azeem Chauhan
fonte
Não tenho certeza se [.] É uma abordagem melhor do que relativeTo:, mas .then()foi útil - não sabia que navegar () retornou uma promessa, que bom que você postou!
Drenai
0

Primeiro, precisamos importar o módulo do roteador do roteador angular e declarar seu nome de alias

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

1. Você pode alterar os parâmetros de consulta usando a função "router.navigate" e passar os parâmetros de consulta

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

Irá atualizar os parâmetros de consulta na rota atual, ou seja, ativada

  1. O abaixo irá redirecionar para a página abc com _id, dia e nome como parâmetros de consulta

    this.router.navigate (['/ abc'], {queryParams: {_id: "abc", dia: "1", nome: "dfd"}});

    Ele irá atualizar os parâmetros de consulta na rota "abc" junto com três parâmetros de consulta

Para buscar parâmetros de consulta: -

    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
    }
VIKAS KOHLI
fonte