Ändern Sie die Routenparameter, ohne sie in Angular 2 neu zu laden

112

Ich erstelle eine Immobilienwebsite mit Angular 2, Google Maps usw. Wenn ein Benutzer die Mitte der Karte ändert, führe ich eine Suche in der API durch, die die aktuelle Position der Karte sowie den Radius angibt. Die Sache ist, ich möchte diese Werte in der URL widerspiegeln, ohne die gesamte Seite neu zu laden. Ist das möglich? Ich habe einige Lösungen mit AngularJS 1.x gefunden, aber nichts über Angular 2.

Marcos Basualdo
quelle
Ich denke, wenn Sie [routerLink] = "['/ route', {param1: value1}] verwenden, wird die Seite nicht neu geladen
Toolkit
aber wie kann ich einen anderen Abfrageparameter hinzufügen?
Toolkit
2
☝️ es wird ein
erneutes
Nur ein Hinweis: Wenn Sie SSR verwenden, um Ihre Website SEO-kompatibel zu machen, ist dies ein strittiges Problem.
Jonathan
@ Jonathan, ist es? Da Angular das Routing übernimmt, sobald die statische Seite gerendert ist, würde ich denken, dass dies auch bei Verwendung von SSR eine gültige Frage ist.
adam0101

Antworten:

90

Sie können verwenden, location.go(url)wodurch sich Ihre URL grundsätzlich ändert, ohne den Anwendungsweg zu ändern.

HINWEIS: Dies kann andere Auswirkungen haben, z. B. die Umleitung von der aktuellen Route zur untergeordneten Route.

Verwandte Fragen, die beschreiben,location.gowerden nicht darauf hindeutenRouter, dass Änderungen eintreten.

Pankaj Parkar
quelle
2
Meine Route hat einen Parameter namens 'search', in dem eine serialisierte Version der Suchfelder empfangen wird. Wenn der Listenstatus zum ersten Mal geladen wird, lese ich diese Parameter nur mit this._routeParams.get ('search') und deserialisiere die Filter und führen Sie die Suche durch. Wenn der Benutzer die Suchfelder entweder mithilfe der Karte oder der Suchfacetten ändert, erstelle ich einfach die richtige URL mit der Methode, die vom Router generiert wurde. Var Anweisung = this._router.generate (['Listing', {search: serializedFields}] ) und verwenden Sie dann this._location.go (Anweisung.urlPath), um die URL zu ändern, ohne den Status neu zu laden.
Marcos Basualdo
20
Wenn sich jemand wundert: {Location} aus 'angle2 / platform / common' importieren;
Kesarion
17
import { Location } from '@angular/common';in Angular 4
tehCivilian
2
Haben Sie Konstrukteur wieconstructor(private location: Location){ }
Pankaj Parkar
2
@AdrianE Das Problem ist höchstwahrscheinlich, dass Sie getippt haben, location.go()während Sie hätten tippen sollen this.location.go(). Wenn Sie das ausgeben this., rufen Sie die Standortschnittstelle von Typescript auf.
Georg-Un
94

Ab RC6 können Sie die URL wie folgt ändern, ohne den Status zu ändern, und so Ihren Routenverlauf beibehalten

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
quelle
Das funktioniert bei mir nicht. Es wird versucht, die Route zu laden. Konsolenfehler:Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'some/newstate'
Inigo
2
Kombinieren Sie dies mit der von @golfadas vorgeschlagenen URL-Erstellung und wir haben einen Gewinner!
Crowmagnumb
63

Verwenden location.go(url)ist der richtige Weg, aber anstatt die URL fest zu codieren, sollten Sie sie mit generieren router.createUrlTree().

Vorausgesetzt, Sie möchten den folgenden Router-Aufruf ausführen: this.router.navigate([{param: 1}], {relativeTo: this.activatedRoute})Ohne die Komponente neu zu laden, kann sie wie folgt umgeschrieben werden:

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

 this.location.go(url);
Golfadas
quelle
9
Diese Antwort löste mein Problem. Eine Frage, die oben generierte URL hat Parameter, die durch ";" (Semikolon) begrenzt sind. Was sollen wir tun, um jeden Parameter in der Abfrage mit "&" zu trennen?
Amarnath
2
Dies ist die Deklaration von createUrlTree (Befehle: any [], navigationExtras?: NavigationExtras). Sie müssen queryParams verwenden, das sich in navigationExtras befindet, nicht in Kommads. createUrlTree ([], {relativeTo: this.activatedRoute, queryParams: {param: 1}})
Kit
Um zu verdeutlichen, was @kit gesagt hat, gehen Sie wie folgt vor:this.router.createUrlTree([], {relativeTo: this.activatedRoute, queryParams: {param: 1}}).toString()
Bluegrounds
12

