Como obter parâmetros de consulta de url no Angular 2?

237

Eu uso angular2.0.0-beta.7. Quando um componente é carregado em um caminho como /path?query=value1ele é redirecionado /path. Por que os parâmetros GET foram removidos? Como posso preservar os parâmetros?

Eu tenho um erro nos roteadores. Se eu tiver uma rota principal como

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

e minha rota filho como

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

então não consigo obter parâmetros no TodoListComponent. Eu consigo

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

mas eu quero o clássico

query params("/my/path?param1=value1&param2=value2")
FireGM
fonte
1
como você especificou @RouteConfigpara isso path?
Pankaj Parkar 28/02
Encontrei um erro. Eu tenho rota principal e rota filho e se eu tiver rota principal como {caminho: '/ todos / ...', nome: 'TodoMain', componente: TodoMainComponent} e rota filho {caminho: '/', componente: TodoListComponent, nome: 'TodoList', useAsDefault: true}, não funciona e redireciona para url sem parâmetros de consulta.
FireGM

Respostas:

412

Ao injetar uma instância de ActivatedRouteum, é possível assinar uma variedade de observáveis, incluindo um queryParamse um paramsobservável:

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

}

UMA NOTA RELATIVA À INSCRIÇÃO

@Reto e @ codef0rmer apontaram, com razão, que, de acordo com os documentos oficiais, um método unsubscribe()dentro dos componentes onDestroy()é desnecessário neste caso. Isso foi removido do meu exemplo de código. (veja a caixa de alerta azul neste tutorial)

Stephen Paul
fonte
2
Sugiro ainda substituir a assinatura por uma promessa - neste caso especial. this.activatedRoute.params.toPromise () .then (response => ...) .catch (error => ...);
dez
Onde posso passar o "enabledRoute"?
Michali
20
A partir da documentação oficial: Preciso cancelar a inscrição? 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
redirecionamentos angulares sem disparar a assinatura (ou promessa). Eu posso ver o retorno de chamada oAUth original com o token, mas ele será redirecionado para a rota sem os parâmetros de consulta e o console.log (param) é apenas um objeto vazio.
FlavorScape 04/12/16
1
@ Shan, sim, há uma diferença. O operador switchMap retorna um Observable enquanto o operador de inscrição permite que o observador (nosso componente) veja os itens sendo finalmente emitidos por um Observable. Portanto, nos documentos há duas instâncias de switchmap sendo empregadas. 1) Eles usaram o switchMap para anexar uma solicitação de heróis. O SwitchMap, diferentemente da assinatura, garantirá que a solicitação seja cancelada caso o usuário navegue novamente para a rota enquanto ainda recupera um herói. 2) Um tubo assíncrono é usado. Os tubos assíncronos consomem um observável; portanto, não é necessário se inscrever (o tubo assíncrono fará isso por você).
Stephen Paul
103

Quando um URL como este http://stackoverflow.com?param1=value

Você pode obter o param1 pelo código a seguir:

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
fonte
2
isso significa que você não precisa adicionar o "/: id" no caminho routeconfig? porque eu recebo "indefinido" quando eu uso isso para que eu ainda deve ter um lugar de erro
Axelle
2
Ótimo. Era isso que eu estava procurando, porque eu preciso ler os parâmetros diretamente de um URL de servidor dinâmico. Não consigo usar a navegação.
TheBear
37

Embora a pergunta especifique a versão beta 7 , ela também aparece como o principal resultado de pesquisa no Google para frases comuns, como parâmetros de consulta angular 2 . Por esse motivo, aqui está uma resposta para o roteador mais recente (atualmente em alpha.7 ).

A maneira como os parâmetros são lidos mudou dramaticamente. Primeiro, você precisa injetar a dependência chamada Routernos parâmetros do construtor, como:

constructor(private router: Router) { }

e depois disso, podemos assinar os parâmetros de consulta em nosso ngOnInitmétodo (o construtor também está bom, mas ngOnInitdeve ser usado para testabilidade) como

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

Neste exemplo, lemos o parâmetro de consulta id da URL como example.com?id=41.

