Какой самый краткий способ прочитать параметры запроса в AngularJS?

312

Я хотел бы прочитать значения параметров запроса URL, используя AngularJS. Я получаю доступ к HTML со следующего URL:

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

Как и ожидалось, location.searchесть "?target=bob". Для доступа к значению target я нашел несколько примеров в Интернете, но ни один из них не работает в AngularJS 1.0.0rc10. В частности, это все undefined:

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

Кто-нибудь знает, что будет работать? (Я использую $locationв качестве параметра для моего контроллера)


Обновить:

Я разместил решение ниже, но я не совсем доволен им. Документация в Руководстве разработчика: Angular Services: использование $ location гласит следующее $location:

Когда я должен использовать $ location?

Каждый раз, когда ваше приложение должно реагировать на изменение текущего URL или если вы хотите изменить текущий URL в браузере.

В моем случае моя страница будет открыта с внешней веб-страницы с параметром запроса, поэтому я не "реагирую на изменение текущего URL" как таковой. Так что, возможно, $locationэто не тот инструмент для работы (подробности см. Ниже). Поэтому я изменил название этого вопроса с «Как читать параметры запроса в AngularJS, используя $ location?» на «Какой самый краткий способ прочитать параметры запроса в AngularJS?». Очевидно, что я мог бы просто использовать javascript и регулярные выражения для разбора location.search, но переход на этот низкоуровневый уровень для чего-то такого базового действительно оскорбляет мои чувства программиста.

Итак: есть ли лучший способ использовать, $locationчем я в своем ответе, или есть краткая альтернатива?

Эллис Уайтхед
источник
1
Разве $ location.search () ['target'] не должен работать?
ограбить
Это не работает, потому что после пути нет хеша. http://127.0.0.1:8080/test.html#?target=bobбудет работать, обратите внимание, #прежде чем ?. $locationэто метод маршрутизации второго уровня, который не отправляется на сервер.
Даниэль Ф
1
@DanielF @rob, вы оба правы. $location.search()['target']работает после того, $locationProvider.html5Mode(true)как был вызван в современном браузере.
Криспи

Ответы:

199

Вы можете добавить $ routeParams (требуется ngRoute ) в свой контроллер. Вот пример из документации:

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

РЕДАКТИРОВАТЬ: Вы также можете получить и установить параметры запроса с помощью службы $ location (доступной в ng), особенно ее searchметода: $ location.search () .

$ routeParams менее полезны после начальной загрузки контроллера; $location.search()можно вызвать в любое время.

Эндрю Джослин
источник
1
Спасибо за предложение и ссылку! Я прочитал страницу и также попытался настроить рабочий образец. Тем не менее, подход не сработает для меня, потому что я действительно не хочу использовать маршрутизацию в этом случае. Тем не менее, это было полезное предложение, и я оповестю его, как только у меня будет достаточно стэкаповерпла.
Эллис Уайтхед
1
Я бы сказал, что ответ @ pkozlowski.opensource более точен в этой ситуации
Мартин Колл
2
Не совсем .. Параметры запроса включены в объект $ routeParams с обычными параметрами маршрута. и вы можете прочитать их / установить их с помощью $ location.search (). Я добавлю это к ответу.
Эндрю Джослин
5
Якуб прав. Это разные вещи. Когда вы используете «поиск» в angular, он добавляет запрос к хешу (конец URL). В спецификации RFC для URI указано, что параметры запроса должны предшествовать (а не добавлять) хэш. Таким образом, «поиск» является конструкцией, которая только угловая будет экстраполировать и интерпретировать. Вот почему для решения выше будет работать только режим HTML5, поскольку вы делегируете все запросы одной странице (на уровне сервера) независимо от фактического URI.
Стивен Пена
2
это работает только если вы хотите использовать route в angularJS!
windmaomao
189

Хорошо, что вам удалось заставить его работать в режиме html5, но также можно заставить его работать в режиме hashbang.

Вы можете просто использовать:

$location.search().target

чтобы получить доступ к поисковому параметру «target».

Для справки вот рабочий jsFiddle: 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
источник
2
вам нужны скобки вокруг $ location.search ()?
Магне
2
@Magne: да, вам нужны круглые скобки, $ location.search - это метод docs.angularjs.org/api/ng/service/$location
nandin,
4
Не забывайте, что если вы не используете, HTML5Mode(true)тогда доступны только параметры после # / или добавляются в URL с # / в начале.
Себастьян
21
@nandin: Нет, вы не нужны круглые скобки вокруг $location.search() . Я не уверен, почему этот ответ помещает их туда.
Дан Тао
9
Я чувствую, что @nandin неправильно понял вопрос «Вам нужны скобки». Вы делаете нужны круглые скобки после поиска, но не те , вокруг полноты $location.search().
К. Карпентер
56

