Was ist die prägnanteste Methode zum Lesen von Abfrageparametern in AngularJS?

312

Ich möchte die Werte von URL-Abfrageparametern mit AngularJS lesen. Ich greife mit der folgenden URL auf den HTML-Code zu:

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

Wie erwartet location.searchist "?target=bob". Für den Zugriff auf den Wert von target habe ich verschiedene Beispiele im Web gefunden, aber keines davon funktioniert in AngularJS 1.0.0rc10. Insbesondere sind alle die folgenden undefined:

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

Weiß jemand was funktionieren wird? (Ich verwende $locationals Parameter für meinen Controller)


Aktualisieren:

Ich habe unten eine Lösung veröffentlicht, bin aber nicht ganz zufrieden damit. In der Dokumentation im Entwicklerhandbuch: Angular Services: Verwenden von $ location wird Folgendes beschrieben $location:

Wann sollte ich $ location verwenden?

Jedes Mal, wenn Ihre Anwendung auf eine Änderung der aktuellen URL reagieren muss oder wenn Sie die aktuelle URL im Browser ändern möchten.

In meinem Szenario wird meine Seite von einer externen Webseite mit einem Abfrageparameter geöffnet, sodass ich nicht per se auf eine Änderung der aktuellen URL reagiere. Vielleicht $locationist es nicht das richtige Werkzeug für den Job (für die hässlichen Details siehe meine Antwort unten). Ich habe daher den Titel dieser Frage von "Wie lese ich Abfrageparameter in AngularJS mit $ location?" Geändert. zu "Was ist die prägnanteste Methode zum Lesen von Abfrageparametern in AngularJS?". Natürlich könnte ich nur Javascript und reguläre Ausdrücke zum Parsen verwenden location.search, aber wenn ich für etwas so Grundlegendes auf diese niedrige Ebene gehe, beleidigt dies wirklich die Sensibilität meines Programmierers.

Also: Gibt es einen besseren Weg $locationals ich in meiner Antwort oder gibt es eine prägnante Alternative?

Ellis Whitehead
quelle
1
Sollte $ location.search () ['target'] nicht funktionieren?
Rob
Dies funktioniert nicht, da nach dem Pfad kein Hash steht. http://127.0.0.1:8080/test.html#?target=bobwürde funktionieren, beachte das #vor dem ?. $locationist eine Routing-Methode der zweiten Ebene, die nicht an den Server gesendet wird.
Daniel F
1
@ DanielF @rob, ihr habt beide recht. $location.search()['target']funktioniert nachdem $locationProvider.html5Mode(true)in einem modernen Browser aufgerufen wurde.
Krispy

Antworten:

199

Sie können $ routeParams (erfordert ngRoute ) in Ihren Controller einfügen . Hier ist ein Beispiel aus den Dokumenten:

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

BEARBEITEN: Sie können Abfrageparameter auch mit dem Dienst $ location (verfügbar in ng) abrufen und festlegen , insbesondere mit der searchMethode $ location.search () .

$ routeParams sind nach dem ersten Laden des Controllers weniger nützlich. $location.search()kann jederzeit aufgerufen werden.

