Comment obtenir les paramètres de requête à partir de l'URL dans Angular 2?

237

J'utilise angular2.0.0-beta.7. Lorsqu'un composant est chargé sur un chemin tel /path?query=value1qu'il est redirigé vers /path. Pourquoi les paramètres GET ont-ils été supprimés? Comment puis-je conserver les paramètres?

J'ai une erreur dans les routeurs. Si j'ai une route principale comme

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

et ma route d'enfant comme

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

alors je ne peux pas obtenir de paramètres dans TodoListComponent. Je peux obtenir

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

mais je veux le classique

query params("/my/path?param1=value1&param2=value2")
FireGM
la source
1
comment avez-vous spécifié @RouteConfigcela path?
Pankaj Parkar
J'ai trouvé une erreur. J'ai une route principale et une route enfant et si j'ai une route principale comme {path: '/ todos / ...', nom: 'TodoMain', composant: TodoMainComponent} et route enfant {path: '/', composant: TodoListComponent, nom: 'TodoList', useAsDefault: true}, cela ne fonctionne pas et redirige vers l'URL sans paramètres de requête.
FireGM

Réponses:

412

En injectant une instance de l' ActivatedRouteun peut souscrire à une variété d'observables, y compris un queryParamset un paramsobservable:

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

}

UNE NOTE CONCERNANT LA DÉSABONNEMENT

@Reto et @ codef0rmer avaient très justement souligné que, selon les documents officiels, une méthode unsubscribe()à l'intérieur de la composante onDestroy()n'est pas nécessaire dans ce cas. Cela a été supprimé de mon exemple de code. (voir la boîte d'alerte bleue dans ce tutoriel)

Stephen Paul
la source
2
Je suggère en outre de remplacer l'abonnement par une promesse - dans ce cas particulier. this.activatedRoute.params.toPromise () .then (response => ...) .catch (error => ...);
dec
Où puis-je passer "enabledRoute"?
michali
20
De la documentation officielle: dois-je me désinscrire? 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
redirection angulaire sans déclencher l'abonnement (ou promesse). Je peux voir le rappel oAUth d'origine avec le jeton, mais ensuite il redirige vers la route sans les paramètres de requête et console.log (param) n'est qu'un objet vide.
FlavorScape
1
@Sobhan, oui il y a une différence. L'opérateur switchMap renvoie un observable tandis que l'opérateur d'abonnement permet à l'observateur (notre composant) de voir les éléments finalement émis par un observable. Donc, dans les documents, il y a 2 instances de switchmap utilisées. 1) Ils ont utilisé switchMap pour ajouter une demande de héros. SwitchMap, contrairement à subscribe, garantira que la demande est annulée si l'utilisateur revient sur l'itinéraire tout en récupérant un héros. 2) Un tuyau asynchrone est utilisé. Les canaux asynchrones consomment un observable, il ne faut donc pas s'abonner (le canal asynchrone le fera pour vous).
Stephen Paul
103

Lorsqu'une URL comme celle-ci http://stackoverflow.com?param1=value

Vous pouvez obtenir le param1 par code:

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"];
    }
}
Trung
la source
2
cela signifie-t-il que vous n'avez plus besoin d'ajouter le "/: id" dans le chemin de routeconfig? car j'obtiens "indéfini" quand j'utilise ceci donc je dois encore avoir une erreur quelque part
Axelle
2
Génial. C'est ce que je cherchais car je dois lire les paramètres directement à partir d'une URL de serveur dynamique. Je ne peux pas utiliser la navigation.
The.Bear
37

Même si la question spécifie la version bêta 7 , cette question apparaît également comme premier résultat de recherche sur Google pour les expressions courantes telles que les paramètres de requête angulaires 2 . Pour cette raison, voici une réponse pour le plus récent routeur (actuellement en alpha.7 ).

La façon dont les paramètres sont lus a radicalement changé. Vous devez d'abord injecter une dépendance appelée Routerdans les paramètres de votre constructeur comme:

constructor(private router: Router) { }

et après cela, nous pouvons souscrire aux paramètres de requête sur notre ngOnInitméthode (le constructeur est correct aussi, mais ngOnInitdevrait être utilisé pour la testabilité) comme

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

Dans cet exemple, nous lisons l' ID de paramètre de requête à partir d'une URL comme example.com?id=41.

Il y a encore peu de choses à remarquer:

  1. L'accès à la propriété de paramslike params['id']renvoie toujours une chaîne , qui peut être convertie en nombre en la préfixant avec +.
  2. La raison pour laquelle les paramètres de requête sont récupérés avec observable est qu'il permet de réutiliser la même instance de composant au lieu d'en charger une nouvelle. Chaque fois que le paramètre de requête est modifié, cela provoquera un nouvel événement auquel nous nous sommes abonnés et nous pouvons donc réagir aux changements en conséquence.
