Altere os parâmetros da rota sem recarregar no Angular 2

112

Estou criando um site de imobiliária usando Angular 2, Google Maps, etc. e quando um usuário muda o centro do mapa, eu faço uma pesquisa na API indicando a posição atual do mapa, bem como o raio. O fato é que desejo refletir esses valores no url sem recarregar a página inteira. Isso é possível? Eu encontrei algumas soluções usando o AngularJS 1.x, mas nada sobre o Angular 2.

Marcos Basualdo
fonte
Acho que se você usar [routerLink] = "['/ route', {param1: value1}], a página não será recarregada
Toolkit
mas como posso adicionar outro parâmetro de consulta?
Toolkit
2
☝️ fará com que a página seja recarregada
LifterCoder
Apenas uma observação que se você usar SSR para tornar seu site compatível com o SEO, este é um problema discutível.
Jonathan,
@Jonathan, não é? Uma vez que o Angular assume o roteamento assim que a página estática é renderizada, eu acho que ainda é uma questão válida mesmo ao usar SSR.
adam0101

Respostas:

91

Você poderia usar o location.go(url)que basicamente mudaria seu url, sem alterar a rota de aplicação.

OBSERVAÇÃO, isso pode causar outros efeitos, como redirecionar para a rota secundária a partir da rota atual.

A questão relacionada que descrevelocation.gonão sugereRouterque ocorram mudanças.

Pankaj Parkar
fonte
2
Minha rota tem um parâmetro chamado 'search' no qual recebo uma versão serializada dos campos de pesquisa, quando o estado de listagem carrega pela primeira vez, eu só leio esses parâmetros usando this._routeParams.get ('search'), desserializo os filtros e realizar a pesquisa. Se o usuário alterar os campos de pesquisa, usando o mapa ou as facetas de pesquisa, eu apenas construo o url correto usando o método generate do roteador var instrução = this._router.generate (['Listing', {search: serializedFields}] ) e, em seguida, usando this._location.go (instrução.urlPath) para alterar o url sem recarregar o estado.
Marcos Basualdo
20
Se mais alguém estiver se perguntando: import {Location} from 'angular2 / platform / common';
Kesarion de
18
import { Location } from '@angular/common';em Angular 4
tehCivilian
2
Você decretou o construtor comoconstructor(private location: Location){ }
Pankaj Parkar
2
@AdrianE o problema provavelmente é que você digitou location.go()enquanto deveria this.location.go(). Ao emitir o this., você chama a interface de localização do Typescript.
georg-un de
94

A partir do RC6, você pode fazer o seguinte para alterar o URL sem alterar o estado e, assim, manter seu histórico de rota

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
fonte
Isso não funciona para mim. Ele ainda tenta carregar a rota. Erro do console:Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'some/newstate'
Inigo
2
Combine isso com a criação de url sugerido por @golfadas e teremos um vencedor!
crowmagnumb de
63

Usar location.go(url)é o caminho a seguir, mas em vez de codificar o url, considere gerá-lo usando router.createUrlTree().

Visto que você deseja fazer a seguinte chamada de roteador: this.router.navigate([{param: 1}], {relativeTo: this.activatedRoute})mas sem recarregar o componente, ele pode ser reescrito como:

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

 this.location.go(url);
golfadas
fonte
9
Esta resposta resolveu meu problema. Uma questão, o url gerado acima está tendo parâmetros delimitados por ";" (ponto e vírgula). O que devemos fazer para separar cada parâmetro na consulta com "&"?
Amarnath
2
esta é a declaração de createUrlTree (comandos: any [], navigationExtras ?: NavigationExtras). você tem que usar queryParams found navigationExtras não vírgulas. createUrlTree ([], {relativeTo: this.activatedRoute, queryParams: {param: 1}})
kit
apenas para esclarecer o que @kit disse, faça o seguinte:this.router.createUrlTree([], {relativeTo: this.activatedRoute, queryParams: {param: 1}}).toString()
bluegrounds
12

Para qualquer pessoa como eu, encontrar esta questão pode ser útil.

Tive um problema semelhante e tentei inicialmente usar location.go e location.replaceState conforme sugerido em outras respostas aqui. No entanto, tive problemas quando tive que navegar para outra página no aplicativo porque a navegação era relativa à rota atual e a rota atual não estava sendo atualizada por location.go ou location.replaceState (o roteador não sabe de nada sobre o que eles fazem ao URL)

Em essência, eu precisava de uma solução que NÃO recarregasse a página / componente quando o parâmetro da rota mudasse, mas atualizasse o estado da rota internamente.

Acabei usando parâmetros de consulta. Você pode encontrar mais sobre isso aqui: https://angular-2-training-book.rangle.io/handout/routing/query_params.html

Portanto, se você precisar fazer algo como salvar um pedido e obter um ID do pedido, pode atualizar o URL da página conforme mostrado abaixo. Atualizar um local central e dados relacionados em um mapa seria semelhante

// 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.
}

e você acompanha isso dentro do 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]
}

Se precisar ir direto para a página do pedido com um novo pedido (não salvo), você pode:

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

Ou, se precisar ir direto para a página de pedido de um pedido existente (salvo), você pode fazer:

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

Tive grandes problemas para fazer isso funcionar nas versões RCx do angular2. O pacote Location foi movido e a execução de location.go () dentro de constructor () não funcionará. Ele precisa ser ngOnInit () ou posterior no ciclo de vida. Aqui está um exemplo de código:

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

Aqui estão os recursos angulares sobre o assunto: 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
fonte
7

Eu uso esta maneira de obtê-lo:

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 -

Acho que devo acrescentar mais algumas informações para isso.

Se você usa o this.location.replaceState()roteador do seu aplicativo não está atualizado, então se você usar as informações do roteador posteriormente não é igual para isso no seu navegador. Por exemplo, se você usar localizeServicepara alterar o idioma, depois de alterar o idioma, seu aplicativo de volta para a última URL onde você estava antes, altere-o com this.location.replaceState().

Se você não quiser esse comportamento, pode escolher um método diferente para atualizar o URL, como:

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

Nesta opção, seu navegador também não atualiza, mas sua URLalteração também é injetada em Routerseu aplicativo, portanto, quando você muda de idioma, não tem problemas como em this.location.replaceState().

Claro, você pode escolher o método de acordo com suas necessidades. O primeiro é mais leve porque você não envolve mais seu aplicativo do que muda o URLnavegador.

kris_IV
fonte
3

Para mim, foi na verdade uma mistura de ambos com o Angular 4.4.5.

O uso de router.navigate destruía meu url por não respeitar a parte realtiveTo: enabledRoute.

Acabei com:

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

Use o atributo queryParamsHandling: 'merge' ao alterar o url.

this.router.navigate([], {
        queryParams: this.queryParams,
        queryParamsHandling: 'merge',
        replaceUrl: true,
});
Rajeev Raushan Prasad
fonte
3
Isso faz com que o componente atualmente roteado seja recarregado
btx