Jaki jest najbardziej zwięzły sposób odczytywania parametrów zapytania w AngularJS?

312

Chciałbym odczytać wartości parametrów zapytania URL za pomocą AngularJS. Uzyskuję dostęp do kodu HTML za pomocą następującego adresu URL:

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

Zgodnie z oczekiwaniami location.searchjest "?target=bob". Aby uzyskać dostęp do wartości celu , znalazłem różne przykłady wymienione w Internecie, ale żaden z nich nie działa w AngularJS 1.0.0rc10. W szczególności są to undefined:

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

Czy ktoś wie, co będzie działać? (Używam $locationjako parametru do mojego kontrolera)


Aktualizacja:

Poniżej zamieściłem rozwiązanie, ale nie jestem do końca z niego zadowolony. Dokumentacja na stronie Developer Guide: Angular Services: Korzystanie z $ location zawiera następujące informacje na temat $location:

Kiedy powinienem użyć $ location?

Za każdym razem, gdy aplikacja musi zareagować na zmianę bieżącego adresu URL lub jeśli chcesz zmienić bieżący adres URL w przeglądarce.

W moim scenariuszu moja strona zostanie otwarta z zewnętrznej strony internetowej z parametrem zapytania, więc per se nie reaguję na zmianę bieżącego adresu URL. Więc może $locationnie jest odpowiednie narzędzie do pracy (brzydkie szczegóły, patrz moja odpowiedź poniżej). Dlatego zmieniłem tytuł tego pytania z „Jak odczytać parametry zapytania w AngularJS za pomocą $ location?” na „Jaki jest najbardziej zwięzły sposób odczytywania parametrów zapytania w AngularJS?”. Oczywiście, mógłbym po prostu użyć javascript i wyrażeń regularnych do parsowania location.search, ale przejście do niskiego poziomu dla czegoś tak podstawowego naprawdę obraża moją wrażliwość programisty.

Więc: czy jest lepszy sposób na użycie $locationniż w mojej odpowiedzi, czy też jest zwięzła alternatywa?

Ellis Whitehead
źródło
1
Czy $ location.search () ['target'] nie powinno działać?
okradać
To nie działa, ponieważ po ścieżce nie ma skrótu. http://127.0.0.1:8080/test.html#?target=bobbędzie działać, zwróć uwagę na #wcześniej ?. $locationto metoda routingu drugiego poziomu, która nie jest wysyłana do serwera.
Daniel F
1
@DanielF @rob, oboje macie rację. $location.search()['target']działa po $locationProvider.html5Mode(true)został wywołany w nowoczesnej przeglądarce.
krispy,

Odpowiedzi:

199

Możesz wstrzyknąć $ routeParams (wymaga ngRoute ) do swojego kontrolera. Oto przykład z dokumentów:

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

EDYCJA: Możesz również uzyskać i ustawić parametry zapytania za pomocą usługi $ location service (dostępna w ng), w szczególności jej searchmetody: $ location.search () .

$ routeParams są mniej przydatne po początkowym załadowaniu kontrolera; $location.search()można zadzwonić w dowolnym momencie.

Andrew Joslin
źródło
1
Dzięki za sugestię i link! Przeczytałem stronę, a także próbowałem skonfigurować działającą próbkę. Jednak podejście to nie zadziała, ponieważ tak naprawdę nie chcę używać routingu w tym przypadku. Była to jednak pomocna sugestia i będę ją głosować, gdy będę mieć wystarczającą liczbę powtórzeń przepełnienia stosu.
Ellis Whitehead,
1
Powiedziałbym, że odpowiedź @ pkozlowski.opensource jest bardziej dokładna w tej sytuacji
Martín Coll
2
Niezupełnie… parametry zapytania są zawarte w obiekcie $ routeParams z normalnymi parametrami trasy. i możesz je odczytać / ustawić za pomocą $ location.search (). Dodam to do odpowiedzi.
Andrew Joslin
5
Jakub ma rację. To są różne rzeczy. Kiedy używasz „wyszukiwania” w kanale kątowym, dodaje zapytanie do skrótu (koniec adresu URL). Specyfikacja RFC dla identyfikatora URI stwierdza, że ​​parametry zapytania powinny poprzedzać (a nie dołączać) skrót. Zatem „wyszukiwanie” jest konstrukcją, która tylko kątowa będzie ekstrapolować i interpretować. Właśnie dlatego w powyższym rozwiązaniu działa tylko tryb HTML5, ponieważ delegujesz wszystkie żądania na jedną stronę (na poziomie serwera) niezależnie od faktycznego identyfikatora URI.
Steven Pena
2
działa to tylko wtedy, gdy chcesz używać trasy w angularJS!
windmaomao
189

Dobrze, że udało ci się uruchomić go w trybie HTML5, ale można również sprawić, aby działał w trybie hashbang.

Możesz po prostu użyć:

$location.search().target

aby uzyskać dostęp do parametru wyszukiwania „docelowego”.

Dla odniesienia, oto działający 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
źródło
2
potrzebujesz nawiasów wokół $ location.search ()?
Magne
2
@Magne: tak, potrzebujesz nawiasów, $ location.search to metoda docs.quarejs.org/api/ng/service/$location
nandin
4
Nie zapominaj, że jeśli nie używasz, HTML5Mode(true)to tylko parametry po # / są dostępne lub zostaną dodane do adresu z # / na początku.
Sebastian
21
@ nandin: Nie, nie potrzebujesz nawiasów w pobliżu $location.search() . Nie jestem pewien, dlaczego ta odpowiedź ich tam umieszcza.
Dan Tao
9
Wydaje mi się, że @nandin źle zrozumiał pytanie „Czy potrzebujesz nawiasów”. Ci zrobić potrzebne nawiasach po wyszukiwania, ale nie te, które na całym całości $location.search().
K. Carpenter
56

