Angularjs 从指令更新控制器作用域

Angularjs 从指令更新控制器作用域,angularjs,angularjs-directive,angularjs-scope,Angularjs,Angularjs Directive,Angularjs Scope,我正在使用AngularJS指令创建可重用的UI组件。我想要一个控制器,它包含我的业务逻辑和嵌套组件(指令)。我希望这些指令能够操作控制器作用域上的单个属性。这些指令需要有一个隔离作用域,因为我可能会多次使用同一指令,并且每个实例都需要绑定到特定的控制器作用域属性 到目前为止,将更改应用回控制器作用域的唯一方法是从指令中调用scope.$apply()。但是,由于rootScope:inprog(scopeoperation-in-progress)错误,当我在ng-click回调中时,这会中断

我正在使用AngularJS指令创建可重用的UI组件。我想要一个控制器,它包含我的业务逻辑和嵌套组件(指令)。我希望这些指令能够操作控制器作用域上的单个属性。这些指令需要有一个隔离作用域,因为我可能会多次使用同一指令,并且每个实例都需要绑定到特定的控制器作用域属性

到目前为止,将更改应用回控制器作用域的唯一方法是从指令中调用
scope.$apply()
。但是,由于rootScope:inprog(scopeoperation-in-progress)错误,当我在ng-click回调中时,这会中断

所以我的问题:当child指令更新了控制器作用域上的值时,让控制器知道的最佳方法是什么

我曾考虑在控制器上设置一个函数,指令可以调用该函数进行更新,但这对我来说似乎很沉重

这是我的代码,在ng click回调时中断。请记住,我不只是想解决ng点击问题。我想要最好的整体解决方案,即应用可重用指令来修改父范围/模型

html

<div ng-controller="myCtrl">
    <my-directive value="val1"></my-directive>
</div>
指令

...
.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>'
};
}]);
。。。
.directive('myDirective',[函数(){
返回{
链接:功能(范围){
scope.buttonClick=函数(){
var val='新值';
scope.value=val;
作用域:$apply();
};
},
范围:{
值:'='
},
模板:“”
};
}]);

指令中双向数据绑定的目的正是您要问的——即“[允许]指令修改父范围/模型。”

首先,仔细检查是否已在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>

我认为你关于
$scope.apply的问题是在转移注意力。我不确定当你开发这个演示和问题时,它为你解决了什么问题,但这不是它的目的,还有FWIW

您不必担心这个问题(“让控制器意识到……某些东西修改了作用域上的值”);Angular的数据绑定会自动处理这些问题

这里有点复杂,因为使用该指令时,需要担心多个作用域。外部作用域属于
,该作用域有一个.val属性,还有一个由
创建的内部作用域,它也有一个.val属性,而
按钮单击
处理程序内部的
myDirective
修改内部作用域。但是您使用
值声明了myDirective的作用域:'='
,这将在内部和外部作用域之间设置该属性值的双向同步

所以它应该自动工作,在我根据你的问题代码创建的plunker中,它会自动工作

那么,
scope.$apply
从何而来?它明确用于在Angular不知道需要时触发摘要循环。(如果您在Angular知道它已经需要一个摘要循环时使用它,您会得到一个嵌套的摘要循环和您注意到的“inprog”错误。),其中我引用“$apply()用于从Angular框架外部执行Angular中的表达式”。例如,当响应使用非角度方法设置的事件处理程序时,需要使用它——直接DOM事件绑定、jQuery、socket.io、,等等。如果你在Angular应用程序中使用这些机制,通常最好将它们封装在处理Angular到non Angular接口的指令或服务中,这样应用程序的其余部分就不必担心了

<代码>范围。$Aptudio< /Calp>实际上是围绕代码>范围的包装器。$摘要< /代码>也管理异常处理。这不太清楚。我发现更容易理解<代码> $摘要>代码>,然后考虑<代码> $AppAp/<代码>。“我实际上应该使用的
$digest
的更友好版本”。)

关于
$apply
的最后一点注意事项是:它需要一个函数回调参数,您应该在这个回调中完成工作。如果您做了一些工作,然后调用
$apply
,之后没有参数,它就可以工作了,但在这一点上它与
$digest
相同。因此,如果您确实需要在这里使用
$apply
,它应该看起来更像:


scope.buttonClick=function(){
作用域$apply(函数(){
scope.value=newValue;
});
});

您可以在$rootScope上发出事件。@camden\u kid我希望得到更好的封装。至少我会使用我考虑过的控制器方法。不过我不想在根作用域上添加更多聊天。您不需要调用$apply(),因为buttonClick函数是由ng click指令调用的,因此不会在angular的事件处理之外执行。如果您想修改属性,那么您所拥有的就可以了(除非您不应该使用$apply()。如果要调用回调函数,请使用
'&'
而不是
'='
传递可调用函数。您可以插入服务。我注意到的一点是,您在指令元素标记中有一个按钮。它不会这样工作。您需要一个模板(或templateURL)在你的指令中。@camden_kid你对模板的看法是对的。我以这种方式发布它是为了简洁,但我会进行编辑。你为我指明了正确的方向。我的问题与双向绑定和原语纠缠在一起。
<div ng-controller="myCtrl">
    <my-directive value="val1" on-val-change="myFunc"> <!-- Added on-change binding -->
        <button ng-click="buttonClick()"></button>
    </my-directive>
</div>