Ainda há poucas coisas a serem observadas:

  1. Acessar a propriedade paramslike params['id']sempre retorna uma string , e isso pode ser convertido em número prefixando-o com +.
  2. O motivo pelo qual os parâmetros de consulta são buscados com observável é que ele permite reutilizar a mesma instância do componente em vez de carregar uma nova. Cada vez que o parâmetro de consulta é alterado, ele causa um novo evento no qual assinamos e, portanto, podemos reagir às alterações de acordo.
Roope Hakulinen
fonte
Existe uma maneira de ter vários parâmetros indo para o mesmo membro? Por exemplo, eu gostaria que 'id' ou 'identificação' fosse para this.selectedId.
21416 Phantinhlan
@phandinhlan: Bem, isso não é realmente uma questão relacionada ao Angular 2. É claro que pode ser implementado, mas você mesmo precisa definir a lógica. Basicamente, o que você deseja fazer é verificar primeiro se a primeira chave está definida e somente então ler o valor dela; caso contrário, leia o valor com outra chave. Isso poderia ser alcançado com algo parecido if (params.hasOwnProperty('id')) { this.selectedId = params['id'] } else { this.selectedId = params['identification']}.
Roope Hakulinen
Sim, acabei fazendo algo assim. Eu apenas pensei que haveria alguma maneira "construída" como: this.selectedId = + params ['id']; this.selectedId = + params ['identificação']; Claro que isso não faz sentido e não funciona.
phandinhlan
28

Gostei muito da resposta do @ StevePaul, mas podemos fazer o mesmo sem uma chamada externa de inscrição / cancelamento de inscrição.

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
fonte
7
a ressalva, é claro, com este é que será o valor inicial e as alterações subsequentes não serão refletidas. Portanto, se você estiver alterando os parâmetros de URL programaticamente como parte de sua lógica, é algo que você precisa estar ciente
ambidestro
Não sei se isso mudou com versões posteriores do Angular, mas agora vê-lo em this.activatedRoute.snapshot.queryParams
Michael
21

Para enviar parâmetros de consulta

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

Para receber parâmetros de consulta

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

Fonte oficial

dddenis
fonte
A leitura funciona bem, mas diferencia maiúsculas de minúsculas. Como podemos torná-lo sem distinção entre maiúsculas e minúsculas?
Unnie
12

Olá, você pode usar URLSearchParams, pode ler mais sobre isso aqui .

importar:

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

e função:

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

Aviso : não é suportado por todas as plataformas e parece estar no estado "EXPERIMENTAL" por documentos angulares

Asaf Hananel
fonte
2
Isso não funciona para mim. Descobri que window.location.search inclui o ponto de interrogação principal dos parâmetros da string de consulta. Portanto, a chave do primeiro parâmetro terá o ponto de interrogação anexado.
AJ Morris
AJ Morris, para contornar o problema: if (window.location.search.indexOf('?') == 0){ normalizedQueryString = window.location.search.substring(1); } else { normalizedQueryString = window.location.search; } let params = new URLSearchParams(normalizedQueryString);
ambidestro 25/08
URLSearchParams está obsoleto. Agora você pode fazer isso com o ActivatedRoute.
Robert Blasco Villarroya
7

Primeiro, o que eu descobri trabalhando com o Angular2 é que o URL com uma string de consulta seria /path;query=value1

Para acessá-lo em um componente que você usa, Então é isso, mas agora segue um bloco de código:

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

Quanto ao motivo pelo qual ele seria removido quando você carregasse o componente, esse não é o comportamento padrão. Fiz uma verificação específica em um projeto de teste limpo e não fui redirecionado ou alterado. É uma rota padrão ou algo mais especial sobre o roteamento?

Leia sobre roteamento com seqüências de caracteres e parâmetros de consulta no Tutorial do Angular2 em https://angular.io/docs/ts/latest/guide/router.html#!#query-parameters

Namirna
fonte
Eu não posso usar parâmetros como "; param1 = valor1; param2 = valor2", este link foi gerado em outro site e redirecionado para o meu site como "example.com/auth?code_for_auth=askjfbkajdsbfksajdf"
FireGM
Da maneira como o roteamento está configurado no Angular2 no momento, não acho que seja possível. Será necessário algum tipo de solução alternativa, pois o roteamento filho depende do URL da matriz. Pelo que sei, pelo menos. Eu interceptá-lo no meu servidor web e transformá-los como um hack, suga mas eu não posso pensar de outra maneira no momento
Namirna
Você não tem a possibilidade de solicitar que o site de link altere o URL deles?
Namirna
1
Não. Mas eu resolvi o problema simplesmente
analisando
4
esta solução foi preterida!
7

