Zmień parametry trasy bez przeładowywania w Angular 2

114

Tworzę stronę internetową z nieruchomościami za pomocą Angular 2, Google Maps itp., A gdy użytkownik zmieni środek mapy, wyszukuję w API wskazując aktualną pozycję mapy oraz promień. Chodzi o to, że chcę odzwierciedlić te wartości w adresie URL bez ponownego ładowania całej strony. Czy to jest możliwe? Znalazłem kilka rozwiązań przy użyciu AngularJS 1.x, ale nic o Angular 2.

Marcos Basualdo
źródło
myślę, że jeśli użyjesz [routerLink] = "['/ route', {param1: value1}], strona nie zostanie ponownie załadowana
zestaw narzędzi
ale jak mogę dodać kolejny parametr zapytania?
Zestaw narzędzi,
2
☝️ spowoduje to przeładowanie strony
LifterCoder
Pamiętaj, że jeśli używasz SSR, aby Twoja witryna była zgodna z SEO, jest to kwestia sporna.
Jonathan
@Jonathan, czy to jest? Ponieważ Angular przejmuje routing po wyrenderowaniu strony statycznej, myślę, że nadal jest to ważne pytanie, nawet przy użyciu SSR.
adam0101

Odpowiedzi:

92

Możesz użyć, location.go(url)który zasadniczo zmieni Twój adres URL, bez zmiany trasy aplikacji.

UWAGA może to spowodować inne skutki, takie jak przekierowanie do trasy podrzędnej z bieżącej trasy.

Powiązane pytanie, które opisujelocation.go, nie spowodujeRouterzmian.

Pankaj Parkar
źródło
2
Moja trasa ma parametr o nazwie „search”, w którym otrzymuję zserializowaną wersję pól wyszukiwania, gdy stan listy jest ładowany po raz pierwszy, odczytuję te parametry tylko przy użyciu this._routeParams.get („search”), deserializuj filtry i przeprowadź wyszukiwanie. Jeśli użytkownik zmieni pola wyszukiwania, używając mapy lub aspektów wyszukiwania, po prostu konstruuję poprawny adres URL, używając metody generowania instrukcji var = this._router.generate (['Listing', {search: serializedFields}] ), a następnie używając this._location.go (instrukcja.urlPath) do zmiany adresu URL bez ponownego ładowania stanu.
Marcos Basualdo
20
Jeśli ktoś się zastanawia: zaimportuj {Location} z 'angular2 / platform / common';
Kesarion
18
import { Location } from '@angular/common';w Angular 4
tehCivilian
2
Czy zadeklarowałeś konstruktora jakconstructor(private location: Location){ }
Pankaj Parkar
2
@AdrianE najprawdopodobniej problem polega na tym, że wpisałeś, location.go()podczas gdy powinieneś był pisać this.location.go(). Kiedy emitujesz this., wywołujesz interfejs lokalizacji Typescript.
georg-un
94

Od wersji RC6 możesz wykonać następujące czynności, aby zmienić adres URL bez zmiany stanu, a tym samym zachować historię tras

    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
źródło
To nie działa na mnie. Sitll próbuje załadować trasę. Błąd konsoli:Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'some/newstate'
Inigo,
2
Połącz to z tworzeniem adresów URL zgodnie z sugestią @golfadas i mamy zwycięzcę!
crowmagnumb
63

Używanie location.go(url)jest właściwą drogą, ale zamiast zakodować adres URL na stałe, rozważ wygenerowanie go za pomocą router.createUrlTree().

Zakładając, że chcesz wykonać następujące wywołanie routera: this.router.navigate([{param: 1}], {relativeTo: this.activatedRoute})ale bez ponownego ładowania komponentu, można go przepisać jako:

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

 this.location.go(url);
golfadas
źródło
9
Ta odpowiedź rozwiązała mój problem. Jedno pytanie, adres URL wygenerowany powyżej ma parametry rozdzielone znakiem „;” (średnik). Co powinniśmy zrobić, aby oddzielić każdy parametr w zapytaniu znakiem „&”?
Amarnath,
2
to jest deklaracja createUrlTree (polecenia: any [], navigationExtras ?: NavigationExtras). musisz użyć queryParams zlokalizowanej nawigacjiExtras, a nie komend. createUrlTree ([], {relativeTo: this.activatedRoute, queryParams: {param: 1}})
zestaw
aby wyjaśnić, co powiedział @kit, zrób to:this.router.createUrlTree([], {relativeTo: this.activatedRoute, queryParams: {param: 1}}).toString()
bluegrounds
12