Roope Hakulinen
la source
Existe-t-il un moyen d'avoir plusieurs paramètres allant au même membre? Par exemple, j'aimerais que 'id' ou 'identification' aille à this.selectedId.
phandinhlan
@phandinhlan: Eh bien, ce n'est pas vraiment une question liée à Angular 2. Elle peut bien sûr être implémentée, mais vous devez définir la logique vous-même. Fondamentalement, ce que vous voulez faire, c'est d'abord vérifier si la première clé est définie et ensuite seulement en lire la valeur, et sinon, lire la valeur avec une autre clé. Cela pourrait être réalisé avec quelque chose comme if (params.hasOwnProperty('id')) { this.selectedId = params['id'] } else { this.selectedId = params['identification']}.
Roope Hakulinen
Oui, j'ai fini par faire quelque chose comme ça. J'ai juste pensé qu'il y aurait une manière "intégrée" comme: this.selectedId = + params ['id']; this.selectedId = + params ['identification']; Bien sûr, cela n'a aucun sens et ne fonctionne pas.
phandinhlan
28

J'ai vraiment aimé la réponse de @ StevePaul mais nous pouvons faire la même chose sans appel subscribe / unsubscribe.

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
}
codef0rmer
la source
7
la mise en garde bien sûr avec celui-ci est que ce sera la valeur initiale et les changements ultérieurs ne seront pas reflétés. Donc, si vous modifiez les paramètres d'URL par programme dans le cadre de votre logique, c'est quelque chose dont vous devez être conscient
ambidextre
Je ne sais pas si cela a changé avec les versions ultérieures d'Angular, mais je le vois maintenant dans this.activatedRoute.snapshot.queryParams
Michael
21

Pour envoyer des paramètres de requête

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

Pour recevoir des paramètres de requête

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

Source officielle

dddenis
la source
La lecture fonctionne bien, mais elle est sensible à la casse. Comment pouvons-nous le rendre insensible à la casse?
Unnie
12

Salut, vous pouvez utiliser URLSearchParams, vous pouvez en savoir plus à ce sujet ici .

importer:

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

et fonction:

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

Remarque : il n'est pas pris en charge par toutes les plates-formes et semble être dans un état "EXPÉRIMENTAL" par les documents angulaires

Asaf Hananel
la source
2
Ça ne marche pas pour moi. J'ai trouvé que window.location.search inclut le premier point d'interrogation des paramètres de la chaîne de requête. Ainsi, la clé du premier paramètre aura le point d'interrogation ajouté.
AJ Morris
AJ Morris, pour contourner votre problème: if (window.location.search.indexOf('?') == 0){ normalizedQueryString = window.location.search.substring(1); } else { normalizedQueryString = window.location.search; } let params = new URLSearchParams(normalizedQueryString);
ambidextre
URLSearchParams est obsolète. Maintenant, vous pouvez le faire avec ActivatedRoute.
Robert Blasco Villarroya
7

Tout d'abord, ce que j'ai trouvé en travaillant avec Angular2, c'est que l'url avec une chaîne de requête serait /path;query=value1

Pour y accéder dans un composant que vous utilisez Voici donc, mais suit maintenant un bloc de code:

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

Quant à savoir pourquoi il serait supprimé lorsque vous chargez le composant, ce n'est pas un comportement par défaut. J'ai vérifié spécifiquement dans un projet de test propre et je n'ai pas été redirigé ou modifié. S'agit-il d'un itinéraire par défaut ou de quelque chose de spécial concernant le routage?

Lisez à propos du routage avec des chaînes de requête et des paramètres dans le didacticiel Angular2 à https://angular.io/docs/ts/latest/guide/router.html#!#query-parameters

Namirna
la source
Je ne peux pas utiliser des paramètres tels que "; param1 = valeur1; param2 = valeur2", ce lien généré sur un autre site et rediriger sur mon site comme "example.com/auth?code_for_auth=askjfbkajdsbfksajdf"
FireGM
La façon dont le routage est configuré dans Angular2 pour le moment, je ne pense pas que ce soit vraiment possible. Une sorte de solution de contournement sera nécessaire car le routage enfant dépend de l'url de la matrice. Pour autant que je sache au moins. Je l'intercepterais sur mon serveur Web et les transformerais en hack, c'est nul, mais je ne peux pas penser à une autre façon pour le moment
Namirna
Vous n'avez pas la possibilité de demander au site de lien de changer son URL?
Namirna
1
Non. Mais j'ai résolu le problème en
analysant
4
cette solution déconseillée!
7