Você pode obter os parâmetros de consulta quando transmitidos na URL usando o ActivatedRoute, conforme indicado abaixo: -

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
fonte
7

Obter parâmetros de URL como um objeto.

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

Se você deseja obter o parâmetro de consulta apenas uma vez, a melhor maneira é usar o método take , para que você não precise se preocupar com a desinscrição. Aqui está o trecho simples: -

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

Nota: Remova a captura (1) se desejar usar os valores dos parâmetros no futuro.

Abhishek Chandel
fonte
2

agora é:

this.activatedRoute.queryParams.subscribe((params: Params) => {
  console.log(params);
});
Alan
fonte
1
Obrigado por este snippet de código, que pode fornecer ajuda limitada a curto prazo. Uma explicação adequada melhoraria bastante seu valor a longo prazo, mostrando por que essa é uma boa solução para o problema e a tornaria mais útil para futuros leitores com outras perguntas semelhantes. Por favor edite sua resposta para adicionar alguma explicação, incluindo as suposições que você fez
Shawn C.
1

Espero que ajude alguém.

A pergunta acima afirma que o valor do parâmetro de consulta é necessário após o redirecionamento da página e podemos assumir que o valor do instantâneo (a alternativa não observável) seria suficiente.

Ninguém aqui mencionou snapshot.paramMap.get a partir da documentação oficial .

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

Portanto, antes de enviá-lo, adicione isso no componente de envio / redirecionamento:

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

em seguida, redirecione como (documentado aqui ):

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

ou simplesmente:

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

Verifique se você adicionou isso no seu módulo de roteamento, conforme documentado aqui :

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

E, finalmente, no seu componente que precisa usar o parâmetro de consulta

  • adicione importações (documentadas aqui ):

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

(a documentação também importa switchMap e também injeta Router e HeroService - mas são necessários apenas para alternativa observável - NÃO são necessários quando você usa a alternativa de instantâneo, como no nosso caso):

    constructor(
      private route: ActivatedRoute
    ) {}
  • e obtenha o valor necessário (documentado aqui ):

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

OBSERVAÇÃO: SE VOCÊ ADICIONAR O MÓDULO DE ROTAÇÃO A UM MÓDULO DE RECURSO (MOSTRADO NA DOCUMENTAÇÃO) VERIFIQUE QUE EM APP.MODULE.ts ESTE MÓDULO DE ROTAÇÃO SEJA ANTES DO AppRoutingModule (ou outro arquivo com rotas de aplicativos no nível raiz) EM IMPORTAÇÕES: []. OUTRAS ROTAS DE RECURSOS NÃO SERÃO ENCONTRADAS (COMO VIRAM APÓS {path: '**', redirectTo: '/ not-found'} e você verá apenas a mensagem não encontrada).

Ula
fonte
1

Você só precisa injetar ActivatedRoute no construtor e acessar os parâmetros ou queryParams sobre ele

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

Em alguns casos, ele não fornece nada no NgOnInit ... talvez por causa da chamada init antes da inicialização dos parâmetros, nesse caso, você pode conseguir isso pedindo ao observável que aguarde algum tempo pela função debounceTime (1000)

por exemplo =>

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

debounceTime () Emite um valor da fonte observável somente após um período de tempo específico passado sem outra emissão de origem

Rajiv
fonte
0

Você não pode obter um parâmetro do RouterState se ele não estiver definido na rota; portanto, no seu exemplo, você deve analisar a string de consulta ...

Aqui está o código que eu usei:

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
fonte
0

Consulta e caminho (Angular 8)

Se você tiver um URL como https://myapp.com/owner/123/show?height=23 , use

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

ATUALIZAR

Caso você use this.router.navigate([yourUrl]);e seus parâmetros de consulta sejam incorporados em yourUrlstring, o angular codifica um URL e você obtém algo como este https://myapp.com/owner/123/show%3Fheight%323 - e a solução acima dará um resultado errado ( queryParams estará vazio e os parâmetros de consulta podem ser colados no último parâmetro do caminho, se estiver no final do caminho). Nesse caso, altere o modo de navegação para este

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