Cambiar parámetros de ruta sin recargar en Angular 2

114

Estoy creando un sitio web de bienes raíces usando Angular 2, Google Maps, etc. y cuando un usuario cambia el centro del mapa, realizo una búsqueda en la API que indica la posición actual del mapa y el radio. La cosa es que quiero reflejar esos valores en la URL sin recargar toda la página. ¿Es eso posible? Encontré algunas soluciones usando AngularJS 1.x pero nada sobre Angular 2.

Marcos Basualdo
fuente
Creo que si usas [routerLink] = "['/ route', {param1: value1}], no se recargará la página
Kit de herramientas
pero ¿cómo puedo agregar otro parámetro de consulta?
Kit de herramientas
2
☝️ causará una recarga de la página
LifterCoder
Solo tenga en cuenta que si usa SSR para hacer que su sitio sea compatible con SEO, este es un problema discutible.
Jonathan
@Jonathan, ¿verdad? Dado que Angular se hace cargo del enrutamiento una vez que se renderiza la página estática, creo que sigue siendo una pregunta válida incluso cuando se usa SSR.
adam0101

Respuestas:

92

Puede usar location.go(url)lo que básicamente cambiará su URL, sin cambios en la ruta de aplicación.

TENGA EN CUENTA que esto podría causar otro efecto como la redirección a la ruta secundaria desde la ruta actual.

La pregunta relacionada que describelocation.gono indicaráRouterque ocurran cambios.

Pankaj Parkar
fuente
2
Mi ruta tiene un parámetro llamado 'búsqueda' en el que recibo una versión serializada de los campos de búsqueda, cuando el estado de la lista se carga por primera vez, solo leo esos parámetros usando this._routeParams.get ('buscar'), deserializa los filtros y realizar la búsqueda. Si el usuario cambia los campos de búsqueda, ya sea usando el mapa o las facetas de búsqueda, simplemente construyo la URL correcta usando el método generate del router var instrucción = this._router.generate (['Listing', {search: serializedFields}] ) y luego usando this._location.go (instrucción.urlPath) para alterar la URL sin recargar el estado.
Marcos Basualdo
20
Si alguien más se pregunta: importe {Ubicación} desde 'angular2 / plataforma / común';
Kesarion
18
import { Location } from '@angular/common';en Angular 4
tehCivilian
2
¿Te gusta constructr?constructor(private location: Location){ }
Pankaj Parkar
2
@AdrianE, lo más probable es que el problema sea que usted escribió location.go()mientras debería haberlo hecho this.location.go(). Cuando emite el this., llama a la interfaz de ubicación de Typecript.
georg-un
94

A partir de RC6, puede hacer lo siguiente para cambiar la URL sin cambiar el estado y, por lo tanto, mantener el historial de su ruta

    import {OnInit} from '@angular/core';

    import {Location} from '@angular/common'; 
    // If you dont import this angular will import the wrong "Location"

    @Component({
        selector: 'example-component',
        templateUrl: 'xxx.html'
    })
    export class ExampleComponent implements OnInit {
        
        constructor( private location: Location )
        {}

        ngOnInit() {    
            this.location.replaceState("/some/newstate/");
        }
    }
tjuzbumz
fuente
Esto no me funciona. Sitll intenta cargar la ruta. Error de consola:Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'some/newstate'
Iñigo
2
Combine esto con la creación de URL como lo sugiere @golfadas y ¡tenemos un ganador!
crowmagnumb
63

Usar location.go(url)es el camino a seguir, pero en lugar de codificar la URL, considere generarla usando router.createUrlTree().

Dado que desea realizar la siguiente llamada al enrutador: this.router.navigate([{param: 1}], {relativeTo: this.activatedRoute})pero sin recargar el componente, se puede reescribir como:

const url = this.router.createUrlTree([], {relativeTo: this.activatedRoute, queryParams: {param: 1}}).toString()

 this.location.go(url);
golfadas
fuente
9
Esta respuesta resolvió mi problema. Una pregunta, la URL generada anteriormente tiene parámetros delimitados por ";" (punto y coma). ¿Qué debemos hacer para separar cada parámetro de la consulta con "&"?
Amarnath
2
esta es la declaración de createUrlTree (comandos: any [], navigationExtras ?: NavigationExtras). tienes que usar queryParams ubicadas navigationExtras no comas. createUrlTree ([], {relatedTo: this.activatedRoute, queryParams: {param: 1}})
kit
solo para aclarar lo que dijo @kit, haga esto:this.router.createUrlTree([], {relativeTo: this.activatedRoute, queryParams: {param: 1}}).toString()
bluegrounds
12

Para cualquier persona como yo que encuentre esta pregunta, la siguiente puede ser útil.