Andrew Joslin
quelle
1
Danke für den Vorschlag und Link! Ich habe die Seite gelesen und auch versucht, ein Arbeitsprobe einzurichten. Der Ansatz wird jedoch für mich nicht funktionieren, da ich in diesem Fall wirklich kein Routing verwenden möchte. Dies war dennoch ein hilfreicher Vorschlag, und ich werde ihn verbessern, sobald ich genug Stackoverflow-Mitarbeiter habe.
Ellis Whitehead
1
Ich würde sagen, dass die Antwort von @ pkozlowski.opensource in dieser Situation genauer ist
Martín Coll
2
Nicht ganz .. Abfrageparameter sind im $ routeParams-Objekt mit den normalen Routenparametern enthalten. und Sie können sie mit $ location.search () lesen / einstellen. Ich werde das der Antwort hinzufügen.
Andrew Joslin
5
Jakub hat recht. Sie sind verschiedene Dinge. Wenn Sie die "Suche" im Winkel verwenden, wird die Abfrage an den Hash (Ende der URL) angehängt. Die RFC-Spezifikation für URI besagt, dass die Abfrageparameter den Hash voranstellen (nicht anhängen) sollen. Somit ist die "Suche" ein Konstrukt, das nur durch Winkel extrapoliert und interpretiert wird. Aus diesem Grund funktioniert für die oben genannte Lösung nur der HTML5-Modus, da Sie alle Anforderungen unabhängig vom tatsächlichen URI an eine Seite (auf Serverebene) delegieren.
Steven Pena
2
Dies funktioniert nur, wenn Sie die Route in angleJS verwenden möchten!
Windmaomao
189

Gut, dass Sie es geschafft haben, es mit dem HTML5-Modus zum Laufen zu bringen, aber es ist auch möglich, es im Hashbang-Modus zum Laufen zu bringen.

Sie könnten einfach verwenden:

$location.search().target

um Zugriff auf den Suchparameter 'Ziel' zu erhalten.

Als Referenz finden Sie hier die funktionierende 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
quelle
2
Benötigen Sie die Klammern um $ location.search ()?
Magne
2
@Magne: Ja, Sie brauchen Klammern, $ location.search ist eine Methode docs.angularjs.org/api/ng/service/$location
nandin
4
Vergessen Sie nicht, dass, wenn Sie nicht verwenden, HTML5Mode(true)nur Parameter nach # / verfügbar sind oder zu Beginn mit # / zur URL hinzugefügt werden.
Sebastian
21
@nandin: Nein, Sie nicht brauchen , um die Klammern um $location.search() . Ich bin mir nicht sicher, warum diese Antwort sie dorthin bringt.
Dan Tao
9
Ich habe das Gefühl, dass @nandin die Frage "Brauchen Sie Klammern?" Missverstanden hat. Sie tun müssen , um die Klammern nach Suche, aber nicht diejenigen , um die Gesamtheit $location.search().
K. Carpenter
56

Um meine eigene Frage teilweise zu beantworten, finden Sie hier ein Arbeitsbeispiel für HTML5-Browser:

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

Der Schlüssel war, $locationProvider.html5Mode(true);wie oben beschrieben anzurufen . Es funktioniert jetzt beim Öffnen http://127.0.0.1:8080/test.html?target=bob. Ich bin nicht glücklich darüber, dass es in älteren Browsern nicht funktioniert, aber ich könnte diesen Ansatz trotzdem verwenden.

Eine Alternative, die mit älteren Browsern funktioniert, besteht darin, den html5mode(true)Anruf abzubrechen und stattdessen die folgende Adresse mit Hash + Schrägstrich zu verwenden:

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

Die entsprechende Dokumentation finden Sie im Entwicklerhandbuch: Angular Services: Verwenden von $ location (seltsam, dass meine Google-Suche dies nicht gefunden hat ...).

Ellis Whitehead
quelle
Danke dafür. Ich habe mir die Haare ausgezogen und versucht, die Abfrageparameter einzulesen. Wie oben erwähnt, wurde ich immer noch "undefiniert". Das Einstellen des Modus auf HTML5 hat funktioniert.
Sthomps
Sollte das ng-controllerAttribut von <body>nicht auf gesetzt werden MyApp?
Jago
4
Sieht so aus, als würden Sie mit Angular 1.3 beginnen. Um html5Mode verwenden zu können, müssen Sie entweder ein <base href="https://stackoverflow.com/" />Tag hinzufügen oder requireBase: falsedem Aufruf von html5Mode einen weiteren Parameter hinzufügen. Details hier
dae721
17

Dies kann auf zwei Arten erfolgen:

  1. Verwenden von $routeParams