Чтобы дать частичный ответ на мой собственный вопрос, вот рабочий пример для браузеров 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>

Ключ должен был позвонить $locationProvider.html5Mode(true);как сделано выше. Теперь работает при открытии http://127.0.0.1:8080/test.html?target=bob. Я не рад тому факту, что он не будет работать в старых браузерах, но я мог бы использовать этот подход в любом случае.

Альтернативой, которая работала бы со старыми браузерами, было бы отбросить html5mode(true)вызов и использовать вместо него следующий адрес с hash + slash:

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

Соответствующая документация находится в Руководстве разработчика: Angular Services: использование $ location (странно, что мой поиск в Google не нашел этого ...).

Эллис Уайтхед
источник
Спасибо за это. Я выдернул свои волосы, пытаясь прочитать в параметрах запроса. Продолжал получать «неопределенный», как вы упоминали выше. Настройка режима на html5 сработала.
sthomps
Не должен ли ng-controllerатрибут <body>быть установлен в MyApp?
Яго
4
Похоже, начиная с Angular 1.3, чтобы использовать html5Mode, вам также нужно либо добавить <base href="https://stackoverflow.com/" />тег, либо добавить в requireBase: falseкачестве другого параметра вызов html5Mode. Подробности здесь
dae721
17

Это можно сделать двумя способами:

  1. С помощью $routeParams

Лучшее и рекомендуемое решение - использовать $routeParamsв вашем контроллере. Требует установки ngRouteмодуля.

   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. Используя $location.search().

Здесь есть оговорка. Он будет работать только в режиме HTML5. По умолчанию он не работает для URL, в котором нет hash ( #)http://localhost/test?param1=abc&param2=def

Вы можете заставить это работать, добавляя #/в URL.http://localhost/test#/?param1=abc&param2=def

$location.search() вернуть объект как:

{
  param1: 'abc',
  param2: 'def'
}
Физер Хан
источник
5
Спасибо за ваш совет с # /
yonexbat
9

$ location.search () будет работать только при включенном режиме HTML5 и только при поддержке браузера.

Это будет работать всегда:

$ window.location.search

Иллидан
источник
6

Просто подвести итог.

Если ваше приложение загружается из внешних ссылок, то angular не обнаружит это как изменение URL, поэтому $ loaction.search () выдаст вам пустой объект. Чтобы решить эту проблему, вам нужно установить следующее в вашем приложении config (app.js)

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

      $locationProvider.html5Mode(true);
 }]);
sapy
источник
1
Ага. Это было больно найти. Спасибо за комментарий.
Майкборг
2

Просто точность ответа Эллис Уайтхед. $locationProvider.html5Mode(true);не будет работать с новой версией angularjs без указания базового URL-адреса для приложения с <base href="">тегом или установки параметра requireBaseнаfalse

Из документа :

Если вы конфигурируете $ location для использования html5Mode (history.pushState), вам нужно указать базовый URL-адрес для приложения с тегом или настроить $ locationProvider, чтобы он не требовал использования базового тега, передавая объект определения с помощью requireBase: false для $ locationProvider. html5Mode ():

$locationProvider.html5Mode({
  enabled: true,
  requireBase: false
});
S.Thiongane
источник
1

Вы также можете использовать $ location. $$ search.yourparameter

thewindev
источник
18
$$searchВнутренняя переменная, использование которой не является такой хорошей идеей.
kumarharsh
1

это может помочь тебе

Какой самый краткий способ прочитать параметры запроса в 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
Кришна
источник
1

Я обнаружил, что для SPA HTML5Mode вызывает много проблем с ошибкой 404, и в этом случае нет необходимости заставлять $ location.search работать. В моем случае я хочу получить параметр строки URL-запроса, когда пользователь заходит на мой сайт, независимо от того, на какую «страницу» они изначально ссылаются, и иметь возможность отправить их на эту страницу после входа в систему. Поэтому я просто собираю все этот материал в 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'];
    }
    ...
}

затем, после входа в систему, я могу сказать $ state.go ($ rootScope.initialPage, $ rootScope.initialParams)

nuander
источник
-3

Уже немного поздно, но я думаю, что вашей проблемой был ваш URL. Если вместо

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

у вас

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

Я уверен, что это сработало бы. Angular действительно требователен к своему # /

Октавио Кидд
источник
Это только если вы не включаете режим HTML5. # / Не всегда есть в угловых URL.
LocalPCGuy
Это если вы строите SPA. Все мои URL имеют #. А HTML5Mode означает 1) 404 при обновлении страницы и 2) прямые URL не будут работать. Похоже на высокую цену.
Нуандер