Tuve un problema similar e inicialmente intenté usar location.go y location.replaceState como se sugiere en otras respuestas aquí. Sin embargo, tuve problemas cuando tuve que navegar a otra página en la aplicación porque la navegación era relativa a la ruta actual y la ruta actual no estaba siendo actualizada por location.go o location.replaceState (el enrutador no sabe nada sobre lo que le hacen a la URL)

En esencia, necesitaba una solución que NO recargara la página / componente cuando cambiaba el parámetro de ruta, pero sí actualizaba el estado de la ruta internamente.

Terminé usando parámetros de consulta. Puede encontrar más información al respecto aquí: https://angular-2-training-book.rangle.io/handout/routing/query_params.html

Entonces, si necesita hacer algo como guardar un pedido y obtener un ID de pedido, puede actualizar la URL de su página como se muestra a continuación. Actualizar la ubicación de un centro y los datos relacionados en un mapa sería similar

// let's say we're saving an order. Initally the URL is just blah/orders
save(orderId) {
    // [Here we would call back-end to save the order in the database]

    this.router.navigate(['orders'], { queryParams: { id: orderId } });
    // now the URL is blah/orders?id:1234. We don't reload the orders
    // page or component so get desired behaviour of not seeing any 
    // flickers or resetting the page.
}

y lo rastrea dentro del método ngOnInit como:

ngOnInit() {
    this.orderId = this.route
        .queryParamMap
        .map(params => params.get('id') || null);
    // orderID is up-to-date with what is saved in database now, or if
    // nothing is saved and hence no id query paramter the orderId variable
    // is simply null.
    // [You can load the order here from its ID if this suits your design]
}

Si necesita ir directamente a la página del pedido con un pedido nuevo (no guardado), puede hacer lo siguiente:

this.router.navigate(['orders']);

O si necesita ir directamente a la página de pedidos de un pedido existente (guardado), puede hacer lo siguiente:

this.router.navigate(['orders'], { queryParams: { id: '1234' } });
TornadoAli
fuente
10

Tuve grandes problemas para que esto funcionara en las versiones RCx de angular2. El paquete Location se ha movido y la ejecución de location.go () dentro de constructor () no funcionará. Debe ser ngOnInit () o más adelante en el ciclo de vida. Aquí hay un código de ejemplo:

import {OnInit} from '@angular/core';
import {Location} from '@angular/common';

@Component({
  selector: 'example-component',
  templateUrl: 'xxx.html'
})
export class ExampleComponent implements OnInit
{
  constructor( private location: Location )
  {}

  ngOnInit()
  {    
    this.location.go( '/example;example_param=917' );
  }
}

Aquí están los recursos angulares al respecto: https://angular.io/docs/ts/latest/api/common/index/Location-class.html https://angular.io/docs/ts/latest/api/ common / index / LocationStrategy-class.html

Luke Dupin
fuente
7

Yo uso esta forma para conseguirlo:

const queryParamsObj = {foo: 1, bar: 2, andThis: 'text'};

this.location.replaceState(
  this.router.createUrlTree(
    [this.locationStrategy.path().split('?')[0]], // Get uri
    {queryParams: queryParamsObj} // Pass all parameters inside queryParamsObj
  ).toString()
);

- EDITAR -

Creo que debería agregar más información para esto.

Si usa el this.location.replaceState()enrutador, su aplicación no está actualizada, por lo que si usa la información del enrutador más adelante, no es igual para esto en su navegador. Por ejemplo, si usa localizeServicepara cambiar el idioma, después de cambiar el idioma, su aplicación vuelve a la última URL donde estaba antes, cámbiela con this.location.replaceState().

Si no desea este comportamiento, puede elegir un método diferente para actualizar la URL, como:

this.router.navigate(
  [this.locationStrategy.path().split('?')[0]],
  {queryParams: queryParamsObj}
);

En esta opción, su navegador tampoco se actualiza, pero su URLcambio también se inyecta en Routersu aplicación, por lo que cuando cambia de idioma no tiene problemas como en this.location.replaceState().

Por supuesto, puede elegir el método que se adapte a sus necesidades. El primero es más ligero porque no activa su aplicación más que un cambio URLde navegador.

kris_IV
fuente
3

Para mí, en realidad fue una combinación de ambos con Angular 4.4.5.

El uso de router.navigate siguió destruyendo mi url al no respetar la parte realtiveTo: selectedRoute.

Terminé con:

this._location.go(this._router.createUrlTree([this._router.url], { queryParams: { profile: value.id } }).toString())
Patrick P.
fuente
3

Utilice el atributo queryParamsHandling: 'merge' mientras cambia la URL.

this.router.navigate([], {
        queryParams: this.queryParams,
        queryParamsHandling: 'merge',
        replaceUrl: true,
});
Rajeev Raushan Prasad
fuente
3
Esto hace que el componente enrutado actualmente se
vuelva