在AngularJS中读取查询参数的最简洁方法是什么?


312

我想使用AngularJS读取URL查询参数的值。我正在使用以下URL访问HTML:

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不是适合该工作的工具(有关丑陋的详细信息,请参见下面的答案)。因此,我已将问题的标题从“如何使用$ location在AngularJS中读取查询参数?”中更改。“在AngularJS中读取查询参数的最简洁方法是什么?”。显然,我可以只使用javascript和正则表达式进行解析location.search,但是对如此基本的内容进行低级配置确实会冒犯我的程序员。

所以:有没有$location比我在回答中更好的使用方法,还是有简洁的替代方法?


1
$ location.search()['target']不应该工作吗?
2013年

这行不通,因为路径后没有哈希。http://127.0.0.1:8080/test.html#?target=bob会起作用,请注意#之前的?$location是不被发送到服务器的第二层路由方法。
Daniel F

1
@DanielF @rob,你是对的。在现代浏览器中被调用$location.search()['target']后才$locationProvider.html5Mode(true)可以工作。
krispy

Answers:


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
感谢您的建议和链接!我阅读了该页面,并尝试设置一个工作示例。但是,这种方法对我来说不可行,因为在这种情况下,我真的不想使用路由。尽管如此,这还是一个有用的建议,一旦我有足够的stackoverflow代表,我就会对其进行投票。
艾利斯·怀特海德

1
我要说@ pkozlowski.opensource的回答是在这种情况下更准确
马丁科尔

2
$ routeParams对象中不包含带有常规路由参数的..查询参数。您可以阅读它们,也可以使用$ location.search()进行设置。我将其添加到答案中。
安德鲁·乔斯林

5
雅各布是对的。他们是不同的东西。当您在角度中使用“搜索”时,它将查询附加到哈希(URL的末尾)。URI的RFC规范指出,查询参数应在哈希之前(而不是追加)。因此,“搜索”是仅角度会外推和解释的构造。这就是为什么只有HTML5模式适用于上述解决方案的原因,因为您将所有请求委托给一个页面(在服务器级别),而不管实际的URI如何。
史蒂文·佩纳

2
这仅在您要在angularJS中使用route时有效!
windmaomao 2015年

189

很好,您已经设法使其在html5模式下工作,但也可以使其在hashbang模式下工作。

您可以简单地使用:

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


2
您是否需要在$ location.search()周围加上括号?
Magne 2014年

2
@Magne:是的,您需要括号,$ location.search是一种方法docs.angularjs.org/api/ng/service/$location
nandin 2014年

4
不要忘记,如果不使用,HTML5Mode(true)则仅在#/之后的参数可用或以#/开头添加到url中。
塞巴斯蒂安

21
@nandin:不,你没有需要括号围绕 $location.search()。我不确定为什么这个答案会把他们放在那里。
丹涛

9
我觉得@nandin误解了“是否需要括号”问题。你这样做需要搜索后括号,但不是全部周围的人$location.search()
K. Carpenter 2014年

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吗?
Jago

4
看起来从Angular 1.3开始,要使用html5Mode,还需要添加<base href="https://stackoverflow.com/" />标签或将requireBase: false另一个参数添加到对html5Mode的调用中。这里的细节
dae721 2015年

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模式。默认情况下,它不适用于没有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()会为您提供一个空对象。为了解决这个问题,您需要在应用程序配置(app.js)中设置以下内容

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

      $locationProvider.html5Mode(true);
 }]);

1
是的 这是一个痛苦的发现。感谢您的评论。
mikeborgh 2015年

2

只是埃利斯·怀特海(Ellis Whitehead)的答案。$locationProvider.html5Mode(true);将angularjs的新版本,而不指定基本URL与应用程序不能正常工作<base href="">的标签或参数设置requireBasefalse

从文档

如果将$ location配置为使用html5Mode(history.pushState),则需要为应用程序指定带有标记的基本URL,或者通过将带有requireBase:false的定义对象传递给$ locationProvider来将$ locationProvider配置为不需要基本标记。 html5Mode():

$locationProvider.html5Mode({
  enabled: true,
  requireBase: false
});

1

您还可以使用$ location。$$ search.yourparameter


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)


-3

有点晚了,但是我认为您的问题是您的URL。如果不是

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

你有过

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

我很确定它会起作用。Angular对它的#/确实很挑剔


仅当您未启用HTML5模式时。Angular URL中的#/并不总是存在的。
LocalPCGuy

如果您正在建立SPA。我所有的网址都有一个#。HTML5Mode表示1)页面刷新404和2)直接网址无效。似乎要付出高昂的代价。
nuander
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.