Vous pouvez obtenir les paramètres de requête lorsqu'ils sont passés dans l'URL en utilisant ActivatedRoute comme indiqué ci-dessous: -

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

}
Saurabh
la source
7

Obtenez les paramètres d'URL en tant qu'objet.

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

Si vous ne souhaitez obtenir le paramètre de requête qu'une seule fois, la meilleure façon est d'utiliser la méthode take afin de ne pas vous soucier de la désinscription. Voici l'extrait simple: -

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

Remarque: Supprimez take (1) si vous souhaitez utiliser des valeurs de paramètres à l'avenir.

Abhishek Chandel
la source
2

c'est maintenant:

this.activatedRoute.queryParams.subscribe((params: Params) => {
  console.log(params);
});
Alan
la source
1
Merci pour cet extrait de code, qui pourrait fournir une aide limitée à court terme. Une explication appropriée améliorerait considérablement sa valeur à long terme en montrant pourquoi il s'agit d'une bonne solution au problème et le rendrait plus utile aux futurs lecteurs ayant d'autres questions similaires. Veuillez modifier votre réponse pour ajouter des explications, y compris les hypothèses que vous avez faites
Shawn C.
1

J'espère que cela aidera quelqu'un d'autre.

La question ci-dessus indique que la valeur du paramètre de requête est nécessaire après la redirection de la page et nous pouvons supposer que la valeur de l'instantané (l'alternative non observable) serait suffisante.

Personne ici n'a mentionné snapshot.paramMap.get dans la documentation officielle .

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

Donc avant de l'envoyer, ajoutez ceci dans le composant d'envoi / redirection:

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

puis redirigez comme l'un ou l'autre (documenté ici ):

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

ou simplement:

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

Assurez-vous que vous l'avez ajouté dans votre module de routage comme indiqué ici :

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

Et enfin, dans votre composant qui doit utiliser le paramètre de requête

  • ajouter des importations (documentées ici ):

    import { Router, ActivatedRoute, ParamMap } from '@angular/router';
  • inject ActivatedRoute

(la documentation importe également switchMap et injecte également Router et HeroService - mais ils sont nécessaires uniquement pour une alternative observable - ils ne sont PAS nécessaires lorsque vous utilisez une alternative de capture instantanée comme dans notre cas):

    constructor(
      private route: ActivatedRoute
    ) {}
  • et obtenez la valeur dont vous avez besoin (documentée ici ):

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

REMARQUE: SI VOUS AJOUTEZ LE MODULE DE ROUTAGE À UN MODULE DE FONCTIONNALITÉS (COMME INDIQUÉ DANS LA DOCUMENTATION) ASSUREZ-VOUS QUE DANS APP.MODULE.ts QUE LE MODULE DE ROUTAGE VIENT AVANT AppRoutingModule (ou tout autre fichier avec des routes d'application au niveau racine) DANS LES IMPORTATIONS: []. AUTREMENT, LES ITINÉRAIRES DE FONCTIONNEMENT NE SERONT PAS TROUVÉS (COMME ILS VIENDRAI APRÈS {path: '**', redirectTo: '/ not-found'} et vous ne verriez que des messages non trouvés).

Ula
la source
1

Il vous suffit d'injecter ActivatedRoute dans le constructeur, puis d'accéder aux paramètres ou aux paramètres de requête par-dessus

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

Dans certains cas, cela ne donne rien dans NgOnInit ... peut-être à cause de l'appel init avant l'initialisation des paramètres dans ce cas, vous pouvez y parvenir en demandant à observable d'attendre un certain temps par la fonction debounceTime (1000)

par exemple =>

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

debounceTime () N'émet une valeur de la source observable qu'après un laps de temps particulier passé sans autre émission de source

Rajiv
la source
0

Vous ne pouvez pas obtenir un paramètre du RouterState s'il n'est pas défini dans la route, donc dans votre exemple, vous devez analyser la chaîne de requête ...

Voici le code que j'ai utilisé:

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

Julien Ricard
la source
0

Requête et chemin (angulaire 8)

Si vous avez une URL comme https://myapp.com/owner/123/show?height=23, utilisez

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

METTRE À JOUR

Dans le cas où lorsque vous utilisez this.router.navigate([yourUrl]);et que vos paramètres de requête sont intégrés dans une yourUrlchaîne, angular code une URL et vous obtenez quelque chose comme ceci https://myapp.com/owner/123/show%3Fheight%323 - et la solution ci-dessus donnera un résultat incorrect ( queryParams sera vide et les paramètres de requête peuvent être collés au dernier paramètre de chemin s'il se trouve à l'extrémité du chemin). Dans ce cas, changez le mode de navigation vers ce

this.router.navigateByUrl(yourUrl);
Kamil Kiełczewski
la source