Für jemanden wie mich, der diese Frage findet, könnte das Folgende nützlich sein.

Ich hatte ein ähnliches Problem und versuchte zunächst, location.go und location.replaceState zu verwenden, wie in anderen Antworten hier vorgeschlagen. Ich hatte jedoch Probleme, als ich zu einer anderen Seite in der App navigieren musste, da die Navigation relativ zur aktuellen Route war und die aktuelle Route nicht durch location.go oder location.replaceState aktualisiert wurde (der Router weiß nichts darüber, was diese mit der URL machen)

Im Wesentlichen brauchte ich eine Lösung, die die Seite / Komponente NICHT neu lud, wenn sich der Routenparameter änderte, sondern den Routenstatus intern aktualisierte.

Am Ende habe ich Abfrageparameter verwendet. Weitere Informationen finden Sie hier: https://angular-2-training-book.rangle.io/handout/routing/query_params.html

Wenn Sie also beispielsweise eine Bestellung speichern und eine Bestellnummer erhalten müssen, können Sie Ihre Seiten-URL wie unten gezeigt aktualisieren. Das Aktualisieren eines Zentrumsstandorts und zugehöriger Daten auf einer Karte wäre ähnlich

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

und Sie verfolgen es innerhalb der ngOnInit-Methode wie folgt:

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]
}

Wenn Sie mit einer neuen (nicht gespeicherten) Bestellung direkt zur Bestellseite gehen müssen, haben Sie folgende Möglichkeiten:

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

Wenn Sie für eine vorhandene (gespeicherte) Bestellung direkt zur Bestellseite wechseln müssen, haben Sie folgende Möglichkeiten:

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

Ich hatte große Probleme damit, dass dies in RCx-Versionen von angle2 funktioniert. Das Location-Paket wurde verschoben, und die Ausführung von location.go () im Konstruktor () funktioniert nicht. Es muss ngOnInit () oder später im Lebenszyklus sein. Hier ist ein Beispielcode:

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

Hier sind die eckigen Ressourcen zu diesem Thema: 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
quelle
7

Ich benutze diesen Weg, um es zu bekommen:

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

- BEARBEITEN -

Ich denke, dass ich hierfür weitere Informationen hinzufügen sollte.

Wenn Sie den this.location.replaceState()Router Ihrer Anwendung verwenden, wird dieser nicht aktualisiert. Wenn Sie also später Router-Informationen verwenden, ist dies in Ihrem Browser nicht gleich. Wenn Sie beispielsweise localizeServicedie Sprache ändern, wird Ihre Anwendung nach dem Sprachwechsel wieder auf die letzte URL zurückgesetzt, mit der Sie sie zuvor geändert haben this.location.replaceState().

Wenn Sie dieses Verhalten nicht möchten, können Sie eine andere Methode zum Aktualisieren der URL auswählen, z.

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

Bei dieser Option wird Ihr Browser auch nicht aktualisiert, aber Ihre URLÄnderung wird auch in RouterIhre Anwendung übernommen. Wenn Sie also die Sprache wechseln, haben Sie keine Probleme wie in this.location.replaceState().

Natürlich können Sie die Methode für Ihre Bedürfnisse wählen. Die erste ist leichter, da Sie Ihre Anwendung nur aktivieren, wenn Sie den URLBrowser ändern .

kris_IV
quelle
3

Für mich war es eigentlich eine Mischung aus beidem mit Angular 4.4.5.

Durch die Verwendung von router.navigate wurde meine URL immer wieder zerstört, indem der Teil realtiveTo: enabledRoute nicht beachtet wurde.

Am Ende habe ich:

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

Verwenden Sie das Attribut queryParamsHandling: 'merge', während Sie die URL ändern.

this.router.navigate([], {
        queryParams: this.queryParams,
        queryParamsHandling: 'merge',
        replaceUrl: true,
});
Rajeev Raushan Prasad
quelle
2
Dies führt dazu, dass die aktuell geroutete Komponente neu geladen wird
BTX