Die beste und empfohlene Lösung ist die Verwendung $routeParamsin Ihrem Controller. Es erfordert die ngRouteInstallation des Moduls.

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

Hier gibt es eine Einschränkung. Es funktioniert nur im HTML5-Modus. Standardmäßig funktioniert es nicht für die URL, die kein Hash ( #) enthälthttp://localhost/test?param1=abc&param2=def

Sie können es zum Laufen bringen, indem Sie #/die URL hinzufügen .http://localhost/test#/?param1=abc&param2=def

$location.search() um ein Objekt zurückzugeben wie:

{
  param1: 'abc',
  param2: 'def'
}
Fizer Khan
quelle
5
Vielen Dank für Ihren Rat mit # /
yonexbat
9

$ location.search () funktioniert nur mit aktiviertem HTML5-Modus und nur mit unterstützendem Browser.

Das wird immer funktionieren:

$ window.location.search

Illidan
quelle
6

Nur um zu sommerisieren.

Wenn Ihre App von externen Links geladen wird, erkennt Angular dies nicht als URL-Änderung, sodass $ loaction.search () Ihnen ein leeres Objekt geben würde. Um dies zu lösen, müssen Sie in Ihrer App-Konfiguration (app.js) Folgendes festlegen:

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

      $locationProvider.html5Mode(true);
 }]);
sapy
quelle
1
Ja. Das war ein Schmerz zu finden. Danke für den Kommentar.
Mikeborgh
2

Nur eine Präzision zu Ellis Whiteheads Antwort. $locationProvider.html5Mode(true);funktioniert nicht mit der neuen Version von anglejs, ohne die Basis-URL für die Anwendung mit einem <base href="">Tag anzugeben oder den Parameter auf requireBasezu setzenfalse

Aus dem Dokument :

Wenn Sie $ location für die Verwendung von html5Mode (history.pushState) konfigurieren, müssen Sie die Basis-URL für die Anwendung mit einem Tag angeben oder $ locationProvider so konfigurieren, dass kein Basis-Tag erforderlich ist, indem Sie ein Definitionsobjekt mit requireBase: false an $ locationProvider übergeben. html5Mode ():

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

Sie können auch $ location. $$ search.yourparameter verwenden

thewindev
quelle
18
Das $$searchist eine interne Variable, deren Verwendung keine so gute Idee ist.
Kumarshar
1

das kann dir helfen

Was ist die prägnanteste Methode zum Lesen von Abfrageparametern in 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
quelle
1

Ich habe festgestellt, dass HTML5Mode für ein SPA viele 404-Fehlerprobleme verursacht. In diesem Fall muss $ location.search nicht funktionieren. In meinem Fall möchte ich einen URL-Abfragezeichenfolgenparameter erfassen, wenn ein Benutzer zu meiner Site kommt, unabhängig davon, auf welche "Seite" er anfänglich verweist, UND sie nach dem Anmelden an diese Seite senden können. Also erfasse ich einfach alle das Zeug in 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'];
    }
    ...
}

dann später nach dem Login kann ich $ state.go sagen ($ rootScope.initialPage, $ rootScope.initialParams)

Nuander
quelle
-3

Es ist etwas spät, aber ich denke, Ihr Problem war Ihre URL. Wenn statt

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

Sie hatten

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

Ich bin mir ziemlich sicher, dass es funktioniert hätte. Angular ist sehr wählerisch in Bezug auf seine # /

Octavio Kidd
quelle
Dies ist nur möglich, wenn Sie den HTML5-Modus nicht aktivieren. Das # / ist in Angular-URLs nicht immer vorhanden.
LocalPCGuy
Es ist, wenn Sie ein SPA bauen. Alle meine URLs haben ein #. Und HTML5Mode bedeutet, dass 1) 404 bei der Seitenaktualisierung und 2) direkte URLs nicht funktionieren. Scheint ein hoher Preis zu sein.
Nuander