Jak uzyskać parametry zapytania z adresu URL w Angular 2?


237

Używam angular2.0.0-beta.7. Gdy składnik jest ładowany na ścieżkę, tak jak /path?query=value1jest przekierowywany /path. Dlaczego usunięto parametry GET? Jak mogę zachować parametry?

Mam błąd w routerach. Jeśli mam główną trasę jak

@RouteConfig([
  {
      path: '/todos/...',
      name: 'TodoMain',
      component: TodoMainComponent
  }
])

i moja droga dziecka jak

@RouteConfig([
  { path: '/', component: TodoListComponent, name: 'TodoList', useAsDefault:true },
  { path: '/:id', component: TodoDetailComponent, name:'TodoDetail' }
])

wtedy nie mogę uzyskać parametrów w TodoListComponent. Jestem w stanie zdobyć

params("/my/path;param1=value1;param2=value2") 

ale chcę klasykę

query params("/my/path?param1=value1&param2=value2")

1
jak określiłeś @RouteConfigto path?
Pankaj Parkar

Znalazłem błąd. Mam główną trasę i trasę podrzędną, a jeśli mam główną trasę, taką jak {ścieżka: '/ todos / ...', nazwa: 'TodoMain', składnik: TodoMainComponent} i droga podrzędna {ścieżka: '/', składnik: TodoListComponent, name: 'TodoList', useAsDefault: true}, to nie działa i przekierowuje na adres URL bez parametrów zapytania.
FireGM

Odpowiedzi:


412

Przez wstrzyknięcie wystąpienia ActivatedRoutemożna subskrybować różne obserwowalne, w tym a queryParamsi paramsobserwowalne:

import {Router, ActivatedRoute, Params} from '@angular/router';
import {OnInit, Component} from '@angular/core';

@Component({...})
export class MyComponent implements OnInit {

  constructor(private activatedRoute: ActivatedRoute) {}

  ngOnInit() {
    // Note: Below 'queryParams' can be replaced with 'params' depending on your requirements
    this.activatedRoute.queryParams.subscribe(params => {
        const userId = params['userId'];
        console.log(userId);
      });
  }

}

UWAGA DOTYCZĄCA BRAKU SUBSKRYPCJI

@Reto i @ codef0rmer całkiem słusznie zauważyli, że zgodnie z oficjalnymi dokumentami metoda unsubscribe()wewnątrz składników nie onDestroy()jest w tym przypadku konieczna. Zostało to usunięte z mojej próbki kodu. (patrz niebieskie pole ostrzeżenia w tym samouczku)


2
Ponadto sugeruję zastąpienie subskrypcji obietnicą - w tym szczególnym przypadku. this.activatedRoute.params.toPromise (). then (response => ...) .catch (error => ...);
gru

Gdzie mogę przekazać „aktywowanyRoute”?
michali

20
Z oficjalnej dokumentacji: Czy muszę się wypisać? The Router manages the observables it provides and localizes the subscriptions. The subscriptions are cleaned up when the component is destroyed, protecting against memory leaks, so we don't need to unsubscribe from the route params Observable.
Reto

przekierowania kątowe bez uruchamiania subskrypcji (lub obietnicy). Widzę oryginalne wywołanie zwrotne oAUth z tokenem, ale następnie przekierowuje na trasę bez zapytania params, a console.log (param) jest tylko pustym obiektem.
FlavorScape

1
@Sobhan, tak, jest różnica. Operator switchMap zwraca wartość Obserwowalny, podczas gdy operator subskrypcji pozwala obserwatorowi (naszemu komponentowi) zobaczyć elementy ostatecznie emitowane przez Obserwowalny. Tak więc w dokumentacji są 2 przypadki zastosowania mapy przełączników. 1) Użyli switchMap, aby dołączyć zapytanie o bohaterów. SwitchMap, w przeciwieństwie do subskrypcji, zapewni, że żądanie zostanie anulowane, jeśli użytkownik ponownie przejdzie na trasę, wciąż szukając bohatera. 2) Zastosowano potok asynchroniczny. Rury asynchroniczne zużywają obserwowalne, więc nie można się subskrybować (rura asynchroniczna zrobi to za Ciebie).
Stephen Paul,

103

Gdy adres URL taki jak ten http://stackoverflow.com?param1=value

Możesz pobrać param1 po kodzie:

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';

@Component({
    selector: '',
    templateUrl: './abc.html',
    styleUrls: ['./abc.less']
})
export class AbcComponent implements OnInit {
    constructor(private route: ActivatedRoute) { }

    ngOnInit() {
        // get param
        let param1 = this.route.snapshot.queryParams["param1"];
    }
}

