Qual é a maneira mais concisa de ler parâmetros de consulta no AngularJS?

312

Eu gostaria de ler os valores dos parâmetros de consulta de URL usando AngularJS. Estou acessando o HTML com o seguinte URL:

http://127.0.0.1:8080/test.html?target=bob

Como esperado, location.searché "?target=bob". Para acessar o valor do target , encontrei vários exemplos listados na Web, mas nenhum deles funciona no AngularJS 1.0.0rc10. Em particular, são todos os seguintes undefined:

  • $location.search.target
  • $location.search['target']
  • $location.search()['target']

Alguém sabe o que vai funcionar? (Estou usando $locationcomo parâmetro para o meu controlador)


Atualizar:

Publiquei uma solução abaixo, mas não estou totalmente satisfeito com ela. A documentação do Developer Guide: Angular Services: Using $ location indica o seguinte sobre $location:

Quando devo usar $ location?

Sempre que seu aplicativo precisar reagir a uma alteração no URL atual ou se você desejar alterar o URL atual no navegador.

Para o meu cenário, minha página será aberta a partir de uma página da Web externa com um parâmetro de consulta, por isso não estou "reagindo a uma alteração no URL atual" por si só. Portanto, talvez $locationnão seja a ferramenta certa para o trabalho (para os detalhes feios, veja minha resposta abaixo). Portanto, mudei o título desta pergunta de "Como ler os parâmetros de consulta no AngularJS usando $ location?" para "Qual é a maneira mais concisa de ler parâmetros de consulta no AngularJS?". Obviamente, eu poderia apenas usar javascript e expressão regular para analisar location.search, mas ir para um nível tão baixo para algo tão básico realmente ofende minhas sensibilidades de programador.

Então: existe uma maneira melhor de usar $locationdo que na minha resposta ou existe uma alternativa concisa?

Ellis Whitehead
fonte
1
$ Location.search () ['target'] não deve funcionar?
precisa
Isso não funciona, porque não há hash após o caminho. http://127.0.0.1:8080/test.html#?target=bobfuncionaria, observe o #antes do ?. $locationé um método de roteamento de segundo nível que não é enviado ao servidor.
Daniel F
1
@DanielF @rob, vocês dois estão certos. $location.search()['target']funciona depois de $locationProvider.html5Mode(true)ter sido chamado em um navegador moderno.
Krispy #

Respostas:

199

Você pode injetar $ routeParams (requer ngRoute ) no seu controlador. Aqui está um exemplo dos documentos:

// Given:
// URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
// Route: /Chapter/:chapterId/Section/:sectionId
//
// Then
$routeParams ==> {chapterId:1, sectionId:2, search:'moby'}

EDIT: Você também pode obter e definir parâmetros de consulta com o serviço $ location (disponível em ng), particularmente seu searchmétodo: $ location.search () .

$ routeParams são menos úteis após o carregamento inicial do controlador; $location.search()pode ser chamado a qualquer momento.

Andrew Joslin
fonte
1
Obrigado pela sugestão e link! Eu li a página e também tentei configurar uma amostra de trabalho. No entanto, a abordagem não funcionará para mim, porque realmente não quero usar o roteamento neste caso. No entanto, essa foi uma sugestão útil, e eu a votarei assim que tiver representante de fluxo de pilha suficiente.
Ellis Whitehead
1
Eu diria @ 's resposta pkozlowski.opensource é mais preciso nesta situação
Martín Coll
2
Não é bem .. os parâmetros de consulta estão incluídos no objeto $ routeParams com os parâmetros de rota normais. e você pode lê-los / configurá-los com $ location.search (). Vou acrescentar isso à resposta.
Andrew Joslin
5
Jakub está certo. São coisas diferentes. Quando você usa a "pesquisa" em angular, ela anexa a consulta ao hash (final do URL). A especificação da RFC para o URI afirma que os parâmetros de consulta devem incluir previamente o hash (não anexá-lo). Assim, a "busca" é uma construção que apenas angular extrapolará e interpretará. É por isso que apenas o modo HTML5 funcionará para a solução acima, porque você está delegando todas as solicitações em uma página (no nível do servidor), independentemente do URI real.
Steven Pena
2
isso só funciona se você quiser usar a rota no angularJS!
Windmaomao
189

É bom que você tenha conseguido fazê-lo funcionar com o modo html5, mas também é possível fazê-lo funcionar no modo hashbang.

