从指令更新控制器范围

时间:2015-02-27 16:39:08

标签: angularjs angularjs-directive angularjs-scope

我使用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>'
};
}]);

2 个答案:

答案 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