Dla każdego, kto tak jak ja, znalazłby to pytanie, przydatne mogą być następujące informacje.

Miałem podobny problem i początkowo próbowałem użyć location.go i location.replaceState, jak sugerowano w innych odpowiedziach tutaj. Jednak napotkałem problemy, gdy musiałem przejść do innej strony w aplikacji, ponieważ nawigacja była względna do bieżącej trasy, a bieżąca trasa nie była aktualizowana przez location.go lub location.replaceState (router nic nie wie o tym, co robią z adresem URL)

Zasadniczo potrzebowałem rozwiązania, które NIE WADZI przeładowywania strony / komponentu, gdy zmienił się parametr trasy, ale NIE zaktualizował stanu trasy wewnętrznie.

Skończyło się na parametrach zapytania. Więcej na ten temat można znaleźć tutaj: https://angular-2-training-book.rangle.io/handout/routing/query_params.html

Więc jeśli chcesz zrobić coś takiego, jak zapisać zamówienie i uzyskać identyfikator zamówienia, możesz zaktualizować adres URL swojej strony, jak pokazano poniżej. Aktualizacja lokalizacji centrum i powiązanych danych na mapie byłaby podobna

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

i śledzisz to w ramach metody ngOnInit, np .:

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

Jeśli chcesz przejść bezpośrednio do strony zamówienia z nowym (niezapisanym) zamówieniem, możesz zrobić:

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

Lub jeśli chcesz przejść bezpośrednio do strony zamówienia istniejącego (zapisanego) zamówienia, możesz zrobić:

this.router.navigate(['orders'], { queryParams: { id: '1234' } });
TornadoAli
źródło
10

Miałem poważne problemy z uruchomieniem tego w wydaniach RCx angular2. Pakiet Location został przeniesiony i uruchomienie funkcji location.go () wewnątrz constructor () nie zadziała. Musi to być ngOnInit () lub później w cyklu życia. Oto przykładowy kod:

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

Oto zasoby kątowe w tej sprawie: 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
źródło
7

Używam tego sposobu, aby to uzyskać:

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

-- EDYTOWAĆ --

Myślę, że powinienem dodać więcej informacji na ten temat.

Jeśli używasz this.location.replaceState()routera, Twoja aplikacja nie jest aktualizowana, więc jeśli później użyjesz informacji o routerze, nie będzie to równe w Twojej przeglądarce. Na przykład, jeśli używasz localizeServicedo zmiany języka, po zmianie języka aplikacji z powrotem na ostatni adres URL, gdzie byłeś przed zmianą za pomocą this.location.replaceState().

Jeśli nie chcesz tego zachowania, możesz wybrać inną metodę aktualizacji adresu URL, na przykład:

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

W tej opcji twoja przeglądarka również się nie odświeża, ale twoja URLzmiana jest również wprowadzana do Routertwojej aplikacji, więc kiedy zmieniasz język, nie masz problemu jak w this.location.replaceState().

Oczywiście możesz dobrać metodę do swoich potrzeb. Pierwsza jest lżejsza, ponieważ nie angażujesz aplikacji bardziej niż zmianę URLw przeglądarce.

kris_IV
źródło
3

Dla mnie była to właściwie mieszanka obu z Angular 4.4.5.

Korzystanie z router.navigate niszczyło mój adres URL, nie przestrzegając części realtiveTo: ActivatedRoute.

Skończyło się na:

this._location.go(this._router.createUrlTree([this._router.url], { queryParams: { profile: value.id } }).toString())
Patrick P.
źródło
3

Użyj atrybutu queryParamsHandling: 'merge' podczas zmiany adresu URL.

this.router.navigate([], {
        queryParams: this.queryParams,
        queryParamsHandling: 'merge',
        replaceUrl: true,
});
Rajeev Raushan Prasad
źródło
3
Powoduje to
ponowne