Aby udzielić częściowej odpowiedzi na moje pytanie, oto działająca próbka dla przeglądarek 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>

Kluczem było zadzwonić, $locationProvider.html5Mode(true);jak opisano powyżej. Teraz działa podczas otwierania http://127.0.0.1:8080/test.html?target=bob. Nie podoba mi się to, że nie będzie działać w starszych przeglądarkach, ale i tak mogę skorzystać z tego podejścia.

Alternatywą, która działałaby w starszych przeglądarkach, byłoby porzucenie html5mode(true)połączenia i użycie następującego adresu z krzyżykiem + ukośnikiem:

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

Odpowiednia dokumentacja znajduje się w Podręczniku programisty: Angular Services: Korzystanie z $ location (dziwne, że moje wyszukiwanie w Google nie znalazło tego ...).

Ellis Whitehead
źródło
Dzięki za to. Wyciągam włosy, próbując odczytać parametry zapytania. Utrzymywano „niezdefiniowany”, jak wspomniano powyżej. Ustawienie trybu na HTML5 działało.
sthomps
Czy nie należy ustawić ng-controlleratrybutu ? <body>MyApp
Jago,
4
Wygląda na to, że zaczynając od Angular 1.3, aby użyć html5Mode, musisz albo dodać <base href="https://stackoverflow.com/" />tag, albo dodać requireBase: falsejako inny parametr do wywołania html5Mode. Szczegóły tutaj
dae721,
17

Można to zrobić na dwa sposoby:

  1. Za pomocą $routeParams

Najlepszym i zalecanym rozwiązaniem jest użycie go $routeParamsw kontrolerze. Wymaga zainstalowania ngRoutemodułu.

   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. Korzystanie $location.search().

Jest tutaj zastrzeżenie. Będzie działać tylko w trybie HTML5. Domyślnie nie działa dla adresu URL, który nie zawiera hash ( #)http://localhost/test?param1=abc&param2=def

Możesz sprawić, by działało, dodając #/adres URL.http://localhost/test#/?param1=abc&param2=def

$location.search() aby zwrócić obiekt taki jak:

{
  param1: 'abc',
  param2: 'def'
}
Fizer Khan
źródło
5
Dzięki za radę z # /
yonexbat
9

$ location.search () będzie działać tylko przy włączonym trybie HTML5 i tylko w obsługiwanej przeglądarce.

Działa to zawsze:

$ window.location.search

Illidan
źródło
6

Tylko na lato.

Jeśli twoja aplikacja jest ładowana z zewnętrznych linków, to kątowy nie wykryje tego jako zmiany adresu URL, więc $ loaction.search () da ci pusty obiekt. Aby rozwiązać ten problem, musisz skonfigurować następujące opcje w konfiguracji aplikacji (app.js)

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

      $locationProvider.html5Mode(true);
 }]);
sapy
źródło
1
Tak. To był trudny do znalezienia. Dziękuję za komentarz.
mikeborgh
2

Tylko precyzja do odpowiedzi Ellisa Whitehead'a. $locationProvider.html5Mode(true);nie będzie działać z nową wersją angularjs bez określenia podstawowego adresu URL aplikacji za pomocą <base href="">znacznika lub ustawienia parametru requireBasenafalse

Z dokumentu :

Jeśli skonfigurujesz $ location, aby używało html5Mode (history.pushState), musisz określić podstawowy adres URL aplikacji za pomocą znacznika lub skonfigurować $ locationProvider, aby nie wymagał znacznika podstawowego, przekazując obiekt definicji z wymaganiemBase: false do $ locationProvider. html5Mode ():

$locationProvider.html5Mode({
  enabled: true,
  requireBase: false
});
S.Thiongane
źródło
1

możesz także użyć $ location. $$ search.yourparameter

thewindev
źródło
18
$$searchJest zmienna wewnętrzna, których użycie nie jest taki dobry pomysł.
kumarharsh
1

to może ci pomóc

Jaki jest najbardziej zwięzły sposób odczytywania parametrów zapytania w 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
źródło
1

Odkryłem, że dla SPA HTML5Mode powoduje wiele problemów z błędem 404 i nie jest konieczne, aby $ location.search działał w tym przypadku. W moim przypadku chcę przechwycić parametr ciągu zapytania adresu URL, gdy użytkownik odwiedza moją witrynę, niezależnie od tego, do której „strony” początkowo prowadzi łącze, ORAZ móc wysyłać je na tę stronę po zalogowaniu. Więc po prostu przechwytuję wszystkie te rzeczy w 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'];
    }
    ...
}

potem po zalogowaniu mogę powiedzieć $ state.go ($ rootScope.initialPage, $ rootScope.initialParams)

nuander
źródło
-3

Jest trochę późno, ale myślę, że twoim problemem był adres URL. Jeśli zamiast

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

miałeś

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

Jestem pewien, że to by zadziałało. Angular jest bardzo wybredny w kwestii swojego # /

Octavio Kidd
źródło
Dzieje się tak tylko wtedy, gdy nie włączasz trybu HTML5. # / Nie zawsze jest dostępny w Angular URL.
LocalPCGuy
To jest, jeśli budujesz SPA. Wszystkie moje adresy URL mają #. A HTML5Mode oznacza 1) 404 odświeżanie strony i 2) bezpośrednie adresy URL nie będą działać. Wydaje się, że trzeba zapłacić wysoką cenę.
nuander