2
Czy to oznacza, że ​​nie musisz już dodawać „/: id” do ścieżki routeconfig? ponieważ dostaję „niezdefiniowany”, kiedy go używam, więc muszę gdzieś mieć błąd
Axelle

2
Wspaniały. Właśnie tego szukałem, ponieważ muszę odczytać parametry bezpośrednio z dynamicznego adresu URL serwera. Nie mogę korzystać z nawigacji.
The.Bear

37

Chociaż pytanie określa wersję beta 7 , to pytanie pojawia się również jako najlepszy wynik wyszukiwania w Google dla typowych wyrażeń, takich jak parametry zapytania kątowego 2 . Z tego powodu oto odpowiedź na najnowszy router (obecnie w wersji alfa 7 ).

Sposób odczytu parametrów zmienił się diametralnie. Najpierw musisz wstrzyknąć zależność wywoływaną Routerw parametrach konstruktora, takich jak:

constructor(private router: Router) { }

a potem możemy zasubskrybować parametry zapytania w naszej ngOnInitmetodzie (konstruktor też jest w porządku, ale ngOnInitpowinien być użyty do testowania) jak

this.router
  .routerState
  .queryParams
  .subscribe(params => {
    this.selectedId = +params['id'];
  });

W tym przykładzie czytamy identyfikator parametru zapytania z adresu URL typu example.com?id=41.

Wciąż pozostaje kilka rzeczy do zauważenia:

  1. Dostęp do właściwości paramslike params['id']zawsze zwraca ciąg , który można przekonwertować na liczbę , poprzedzając go znakiem +.
  2. Powodem, dla którego parametry zapytania są pobierane z możliwym do zaobserwowania, jest to, że umożliwia ponowne użycie tego samego wystąpienia komponentu zamiast ładowania nowego. Za każdym razem, gdy parametr zapytania zostanie zmieniony, spowoduje to nowe zdarzenie, na które zasubskrybowaliśmy, dzięki czemu możemy odpowiednio zareagować na zmiany.

Czy istnieje sposób, aby wiele parametrów trafiało do tego samego członka? Na przykład chciałbym, aby „id” lub „identyfikacja” poszły do ​​this.selectedId.
phandinhlan

@phandinhlan: Cóż, tak naprawdę nie jest to pytanie związane z Angularem 2. Można go oczywiście zaimplementować, ale musisz sam zdefiniować logikę. Zasadniczo, co chcesz zrobić, to najpierw sprawdzić, czy pierwszy klucz jest zdefiniowany, a dopiero potem odczytać z niego wartość, a jeśli nie, odczytać wartość za pomocą innego klucza. Można to osiągnąć za pomocą czegoś takiego if (params.hasOwnProperty('id')) { this.selectedId = params['id'] } else { this.selectedId = params['identification']}.
Roope Hakulinen,

Tak, skończyło się na zrobieniu czegoś takiego. Pomyślałem, że będzie jakiś „wbudowany” sposób, taki jak: this.selectedId = + params ['id']; this.selectedId = + params ['identyfikacja']; Oczywiście to nie ma sensu i nie działa.
phandinhlan

28

Bardzo podobała mi się odpowiedź @ StevePaula, ale możemy zrobić to samo bez zbędnego połączenia z subskrypcją / anulowaniem subskrypcji.

import { ActivatedRoute } from '@angular/router';
constructor(private activatedRoute: ActivatedRoute) {
    let params: any = this.activatedRoute.snapshot.params;
    console.log(params.id);
    // or shortcut Type Casting
    // (<any> this.activatedRoute.snapshot.params).id
}

7
zastrzeżeniem jest oczywiście to, że będzie to wartość początkowa i kolejne zmiany nie zostaną odzwierciedlone. Jeśli więc programowo zmieniasz parametry adresu URL w ramach logiki, musisz o tym wiedzieć
oburęczny

Nie jestem pewien, czy zmieniło się to w późniejszych wersjach Angulara, ale teraz widzę to w this.activatedRoute.snapshot.queryParams
Michael

21

Aby wysłać parametry zapytania

import { Router } from '@angular/router';
this.router.navigate([ '/your-route' ], { queryParams: { key: va1, keyN: valN } });

Aby otrzymać parametry zapytania

import { ActivatedRoute } from '@angular/router';
this.activatedRoute.queryParams.subscribe(params => {
    let value_1 = params['key'];
    let value_N = params['keyN'];
});

Oficjalne źródło


Odczyt działa dobrze, ale wielkość liter ma znaczenie. Jak sprawić, by wielkość liter nie była uwzględniana?
Unnie,

12

Cześć, możesz użyć URLSearchParams, możesz przeczytać więcej na ten temat tutaj .

import:

import {URLSearchParams} from "@angular/http";

i funkcja:

getParam(){
  let params = new URLSearchParams(window.location.search);
  let someParam = params.get('someParam');
  return someParam;
}

Uwaga : nie jest obsługiwany przez wszystkie platformy i wydaje się być w stanie „EKSPERYMENTALNYM” przez kątowe dokumenty


2
To mi nie działa. Odkryłem, że window.location.search zawiera wiodący znak zapytania parametrów zapytania. Tak więc klucz do pierwszego parametru będzie poprzedzony znakiem zapytania.
AJ Morris

AJ Morris, aby obejść problem: if (window.location.search.indexOf('?') == 0){ normalizedQueryString = window.location.search.substring(1); } else { normalizedQueryString = window.location.search; } let params = new URLSearchParams(normalizedQueryString);
oburęczny

URLSearchParams jest przestarzałe. Teraz możesz to zrobić za pomocą ActivatedRoute.
Robert Blasco Villarroya,

7

Po pierwsze, znalazłem pracę z Angular2, że będzie to adres URL z ciągiem zapytania /path;query=value1

Aby uzyskać dostęp do tego komponentu, którego używasz Tak jest, ale teraz następuje blok kodu:

    constructor(params: RouteParams){
    var val = params.get("query");
    }

Co do tego, dlaczego zostałby usunięty podczas ładowania komponentu, nie jest to zachowanie domyślne. Sprawdziłem konkretnie w czystym projekcie testowym i nie zostałem przekierowany ani zmieniony. Czy jest to domyślna trasa, czy coś specjalnego w routingu?

Przeczytaj o routingu z ciągami zapytań i parametrami w samouczku Angular2 na https://angular.io/docs/ts/latest/guide/router.html#!#query-parameters


Nie mogę używać parametrów takich jak „; param1 = wartość1; param2 = wartość2”, ten link wygenerowany w innej witrynie i przekierowuje na mojej stronie, np. „
Example.com/auth?code_for_auth=askjfbkajdsbfksajdf

Sposób, w jaki routing jest obecnie skonfigurowany w Angular2, nie sądzę, że jest to naprawdę możliwe. Konieczne będzie pewne obejście, ponieważ routing potomny zależy od adresu URL macierzy. O ile przynajmniej wiem. Przechwyciłbym go na moim serwerze internetowym i przekształciłbym w hack, do bani, ale w tej chwili nie mogę wymyślić innego sposobu
Namirna

Nie możesz poprosić strony linkującej o zmianę adresu URL?
Namirna

1
Nie. Ale problem rozwiązałem po prostu ręcznie analizując parametr Location.path ()
FireGM

4
to rozwiązanie jest przestarzałe!

7

Parametry zapytania można uzyskać po przekazaniu w adresie URL za pomocą ActivatedRoute, jak podano poniżej: -

url: - http: /domain.com? test = abc

import { Component } from '@angular/core';
import { ActivatedRoute }     from '@angular/router';

@Component({
  selector: 'my-home'
})
export class HomeComponent {

  constructor(private sharedServices : SharedService,private route: ActivatedRoute) { 
    route.queryParams.subscribe(
      data => console.log('queryParams', data['test']));
  }

}

7

Uzyskaj parametr URL jako obiekt.

import { Router } from '@angular/router';
constructor(private router: Router) {
    console.log(router.parseUrl(router.url));
}

2

Jeśli chcesz uzyskać parametr zapytania tylko raz, najlepszym sposobem jest użycie metody take , dzięki czemu nie musisz się martwić o rezygnację z subskrypcji. Oto prosty fragment: -

constructor(private route: ActivatedRoute) {
  route.snapshot.queryParamMap.take(1).subscribe(params => {
     let category = params.get('category')
     console.log(category);
  })
}

Uwaga: Usuń take (1), jeśli chcesz użyć wartości parametrów w przyszłości.


2

teraz jest:

this.activatedRoute.queryParams.subscribe((params: Params) => {
  console.log(params);
});

1
Dziękujemy za ten fragment kodu, który może zapewnić ograniczoną krótkotrwałą pomoc. Właściwe wyjaśnienie znacznie poprawiłoby jego długoterminową wartość, pokazując, dlaczego jest to dobre rozwiązanie problemu i uczyniłoby to bardziej użytecznym dla przyszłych czytelników z innymi podobnymi pytaniami. Edytuj swoją odpowiedź, aby dodać wyjaśnienie, w tym przyjęte przez ciebie założenia
Shawn C.

1

Mam nadzieję, że pomoże to komuś innemu.

Pytanie powyżej stwierdza, że ​​wartość parametru zapytania jest potrzebna po przekierowaniu strony i możemy założyć, że wartość migawki (nieobserwowalna alternatywa) byłaby wystarczająca.

