Angular: Cómo actualizar queryParams sin cambiar la ruta

125

Estoy tratando de actualizar (agregar, eliminar) queryParams de un componente. En angularJS, solía ser posible gracias a:

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

Tengo una aplicación con una lista que el usuario puede filtrar, ordenar, etc. y me gustaría configurar en los queryParams de la url todos los filtros activados para que pueda copiar / pegar la url o compartirla con otra persona.

Sin embargo, no quiero que mi página se vuelva a cargar cada vez que se selecciona un filtro.

¿Es esto posible con el nuevo enrutador?

Olivier
fuente

Respuestas:

271

Puede navegar a la ruta actual con nuevos parámetros de consulta, que no volverán a cargar su página, pero actualizarán los parámetros de consulta.

Algo como (en el 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
    });
}

Tenga en cuenta que, si bien no volverá a cargar la página, enviará una nueva entrada al historial del navegador. Si desea reemplazarlo en el historial en lugar de agregar un nuevo valor allí, puede usar { queryParams: queryParams, replaceUrl: true }.

EDITAR: Como ya se señaló en los comentarios, []y la relativeTopropiedad faltaba en mi ejemplo original, por lo que también podría haber cambiado la ruta, no solo los parámetros de consulta. El this.router.navigateuso adecuado será en este caso:

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

Establecer el nuevo valor del parámetro en nulleliminará el parámetro de la URL.

Radosław Roszkowiak
fuente
30
Tuve que usar en []lugar de ['.']hacerlo funcionar
Jaime Gómez
5
Necesita utilizar queryParams ['relatedTo'] = this.activatedRoute; para que la navegación sea relativa a la página actual
klonq
3
Buena solución para resolver el problema del OP. Lo que no obtiene, a menos que me falte algo, es la capacidad de retroceder y avanzar en el historial de la página actual (por ejemplo, cambiar el filtro o realizar el pedido 5 veces, cada una con su propia URL pero el mismo componente) y tener la El contenido de la página aparece como si accediera directamente a esas 5 URL. Creo que podría lograr esto manualmente a través de this.activatedRoute.queryParams.subscribey hacer varias actualizaciones en su componente, pero ¿existe una forma angular simple de cargar la ruta de manera que el avance y el retroceso funcionen automáticamente?
jmq
1
al usar router.navigate, se desplazará hacia la parte superior de la ventana, ¿alguna idea de cómo deshabilitar esto?
Hese
1
@Hese, ¿estás seguro? No creo que se desplace hacia la parte superior. Eche un vistazo a este ejemplo: stackblitz.com/edit/angular-sdtsew?file=src/app/…
Radosław Roszkowiak
23

La respuesta de @ Radosław Roszkowiak es casi correcta, excepto que relativeTo: this.routese requiere como se muestra a continuación:

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

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

En Angular 5, puede obtener y modificar fácilmente una copia de urlTree analizando la url actual. Esto incluirá parámetros de consulta y fragmentos.

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

  this.router.navigateByUrl(urlTree); 

La "forma correcta" de modificar un parámetro de consulta es probablemente con createUrlTree, como se muestra a continuación, que crea un nuevo UrlTree a partir del actual y nos permite modificarlo mediante 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 eliminar un parámetro de consulta de esta manera, puede establecerlo en undefinedo null.

bjornalm
fuente
2
navigateByUrles diferente a navigate, no solo con el parámetro UrlTree. Ver stackoverflow.com/a/45025432/271012
Drenai
9

Tratar

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

funcionará para la navegación por la misma ruta que no sean comillas simples.

Prudhvi Raj
fuente
Estaba buscando exactamente esto. ¡¡¡Gracias!!!
cevaris
7

La respuesta con más votos me funcionó parcialmente. La URL del navegador se mantuvo igual, pero mi routerLinkActiveya no funcionaba después de la navegación.

Mi solución fue 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());
  }
}

Usé HttpParams para construir la cadena de consulta ya que ya la estaba usando para enviar información con httpClient. pero puedes construirlo tú mismo.

y el this._router.url.split("?")[0], es eliminar toda la cadena de consulta anterior de la URL actual.

moi_meme
fuente
4
Esta DEBERÍA ser la respuesta aceptada, el router.navigates también actualiza el ngOnit, ¡location.go NO hace esto! Esto es realmente importante porque si su componente tiene alguna lógica ngOnit (llamadas HTTP, etc.), se volverá a llamar cuando use router.navigate. No quieres esto.
Danny Hoeve
¿Por qué necesita un enrutador, solo para la URL? ¿No es this.location.path().split...mejor?
Vladimir
@Vladimir, puede que tenga razón, lo estaba usando para otro propósito en mi componente, así que no fue solo para eso. Sin embargo, no tengo tiempo para validar.
moi_meme
Esto no funcionará si desea conservar los parámetros de consulta, por ejemplo, promoción o parámetros de seguimiento de Google
Jon Tinsman
5

Terminé combinándome urlTreeconlocation.go

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

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

No estoy seguro si toStringpuede causar problemas, pero desafortunadamente location.go, parece estar basado en cadenas.

Razze
fuente
4

Si desea cambiar los parámetros de consulta sin cambiar la ruta. Vea el ejemplo a continuación que podría ayudarlo: la ruta actual es: / búsqueda y la ruta de destino es (sin página de recarga): / search? query = love

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

tenga en cuenta: puede utilizar this.router.navigate (['buscar'] en lugar de this.router.navigate (['.']

Azeem Chauhan
fuente
No estoy seguro de que [.] Sea un enfoque mejor que relativeTo:, pero .then()fue útil: no sabía que navigate () devolvió una promesa, ¡me alegro de que haya publicado!
Drenai
0

Primero, necesitamos importar el módulo del enrutador desde el enrutador angular y declarar su nombre de alias

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

1. Puede cambiar los parámetros de consulta mediante la función "router.navigate" y pasar los parámetros de consulta

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

Actualizará los parámetros de consulta en la ruta activada actual

  1. Lo siguiente redirigirá a la página abc con _id, día y nombre como parámetros de consulta

    this.router.navigate (['/ abc'], {queryParams: {_id: "abc", día: "1", nombre: "dfd"}});

    Actualizará los parámetros de consulta en la ruta "abc" junto con tres parámetros de consulta

Para obtener 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
fuente