Você pode simplesmente usar:

$location.search().target

para obter acesso ao parâmetro de pesquisa 'target'.

Para referência, aqui está o jsFiddle em funcionamento: http://web.archive.org/web/20130317065234/http://jsfiddle.net/PHnLb/7/

var myApp = angular.module('myApp', []);

function MyCtrl($scope, $location) {

    $scope.location = $location;
    $scope.$watch('location.search()', function() {
        $scope.target = ($location.search()).target;
    }, true);

    $scope.changeTarget = function(name) {
        $location.search('target', name);
    }
}
<div ng-controller="MyCtrl">

    <a href="#!/test/?target=Bob">Bob</a>
    <a href="#!/test/?target=Paul">Paul</a>
    
    <hr/>    
    URL 'target' param getter: {{target}}<br>
    Full url: {{location.absUrl()}}
    <hr/>
    
    <button ng-click="changeTarget('Pawel')">target=Pawel</button>
    
</div>

pkozlowski.opensource
fonte
2
você precisa dos parênteses em torno de $ location.search ()?
Magne
2
@Magne: sim, você precisa de parênteses, $ location.search é um método docs.angularjs.org/api/ng/service/$location
nandin
4
Não se esqueça que, se você não usar HTML5Mode(true), apenas os parâmetros após # / estarão disponíveis ou serão adicionados ao URL com # / no início.
Sebastian
21
@nandin: Não, você não precisa dos parênteses ao redor $location.search() . Não sei por que essa resposta os coloca lá.
Dan Tao
9
Sinto que @nandin entendeu mal a pergunta "Você precisa de parênteses". Você fazer precisa dos parênteses após pesquisa, mas não os únicos em todo o conjunto de $location.search().
K. Carpenter
56

Para dar uma resposta parcial à minha própria pergunta, aqui está um exemplo de trabalho para navegadores HTML5:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <script src="http://code.angularjs.org/1.0.0rc10/angular-1.0.0rc10.js"></script>
  <script>
    angular.module('myApp', [], function($locationProvider) {
      $locationProvider.html5Mode(true);
    });
    function QueryCntl($scope, $location) {
      $scope.target = $location.search()['target'];
    }
  </script>
</head>
<body ng-controller="QueryCntl">

Target: {{target}}<br/>

</body>
</html>

A chave era ligar $locationProvider.html5Mode(true);como feito acima. Agora funciona ao abrir http://127.0.0.1:8080/test.html?target=bob. Não estou feliz com o fato de que ele não funcionará em navegadores mais antigos, mas posso usar essa abordagem de qualquer maneira.

Uma alternativa que funcionaria com navegadores mais antigos seria encerrar a html5mode(true)chamada e usar o seguinte endereço com barra + hash:

http://127.0.0.1:8080/test.html#/?target=bob

A documentação relevante está no Guia do desenvolvedor: Serviços angulares: usando $ location (estranho que minha pesquisa no google não encontrou isso ...).

Ellis Whitehead
fonte
Obrigado por isso. Eu tenho puxado meu cabelo tentando ler os parâmetros de consulta. Manteve-se "indefinido", como você mencionou acima. O modo de configuração para html5 funcionou.
Sthomps 16/05/2013
O ng-controlleratributo de não deve <body>ser definido como MyApp?
Jago
4
Parece que começando com o Angular 1.3, para usar o html5Mode, você também precisa adicionar uma <base href="https://stackoverflow.com/" />tag ou adicionar requireBase: falseoutro parâmetro à chamada para html5Mode. Detalhes aqui
dae721
17

Isso pode ser feito de duas maneiras:

  1. Usando $routeParams

A solução melhor e recomendada é usar $routeParamsno seu controlador. Requer o ngRoutemódulo a ser instalado.

   function MyController($scope, $routeParams) {
      // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
      // Route: /Chapter/:chapterId/Section/:sectionId
      // $routeParams ==> {chapterId:'1', sectionId:'2', search:'moby'}
      var search = $routeParams.search;
  }
  1. Usando $location.search().

