我使用AngularJS指令创建可重用的UI组件。我想有一个控制器,其中包含我的业务逻辑与嵌套组件(指令)。我希望指令能够操作控制器范围上的单个属性。指令需要有一个隔离范围,因为我可能会多次使用同一个指令,并且每个实例都需要绑定到特定的控制器范围属性。
到目前为止,我可以将更改应用回控制器范围的唯一方法是从指令调用scope.$apply()
。但是当我因为rootScope:inprog(范围操作正在进行中)错误而进入ng-click回调时,这会中断。
所以我的问题:当子指令更新了控制器范围的值时,让控制器知道的最佳方法是什么?
我已经考虑过在控制器上有一个函数,指令可以调用它来进行更新,但这对我来说似乎很重要。
这是我的代码,它打破了ng-click回调。 请记住,我不只是想解决ng-click问题。我想要最好的整体解决方案来应用可重用指令来修改父作用域/模型。
HTML
<div ng-controller="myCtrl">
<my-directive value="val1"></my-directive>
</div>
控制器
...
.controller('myCtrl', ['$scope', function ($scope) {
$scope.val1 = 'something';
}});
指令
...
.directive('myDirective', [function () {
return {
link: function(scope) {
scope.buttonClick = function () {
var val = 'new value';
scope.value = val;
scope.$apply();
};
},
scope: {
value: '='
},
template: '<button ng-click="buttonClick()"></button>'
};
}]);
答案 0 :(得分:4)
指令中的双向数据绑定的目的正是您所要求的 - “[允许]指令修改父作用域/模型”。
首先,仔细检查您是否在directive属性上正确设置了双向数据绑定,该属性公开了要在作用域之间共享的变量。在控制器中,如果您需要在值更改时执行某些操作,则可以使用$watch
来检测更新。此外,您还可以选择向指令添加事件处理程序属性。这允许指令在发生事件时调用函数。这是一个例子:
<div ng-controller="myCtrl">
<my-directive value="val1" on-val-change="myFunc"> <!-- Added on-change binding -->
<button ng-click="buttonClick()"></button>
</my-directive>
</div>
答案 1 :(得分:4)
我认为你关于$scope.apply
的问题是一个红色的鲱鱼。我不确定当你演变这个演示和问题时它为你解决了什么问题,但这不是它的用途,而且FWIW your example works for me without it。
你不应该担心这个问题(“让控制器意识到...... [某事]修改了范围内的值”); Angular的数据绑定会自动处理。
这里有点复杂,因为使用该指令时,需要担心多个范围。外部作用域属于<div ng-controller=myCtrl>
,该作用域具有.val属性,并且<my-directive>
创建了一个内部作用域,它还具有.val属性和buttonClick
处理程序内部myDirective
修改内部的内部。但是您使用value: '='
声明了myDirective的范围,该范围设置了内部和外部范围之间的属性值的双向同步。
所以它应该自动运行,并且在我从问题代码创建的plunker中,它会自动运行。
那么scope.$apply
会在哪里进来?当Angular不知道它需要时,它明确地用于触发摘要循环。 (如果你在Angular知道它已经知道它需要一个摘要周期时使用它,你会得到一个嵌套的摘要周期和你注意到的“inprog”错误。)Here's the doc link,我引用“$ apply()”从角度框架外部以角度执行表达式“。你需要使用它,例如,当响应使用非Angular方法设置的事件处理程序时 - 直接DOM事件绑定,jQuery,socket.io等。如果你在Angular应用程序中使用这些机制,它通常是最好将它们包装在处理Angular到非Angular接口的指令或服务中,以便应用程序的其余部分不必担心它。
(scope.$apply
实际上是scope.$digest
的包装器,它也管理异常处理。这在文档中不是很清楚。我发现更容易理解{{1}的名称/行为},然后将$digest
视为“我实际上应该使用的$apply
更友好的版本”。)
关于$digest
的最后一点说明;它需要一个函数回调参数,你应该在这个回调中做这项工作。如果你做了一些工作,然后在没有参数的情况下调用$apply
,它就可以工作,但在那时它与$apply
相同。因此,如果你 需要在这里使用$digest
,它应该看起来更像:
$apply