Nikt tutaj nie wspomniał o snapshot.paramMap.get z oficjalnej dokumentacji .

this.route.snapshot.paramMap.get('id')

Więc przed wysłaniem dodaj to w komponencie wysyłającym / przekierowującym:

import { Router } from '@angular/router';

następnie przekieruj jako jedno z nich ( tutaj udokumentowane ):

this.router.navigate(['/heroes', { id: heroId, foo: 'foo' }]);

lub po prostu:

this.router.navigate(['/heroes', heroId ]);

Upewnij się, że dodałeś to do swojego modułu routingu, jak tu udokumentowano :

 { path: 'hero/:id', component: HeroDetailComponent }

I wreszcie w komponencie, który musi użyć parametru zapytania

  • dodaj import (udokumentowany tutaj ):

    import { Router, ActivatedRoute, ParamMap } from '@angular/router';
  • wstrzyknąć ActivatedRoute

(dokumentacja importuje również SwitchMap, a także wstrzykuje Routera i HeroService - ale są one potrzebne tylko dla obserwowalnej alternatywy - NIE są one potrzebne, gdy używasz alternatywnej migawki, jak w naszym przypadku):

    constructor(
      private route: ActivatedRoute
    ) {}
  • i uzyskaj potrzebną wartość (udokumentowaną tutaj ):

    ngOnInit() {
      const id = this.route.snapshot.paramMap.get('id');
    }

UWAGA: JEŚLI DODIESZ MODUŁ ROUTINGU DO MODUŁU FUNKCJI (JAK WYKAZANO W DOKUMENTACJI) UPEWNIJ SIĘ, ŻE W APP.MODULE.ts, ŻE MODUŁ ROUTINGU PRZYJMUJE PRZED modułem AppRoutingModule (lub innym plikiem z trasami aplikacji na poziomie administratora) W PRZYPADKU: []. INNE TRASY FUNKCJI NIE ZOSTANĄ ZNALEZIONE (TAK, JAKIE POWINNY BYĆ PO {path: '**', przekieruj do: '/ not-found'}, a zobaczysz tylko wiadomość nie znalezioną).


1

Musisz tylko wstrzyknąć ActivatedRoute do konstruktora, a następnie po prostu uzyskać dostęp do parametrów lub queryParams

constructor(private route:ActivatedRoute){}
ngOnInit(){
        this.route.queryParams.subscribe(params=>{
        let username=params['username'];
      });
 }

W niektórych przypadkach nie daje to niczego w NgOnInit ... może z powodu wywołania init przed inicjalizacją parametrów w tym przypadku można to osiągnąć, prosząc obserwowalne, aby poczekało jakiś czas przez funkcję debounceTime (1000)

np. =>

 constructor(private route:ActivatedRoute){}
    ngOnInit(){
            this.route.queryParams.debounceTime(100).subscribe(params=>{
            let username=params['username'];
          });
     }

debounceTime () Emituje wartość ze źródła obserwowalną dopiero po upływie określonego czasu bez emisji innej źródła


0

Nie możesz uzyskać parametru z RouterState, jeśli nie jest zdefiniowany w trasie, więc w twoim przykładzie musisz przeanalizować kwerendę ...

Oto kod, którego użyłem:

let re = /[?&]([^=#&]+)=([^&#]*)/g;
let match;
let isMatch = true;
let matches = [];
while (isMatch) {
    match = re.exec(window.location.href);
    if (match !== null) {
        matches[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
        if (match.index === re.lastIndex) {
            re.lastIndex++;
        }
    }
    else {
        isMatch = false;
    }
}
console.log(matches);


0

Zapytanie i ścieżka (Angular 8)

Jeśli masz adres URL taki jak https://myapp.com/owner/123/show?height=23, użyj

combineLatest( [this.route.paramMap, this.route.queryParamMap] )
  .subscribe( ([pathParams, queryParams]) => {
    let ownerId = pathParams.get('ownerId');    // =123
    let height  = queryParams.get('height');    // =height
    // ...
  })

AKTUALIZACJA

W przypadku, gdy użyjesz, this.router.navigate([yourUrl]);a parametry zapytania są osadzone w yourUrlciągu, wówczas kątowy koduje adres URL i otrzymujesz coś takiego: https://myapp.com/owner/123/show%3Fheight%323 - i powyższe rozwiązanie da zły wynik ( queryParams będzie puste, a parametry zapytania można przykleić do ostatniego parametru ścieżki, jeśli znajduje się na końcu ścieżki). W takim przypadku zmień sposób nawigacji na to

this.router.navigateByUrl(yourUrl);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.