Modifica i parametri del percorso senza ricaricare in Angular 2


114

Sto realizzando un sito web immobiliare utilizzando Angular 2, Google Maps, ecc. E quando un utente cambia il centro della mappa eseguo una ricerca all'API indicando la posizione corrente della mappa oltre che il raggio. Il fatto è che voglio riflettere quei valori nell'URL senza ricaricare l'intera pagina. È possibile? Ho trovato alcune soluzioni usando AngularJS 1.x ma niente su Angular 2.


Penso che se usi [routerLink] = "['/ route', {param1: value1}] non ricaricherà la pagina
Toolkit

ma come posso aggiungere un altro parametro di query?
Toolkit

2
☝️ causerà un ricaricamento della pagina
LifterCoder

Solo una nota che se usi SSR per rendere il tuo sito compatibile SEO, questo è un problema discutibile.
Jonathan

@ Jonathan, vero? Poiché Angular assume il controllo del routing una volta che la pagina statica è stata renderizzata, penserei che sia ancora una domanda valida anche quando si utilizza SSR.
adam0101

Risposte:


92

Potresti usare location.go(url)che sostanzialmente cambierà il tuo URL, senza cambiare il percorso dell'applicazione.

NOTA questo potrebbe causare altri effetti come il reindirizzamento al percorso figlio dal percorso corrente.

La domanda correlata che descrivelocation.gonon intendeRouterfar accadere cambiamenti.


2
Il mio percorso ha un parametro chiamato 'ricerca' in cui ricevo una versione serializzata dei campi di ricerca, quando lo stato dell'elenco viene caricato per la prima volta leggo solo quei parametri usando this._routeParams.get ('cerca'), deserializza i filtri ed eseguire la ricerca. Se l'utente modifica i campi di ricerca, utilizzando la mappa o le sfaccettature di ricerca, costruisco semplicemente l'URL corretto utilizzando il metodo generate dell'istruzione var router = this._router.generate (['Listing', {search: serializedFields}] ) e quindi utilizzando this._location.go (instructions.urlPath) per modificare l'URL senza ricaricare lo stato.
Marcos Basualdo

20
Se qualcun altro si sta chiedendo: import {Location} da 'angular2 / platform / common';
Kesarion

18
import { Location } from '@angular/common';in Angular 4
tehCivilian

2
Hai decaricato la costruzione comeconstructor(private location: Location){ }
Pankaj Parkar

2
@ AdrianE il problema è molto probabilmente che hai digitato location.go()mentre avresti dovuto digitare this.location.go(). Quando si emette il this., si chiama l'interfaccia di localizzazione di Typescript.
georg-un

94

A partire da RC6 puoi fare quanto segue per cambiare l'URL senza cambiare stato e mantenendo così la cronologia del percorso

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

Questo non funziona per me. Prova a caricare il percorso. Errore console:Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'some/newstate'
Inigo

2
Combina questo con la creazione dell'URL come suggerito da @golfadas e abbiamo un vincitore!
crowmagnumb

63

L'uso location.go(url)è la strada da percorrere, ma invece di codificare l'URL, considera di generarlo usando router.createUrlTree().

Dato che vuoi fare la seguente chiamata al router: this.router.navigate([{param: 1}], {relativeTo: this.activatedRoute})ma senza ricaricare il componente, può essere riscritto come:

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

 this.location.go(url);

9
Questa risposta ha risolto il mio problema. Una domanda, l'URL generato sopra sta avendo parametri delimitati da ";" (punto e virgola). Cosa dovremmo fare per separare ogni parametro nella query con "&"?
Amarnath

2
questa è la dichiarazione di createUrlTree (commands: any [], navigationExtras ?: NavigationExtras). devi usare queryParams trova navigationExtras non commads. createUrlTree ([], {relativeTo: this.activatedRoute, queryParams: {param: 1}})
kit

solo per chiarire cosa ha detto @kit, fai questo:this.router.createUrlTree([], {relativeTo: this.activatedRoute, queryParams: {param: 1}}).toString()
bluegrounds il

12

Per chiunque come me trovi questa domanda, potrebbe essere utile quanto segue.

Ho avuto un problema simile e inizialmente ho provato a utilizzare location.go e location.replaceState come suggerito in altre risposte qui. Tuttavia ho riscontrato problemi quando ho dovuto navigare in un'altra pagina dell'app perché la navigazione era relativa al percorso corrente e il percorso corrente non veniva aggiornato da location.go o location.replaceState (il router non sa nulla su cosa fanno all'URL)

In sostanza, avevo bisogno di una soluzione che NON ricaricasse la pagina / componente quando il parametro del percorso è cambiato, ma aggiornava internamente lo stato del percorso.

Ho finito per utilizzare i parametri di query. Puoi trovare ulteriori informazioni al riguardo qui: https://angular-2-training-book.rangle.io/handout/routing/query_params.html

Quindi, se devi fare qualcosa come salvare un ordine e ottenere un ID ordine, puoi aggiornare l'URL della tua pagina come mostrato di seguito. L'aggiornamento della posizione di un centro e dei dati correlati su una mappa sarebbe simile

// 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 ne tieni traccia all'interno del metodo ngOnInit come:

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 devi andare direttamente alla pagina dell'ordine con un nuovo ordine (non salvato) puoi fare:

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

Oppure, se devi andare direttamente alla pagina dell'ordine per un ordine esistente (salvato) puoi fare:

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

10

Ho avuto grossi problemi a farlo funzionare nelle versioni RCx di angular2. Il pacchetto Location è stato spostato e l'esecuzione di location.go () all'interno di constructor () non funzionerà. Deve essere ngOnInit () o successivo nel ciclo di vita. Ecco un codice di esempio:

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

Ecco le risorse angolari in materia: https://angular.io/docs/ts/latest/api/common/index/Location-class.html https://angular.io/docs/ts/latest/api/ comune / index / LocationStrategy-class.html


7

Uso questo modo per ottenerlo:

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

-- MODIFICARE --

Penso che dovrei aggiungere qualche informazione in più per questo.

Se utilizzi il this.location.replaceState()router, la tua applicazione non è aggiornata, quindi se utilizzi le informazioni del router in un secondo momento non è uguale a questo nel tuo browser. Ad esempio, se si utilizza localizeServiceper cambiare la lingua, dopo aver cambiato la lingua l'applicazione torna all'ultimo URL in cui si trovava prima, cambiarla con this.location.replaceState().

Se non desideri questo comportamento, puoi scegliere un metodo diverso per l'aggiornamento dell'URL, come:

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

In questa opzione anche il tuo browser non si aggiorna ma la tua URLmodifica viene anche iniettata nella Routertua applicazione, quindi quando cambi lingua non hai problemi come in this.location.replaceState().

Ovviamente puoi scegliere il metodo per le tue esigenze. Il primo è più leggero perché non coinvolgi la tua applicazione più che cambiare URLbrowser.


3

Per me è stato effettivamente un mix di entrambi con Angular 4.4.5.

L'utilizzo di router.navigate continuava a distruggere il mio URL non rispettando la parte realtiveTo: enabledRoute.

Ho finito con:

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

3

Utilizza l'attributo queryParamsHandling: 'merge' durante la modifica dell'URL.

this.router.navigate([], {
        queryParams: this.queryParams,
        queryParamsHandling: 'merge',
        replaceUrl: true,
});

3
Questo fa sì che il componente attualmente instradato venga ricaricato
btx
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.