您可以在创build时将parameter passing给AngularJS控制器吗?

我有一个控制器负责与API通信,以更新用户,名称,电子邮件等的属性。每个用户有一个'id' ,从configuration文件页面查看时从服务器传递。

我想将这个值传递给AngularJS控制器,以便知道当前用户的API入口点是什么。 我试过在ng-controller传递值。 例如:

 function UserCtrl(id, $scope, $filter) { $scope.connection = $resource('api.com/user/' + id) 

并在HTML中

 <body ng-controller="UserCtrl({% id %})"> 

其中{% id %}打印从服务器发送的ID。 但我得到错误。

在创build时将值传递给控制器​​的正确方法是什么?

笔记:

这个答案是旧的。 这只是关于如何达到预期结果的概念certificate。 但是,根据下面的一些评论,这可能不是最好的解决scheme。 我没有任何文档来支持或拒绝以下方法。 请参阅下面的一些评论以进一步讨论这个话题。

原始答案:

我回答是肯定的,你绝对可以使用ng-init和一个简单的init函数。

这是在plunker它的例子

HTML

 <!DOCTYPE html> <html ng-app="angularjs-starter"> <head lang="en"> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script> <script src="app.js"></script> </head> <body ng-controller="MainCtrl" ng-init="init('James Bond','007')"> <h1>I am {{name}} {{id}}</h1> </body> </html> 

JavaScript的

 var app = angular.module('angularjs-starter', []); app.controller('MainCtrl', function($scope) { $scope.init = function(name, id) { //This function is sort of private constructor for controller $scope.id = id; $scope.name = name; //Based on passed argument you can make a call to resource //and initialize more objects //$resource.getMeBond(007) }; }); 

我很晚了,我不知道这是不是一个好主意,但是你可以在控制器函数中包含$attrs注入,允许控制器使用元素上提供的“参数”进行初始化, 例如

 app.controller('modelController', function($scope, $attrs) { if (!$attrs.model) throw new Error("No model for modelController"); // Initialize $scope using the value of the model attribute, eg, $scope.url = "http://example.com/fetch?model="+$attrs.model; }) <div ng-controller="modelController" model="foobar"> <a href="{{url}}">Click here</a> </div> 

再次,不知道这是一个好主意,但它似乎工作,是另一种select。

这也适用。

使用Javascript:

 var app = angular.module('angularApp', []); app.controller('MainCtrl', function($scope, name, id) { $scope.id = id; $scope.name = name; // and more init }); 

HTML:

 <!DOCTYPE html> <html ng-app="angularApp"> <head lang="en"> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script> <script src="app.js"></script> <script> app.value("name", "James").value("id", "007"); </script> </head> <body ng-controller="MainCtrl"> <h1>I am {{name}} {{id}}</h1> </body> </html> 

就像@akonsu和Nigel Findlaterbuild议的那样,你可以通过$routeParams.id来读取URL为index.html#/user/:id的url,并在控制器中使用它。

你的应用:

 var app = angular.module('myApp', [ 'ngResource' ]); app.config(['$routeProvider', function($routeProvider) { $routeProvider.when('/:type/:id', {templateUrl: 'myView.html', controller: 'myCtrl'}); }]); 

资源服务

 app.factory('MyElements', ['$resource', function($resource) { return $resource('url/to/json/:type/:id', { type:'@type', id:'@id' }); }]); 

控制器

 app.controller('MyCtrl', ['$scope', '$routeParams', 'MyElements', function($scope, $routeParams, MyElements) { MyElements.get({'type': $routeParams.type, "id": $routeParams.id }, function(elm) { $scope.elm = elm; }) }]); 

那么, elm是可以在视图中访问取决于id

该视图不应该指定configuration

在Angular中,模板不应该指定configuration,这是人们想要从模板文件传递参数给控制器的内在要求。 这成为一个滑坡。 如果configuration设置在模板中被硬编码(例如通过指令或控制器参数属性),则不能再使用该模板来进行除此之外的任何操作。 不久之后,您将需要重新使用该模板,但使用不同的configuration,现在为了做到这一点,您可以预先处理模板,以便在传递给angular度之前注入variables,或者使用大量指令来吐出巨型所以你重新使用所有的控制器HTML除了包装div和它的参数。 对于小项目来说没什么大不了的。 对于一些大的东西(angular度擅长),它会变得很难看。

替代scheme:模块

这种types的configuration是模块devise来处理的。 在许多angular度教程中,人们都为整个应用程序提供了一个单独的模块,但实际上系统的devise和完全支持了许多小型模块,每个模块都包装了整个应用程序的小部分。 理想情况下,控制器,模块等将在单独的文件中声明,并以特定的可重用块拼接在一起。 当你的应用程序按照这种方式devise的时候,除了简单的控制器参数以外,还有很多的重用。

下面的例子有2个模块,重新使用相同的控制器,但每个都有自己的configuration设置。 该configuration设置通过dependency injection使用module.value传入。 这符合angular度的方式,因为我们有以下几点:构造器dependency injection,可重用的控制器代码,可重复使用的控制器模板(控制器div可以很容易地包含在ng-include中),易于unit testing的系统没有HTML,最后可重用模块作为将拼块拼接在一起的车辆。

这是一个例子:

 <!-- index.html --> <div id="module1"> <div ng-controller="MyCtrl"> <div>{{foo}}</div> </div> </div> <div id="module2"> <div ng-controller="MyCtrl"> <div>{{foo}}</div> </div> </div> <script> // part of this template, or a JS file designed to be used with this template angular.element(document).ready(function() { angular.bootstrap(document.getElementById("module1"), ["module1"]); angular.bootstrap(document.getElementById("module2"), ["module2"]); }); </script> <!-- scripts which will likely in be in their seperate files --> <script> // MyCtrl.js var MyCtrl = function($scope, foo) { $scope.foo = foo; } MyCtrl.$inject = ["$scope", "foo"]; // Module1.js var module1 = angular.module('module1', []); module1.value("foo", "fooValue1"); module1.controller("MyCtrl", MyCtrl); // Module2.js file var module2 = angular.module('module2', []); module2.value("foo", "fooValue2"); module2.controller("MyCtrl", MyCtrl); </script> 

看到它在行动: jsFiddle 。

如果ng-init不用于将对象传递给$scope ,则可以随时编写自己的指令。 所以这里是我得到的:

http://jsfiddle.net/goliney/89bLj/

Javasript:

 var app = angular.module('myApp', []); app.directive('initData', function($parse) { return function(scope, element, attrs) { //modify scope var model = $parse(attrs.initData); model(scope); }; }); function Ctrl1($scope) { //should be defined $scope.inputdata = {foo:"east", bar:"west"}; } 

HTML:

 <div ng-controller="Ctrl1"> <div init-data="inputdata.foo=123; inputdata.bar=321"></div> </div> 

但是我的方法只能修改已经在控制器中定义的对象。

它看起来像你最好的解决scheme实际上是一个指令。 这允许你仍然有你的控制器,但是为它定义自定义的属性。

如果您需要访问包装范围中的variables,请使用此方法:

 angular.module('myModule').directive('user', function ($filter) { return { link: function (scope, element, attrs) { $scope.connection = $resource('api.com/user/' + attrs.userId); } }; }); <user user-id="{% id %}"></user> 

如果您不需要访问包装范围中的variables,请使用此选项:

 angular.module('myModule').directive('user', function ($filter) { return { scope: { userId: '@' }, link: function (scope, element, attrs) { $scope.connection = $resource('api.com/user/' + scope.userId); } }; }); <user user-id="{% id %}"></user> 

我发现从$ routeProvider有用的传递variables。

例如,你使用一个控制器MyController来控制多个屏幕,在里面传递一些非常重要的variables“mySuperConstant”。

使用这个简单的结构:

 Router: $routeProvider .when('/this-page', { templateUrl: 'common.html', controller: MyController, mySuperConstant: "123" }) .when('/that-page', { templateUrl: 'common.html', controller: MyController, mySuperConstant: "456" }) .when('/another-page', { templateUrl: 'common.html', controller: MyController, mySuperConstant: "789" }) MyController: MyController: function ($scope, $route) { var mySuperConstant: $route.current.mySuperConstant; alert(mySuperConstant); } 

你可以在build立路线时做到这一点

  .when('/newitem/:itemType', { templateUrl: 'scripts/components/items/newEditItem.html', controller: 'NewEditItemController as vm', resolve: { isEditMode: function () { return true; } }, }) 

后来用它作为

 (function () { 'use strict'; angular .module('myApp') .controller('NewEditItemController', NewEditItemController); NewEditItemController.$inject = ['$http','isEditMode',$routeParams,]; function NewEditItemController($http, isEditMode, $routeParams) { /* jshint validthis:true */ var vm = this; vm.isEditMode = isEditMode; vm.itemType = $routeParams.itemType; } })(); 

所以在这里,当我们build立了我们发送的路由:itemType,稍后从$ routeParams中取回它。

还有另一种方式通过将$ routeParams注入控制器,然后使用这里描述的url参数来将parameter passing给控制器在AngularJS中读取查询参数的最简洁的方法是什么?

这个问题是古老的,但我挣扎了很长时间试图得到这个问题的答案,这将符合我的需求,并不容易find它。 我相信我的下面的解决scheme比目前所接受的解决scheme要好得多,也许是因为这个问题本来就是由于angular增加了function。

简而言之,使用Module.value方法可以将数据传递给控制器​​构造函数。

在这里看到我的掠夺者

我创build一个模型对象,然后将它与模块的控制器相关联,引用它的名称“模型”

HTML / JS

  <html> <head> <script> var model = {"id": 1, "name":"foo"}; $(document).ready(function(){ var module = angular.module('myApp', []); module.value('model', model); module.controller('MyController', ['model', MyController]); angular.bootstrap(document, ['myApp']); }); function confirmModelEdited() { alert("model name: " + model.name + "\nmodel id: " + model.id); } </script> </head> <body > <div ng-controller="MyController as controller"> id: {{controller.model.id}} <br> name: <input ng-model="controller.model.name"/>{{controller.model.name}} <br><button ng-click="controller.incrementId()">increment ID</button> <br><button onclick="confirmModelEdited()">confirm model was edited</button> </div> </body> </html> 

然后,我的控制器中的构造函数接受一个具有相同标识符“model”的参数,然后可以访问该参数。

调节器

 function MyController (model) { this.model = model; } MyController.prototype.incrementId = function() { this.model.id = this.model.id + 1; } 

笔记:

我正在使用bootstrapping的手动初始化,它允许我在将模型发送到angular之前初始化我的模型。 这可以更好地与现有的代码一起使用,因为您可以等待设置相关数据,并只在需要时编译应用程序的angular度子集。

在plunker中,我添加了一个button来提醒最初在javascript中定义的模型对象的值,并将其传递给angular,以确认angular是否真正引用模型对象,而不是复制它并使用副本。

在这一行上:

 module.controller('MyController', ['model', MyController]); 

我将MyController对象传入Module.controller函数,而不是内联函数声明。 我认为这可以让我们更清楚地定义我们的控制器对象,但是Angular文档倾向于使用内联,所以我认为这是明确的。

我使用“控制器为”语法,并将值分配给MyController的“this”属性,而不是使用“$ scope”variables。 我相信这也可以正常使用$范围,控制器分配将如下所示:

 module.controller('MyController', ['$scope', 'model', MyController]); 

而控制器的构造函数会有这样的签名:

 function MyController ($scope, model) { 

如果无论出于何种原因,您也可以将此模型附加为第二个模块的值,然后将其作为依赖项附加到您的主模块。

我相信他的解决办法比现在接受的要好得多

  1. 传递给控制器​​的模型实际上是一个javascript对象,而不是被评估的string。 它是对象的一个​​真实的引用,并且它的变化会影响对这个模型对象的其他引用。
  2. Angular说,接受的答案是使用ng-init是一种滥用,这种解决scheme不适用。

Angular似乎在我见过的大多数其他例子中都有工作,控制器定义了模型的数据,这对我来说是没有意义的,模型和控制器之间没有分离,看起来并不像MVC给我。 这个解决scheme允许你真的有一个完全独立的模型对象,你传递给控制器​​。 另外值得注意的是,如果你使用ng-include指令,你可以把所有的angular度html放在一个单独的文件中,完全把你的模型视图和控制器分隔成不同的模块。

如果使用angular-ui-router,那么这是正确的解决scheme: https : //github.com/angular-ui/ui-router/wiki#resolve

基本上,在控制器实例化之前,您声明了一组依赖项来“parsing”。 您可以为每个“状态”声明依赖关系。 这些依赖关系然后被传递到控制器的“构造函数”中。

这样做的一种方式是拥有一个单独的服务,可以作为公共数据成员的争论的“容器”。

不,这是不可能的。 我认为你可以使用ng-init作为破解http://docs.angularjs.org/api/ng.directive:ngInit

这是一个解决scheme(基于Marcin Wyszynski的build议),它的工作原理是将值传递给你的控制器,但是你没有在你的html中明确声明控制器(ng-init似乎需要) – 例如,你正在使用ng-view呈现模板,并通过routeProvider声明每个控制器的相应路由。

JS

 messageboard.directive('currentuser', ['CurrentUser', function(CurrentUser) { return function(scope, element, attrs) { CurrentUser.name = attrs.name; }; }]); 

HTML

 <div ng-app="app"> <div class="view-container"> <div ng-view currentuser name="testusername" class="view-frame animate-view"></div> </div> </div> 

在这个解决scheme中,CurrentUser是一个可以注入任何控制器的服务,然后.name属性可用。

两个注释:

  • 我遇到的一个问题是,在控制器加载后.name被设置,所以作为一种解决方法,在控制器的作用域上呈现用户名之前,我有一个很短的超时时间。 是否有一个干净的方式等待.name已经在服务上设置?

  • 这感觉就像一个非常简单的方法来获得一个当前用户进入Angular应用程序与Angular以外的所有身份validation。 您可以使用before_filter来防止未login的用户访问您的Angular应用程序所在的html,并且在该html中,如果您想与用户的详细信息交互,则可以插入login的用户名,甚至是他们的ID通过您的Angular应用程序的http请求。 您可以允许未login的用户使用默认的“访客用户”的Angular App。 任何build议,为什么这种方法会很糟糕,将是受欢迎的 – 这感觉太容易明智!)