在这些情况下,我经常想要从控制器发布一些数据,以便在包含的部分中使用.现在,我知道我可以简单地绑定控制器范围内的项目,但是我想明确指定“模型”位置,以使代码更易于维护和更易于阅读.我想要使用的是ng-model,因为它将用于自定义指令,但就在我的普通控制器旁边:
<div ng-controller="AppController" ng-model='fooModel'> {{fooModel}} </div>
但是,我没有办法在不使用指令和’require’注入的情况下获得对生成的ngModelController的引用.
我知道我可以通过将$attr注入到我的控制器中来轻松地创建自己的属性,并执行以下操作:
<div ng-controller="AppController" my-model='fooModel'> {{fooModel}} </div>
在这种情况下,我只需手动获取或解析myModel值,并将我的模型粘贴到该名称下的$scope中.然而,在这种情况下感觉不对 – 我真的只需要一个控制器的“模型”,并且我宁愿不必在ngModel存在时将这个样板添加到每个控制器. (这是事情的原则!)
我的问题是:
1)有没有办法使用ngModel和普通控制器来获得上述效果?
2)我一直在试图找出存储ngModelControllers的位置,这样我就可以查看调试器中的情况但却找不到它们.使用ngModel指令时,我应该在范围或父范围内看到这些吗? (他们住在哪里?!?)
更新:如下面的答案所示,$element.controller()可用于获取控制器.这工作(http://plnkr.co/edit/bZzdLpacmAyKy239tNAO?p=preview)然而,它有点不满意,因为它需要使用$evalAsync.
2) I have been trying to figure out where ngModelControllers are stored so that I could look at the situation in the debugger but have not been able to find them. When using an ngModel directive should I see these in the scope or parent scope? (Where do they live?!?)
答案取决于您要从哪里访问控制器.
使用ng-model从元素外部
它在具有ng-model属性的元素和父表单(或ngForm)上都需要“name”属性.所以假设你有一个名为myForm的表单和一个名为myInput的ng-model属性的元素,那么你可以从父作用域访问myFoo的ngModelController作为myForm.myInput.例如,出于调试目的:
<p>myFoo: {{myForm.myInput.$modelValue}}<p> <form name="myForm"> <div ng-controller="InnerController" name="myInput" ng-model="model.foo"></div> </form>
从http://plnkr.co/edit/IVTtvIXlBWXGytOEHYbn?p=preview可以看出
从具有ng-model的元素内部
与answer from @pixelbits类似,由于控制器创建的顺序,需要使用$evalAsync,但您也可以使用angular.element.controller函数来检索它:
app.controller('InnerController',function($scope,$element) { $scope.$evalAsync(function() { $scope.myModelController = $element.controller('ngModel'); }); });
在控制器内部使用,以进行调试,如下所示:
<div ng-controller="InnerController" ng-model="model.foo"> <p>myFoo: {{myModelController.$modelValue}}<p> </div>
从http://plnkr.co/edit/C7ykMHmd8Be1N1Gl1Auc?p=preview可以看出.
1) Is there some way to use ngModel along with a plain controller to get the effect above?
一旦在指令中有了ngModelController,就可以像使用$setViewValue函数使用访问ngModelController的自定义指令一样更改其值:
myModelController.$setViewValue('my-new-model-value');
例如,您可以执行此操作以响应触发ngChange处理程序的用户操作.
app.controller('InnerController',$element) { $scope.$evalAsync(function() { $scope.myModelController = $element.controller('ngModel'); }); $scope.$watch('myModelController.$modelValue',function(externalModel) { $scope.localModel = externalModel; }); $scope.changed = function() { $scope.myModelController.$setViewValue($scope.localModel); }; });
请注意$modelValue上的额外观察者以获取模型的初始值,以及对任何后续更改做出反应.
它可以与模板一起使用,如:
{{model.foo}} <div ng-controller="InnerController" ng-model="model.foo"> <p><input type="text" ng-model="localModel" ng-change="changed()"></p> </div>
请注意,这使用ngChange而不是localModel上的观察程序.这是故意的,因此只有当用户与元素交互时才调用$setViewValue,而不是响应来自父作用域的模型更改.
这可以在http://plnkr.co/edit/uknixs6RhXtrqK4ZWLuC?p=preview看到
编辑:如果您想避免使用$evalAsync,可以使用观察者.
$scope.$watch(function() { return $element.controller('ngModel'); },function(ngModelController) { $scope.myModelController = ngModelController; });
见于http://plnkr.co/edit/gJonpzLoVsgc8zB6tsZ1?p=preview
作为旁注,到目前为止,我似乎已经避免了像这样的嵌套普通控制器.我认为如果模板角色的某个部分是通过ngModel来控制变量,那么它是编写小指令的主要候选者,通常使用隔离范围来确保由于范围继承而没有意外的影响,这有明确的API,并使用require来访问ngModelController.是的,它可能不会被重用,但它确实有助于在代码的各个部分之间强制分离责任.