Há uma ressalva aqui. Funcionará apenas no modo HTML5. Por padrão, ele não funciona para o URL que não possui hash ( #).http://localhost/test?param1=abc&param2=def

Você pode fazer isso adicionando #/o URL.http://localhost/test#/?param1=abc&param2=def

$location.search() para retornar um objeto como:

{
  param1: 'abc',
  param2: 'def'
}
Fizer Khan
fonte
5
Obrigado por seu conselho com # /
yonexbat
9

$ location.search () funcionará apenas com o modo HTML5 ativado e apenas no navegador de suporte.

Isso sempre funcionará:

$ window.location.search

Illidan
fonte
6

Apenas para o verão.

Se o seu aplicativo estiver sendo carregado a partir de links externos, o angular não detectará isso como uma alteração de URL, para que $ loaction.search () forneça um objeto vazio. Para resolver isso, é necessário definir o seguinte na configuração do seu aplicativo (app.js)

.config(['$routeProvider', '$locationProvider', function ($routeProvider,     $locationProvider) 
{
   $routeProvider
      .when('/', {
         templateUrl: 'views/main.html',
         controller: 'MainCtrl'
      })
      .otherwise({
         redirectTo: '/'
      });

      $locationProvider.html5Mode(true);
 }]);
sapy
fonte
1
Sim. Era uma dor de encontrar. Obrigado pelo comentário.
Mikeborgh
2

Apenas uma precisão para a resposta de Ellis Whitehead. $locationProvider.html5Mode(true);não funcionará com a nova versão do angularjs sem especificar o URL base do aplicativo com uma <base href="">tag ou definir o parâmetro requireBasecomofalse

Do documento :

Se você configurar $ location para usar html5Mode (history.pushState), precisará especificar o URL base do aplicativo com uma tag ou configurar $ locationProvider para não exigir uma tag base, passando um objeto de definição com requireBase: false para $ locationProvider. html5Mode ():

$locationProvider.html5Mode({
  enabled: true,
  requireBase: false
});
S.Thiongane
fonte
1

você também pode usar $ location. $$ search.yourparameter

thewindev
fonte
18
O $$searché uma variável interna, cuja utilização não é uma boa idéia.
precisa saber é o seguinte
1

isso pode ajudar você

Qual é a maneira mais concisa de ler parâmetros de consulta no AngularJS

// Given:
// URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
// Route: /Chapter/:chapterId/Section/:sectionId
//
// Then
$routeParams ==> {chapterId:1, sectionId:2, search:'moby'}

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <script src="http://code.angularjs.org/1.0.0rc10/angular-1.0.0rc10.js"></script>
  <script>
    angular.module('myApp', [], function($locationProvider) {
      $locationProvider.html5Mode(true);
    });
    function QueryCntl($scope, $location) {
      $scope.target = $location.search()['target'];
    }
  </script>
</head>
<body ng-controller="QueryCntl">

Target: {{target}}<br/>

</body>
</html>

($location.search()).target
Krishna
fonte
1

Descobri que para um SPA o HTML5Mode causa muitos problemas de erro 404, e não é necessário fazer com que $ location.search funcione nesse caso. No meu caso, quero capturar um parâmetro de string de consulta de URL quando um usuário chega ao meu site, independentemente de qual "página" ele vincular inicialmente, e ser capaz de enviá-lo para essa página assim que efetuar o login. essas coisas no app.run

$rootScope.$on('$stateChangeStart', function (e, toState, toParams, fromState, fromParams) {
    if (fromState.name === "") {
        e.preventDefault();
        $rootScope.initialPage = toState.name;
        $rootScope.initialParams = toParams;
        return;
    }
    if ($location.search().hasOwnProperty('role')) {
        $rootScope.roleParameter = $location.search()['role'];
    }
    ...
}

depois, após o login, posso dizer $ state.go ($ rootScope.initialPage, $ rootScope.initialParams)

nuander
fonte
-3

É um pouco tarde, mas acho que seu problema foi o seu URL. Se em vez de

http://127.0.0.1:8080/test.html?target=bob

você tinha

http://127.0.0.1:8080/test.html#/?target=bob

Tenho certeza de que teria funcionado. Angular é realmente exigente quanto ao seu # /

Octavio Kidd
fonte
Isso é apenas se você não estiver ativando o modo HTML5. O # / nem sempre existe nos URLs angulares.
LocalPCGuy
É se você estiver construindo um SPA. Todos os meus URLs têm um #. E HTML5Mode significa 1) 404 na atualização da página e 2) URLs diretos não funcionarão. Parece um preço alto a pagar.
Nuander