从指令更新控制器范围
Update controller scope from directive
我正在使用 AngularJS 指令创建可重用的 UI 组件。我想要一个包含我的业务逻辑和嵌套组件(指令)的控制器。我希望指令能够在控制器范围内操作单个 属性。这些指令需要有一个独立的范围,因为我可能会多次使用同一个指令,并且每个实例都需要绑定到一个特定的控制器范围 属性.
到目前为止,我可以将更改应用回控制器范围的唯一方法是从指令中调用 scope.$apply()
。但是,由于 rootScope:inprog(范围操作正在进行)错误,当我在 ng-click 回调中时,这会中断。
所以我的问题:当子指令更新了控制器范围内的值时,让我的控制器知道的最佳方法是什么?
我考虑过在控制器上有一个函数,指令可以调用它来进行更新,但这对我来说似乎很重。
这是我在 ng-click 回调时中断的代码。 请记住,我不只是想解决 ng-click 问题。我想要最好的整体解决方案来应用可重用指令来修改父级 scope/model。
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>'
};
}]);
指令中双向数据绑定的目的正是您要问的——“[允许]指令修改父项scope/model”。
首先,仔细检查您是否在指令属性上正确设置了双向数据绑定,该指令属性公开了您要在范围之间共享的变量。在控制器中,如果您需要在值更改时执行某些操作,则可以使用 $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 your example works for me without it.
您不必担心这个问题 ("make controller aware ... that [something] modified a value on a scope"); Angular 的数据绑定会自动处理。
这里有点复杂,因为使用指令,需要考虑多个范围。外部作用域属于 <div ng-controller=myCtrl>
,该作用域有一个 .val 属性,还有一个由 <my-directive>
创建的内部作用域,它也有一个 .val 属性,并且 myDirective
中的 buttonClick
处理程序修改了内部处理程序。但是您使用 value: '='
声明了 myDirective 的范围,它设置了内部和外部范围之间 属性 值的双向同步。
所以它应该会自动工作,在我根据你的问题代码创建的 plunker 中,它确实会自动工作。
那么 scope.$apply
是从哪里来的呢?它明确用于在 Angular 不知道需要时触发摘要循环。 (如果你在 Angular 知道它已经需要一个摘要循环时使用它,你会得到一个嵌套的摘要循环和你注意到的 "inprog" 错误。)Here's the doc link,我引用“ $apply() 用于从 angular 框架之外执行 angular 中的表达式”。您需要使用它,例如,在响应使用非 Angular 方法设置的事件处理程序时——直接 DOM 事件绑定、jQuery、socket.io 等. 如果您在 Angular 应用程序中使用这些机制,通常最好将它们包装在处理 Angular-to-non-Angular 接口的指令或服务中,以便其余的您的应用不必担心。
(scope.$apply
实际上是 scope.$digest
的包装器,它还管理异常处理。这在文档中不是很清楚。我发现它更容易理解 name/behavior $digest
,然后认为$apply
为"the friendlier version of $digest
that I'm actually supposed to use"。)
关于 $apply
的最后一个说明;它需要一个函数回调参数,你应该在这个回调中完成工作。如果你做了一些工作然后调用 $apply
之后没有参数,它会起作用,但在那一点上它与 $digest
相同。所以如果你确实需要在这里使用$apply
,它应该看起来更像:
scope.buttonClick = function() {
scope.$apply(function() {
scope.value = newValue;
});
});
我正在使用 AngularJS 指令创建可重用的 UI 组件。我想要一个包含我的业务逻辑和嵌套组件(指令)的控制器。我希望指令能够在控制器范围内操作单个 属性。这些指令需要有一个独立的范围,因为我可能会多次使用同一个指令,并且每个实例都需要绑定到一个特定的控制器范围 属性.
到目前为止,我可以将更改应用回控制器范围的唯一方法是从指令中调用 scope.$apply()
。但是,由于 rootScope:inprog(范围操作正在进行)错误,当我在 ng-click 回调中时,这会中断。
所以我的问题:当子指令更新了控制器范围内的值时,让我的控制器知道的最佳方法是什么?
我考虑过在控制器上有一个函数,指令可以调用它来进行更新,但这对我来说似乎很重。
这是我在 ng-click 回调时中断的代码。 请记住,我不只是想解决 ng-click 问题。我想要最好的整体解决方案来应用可重用指令来修改父级 scope/model。
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>'
};
}]);
指令中双向数据绑定的目的正是您要问的——“[允许]指令修改父项scope/model”。
首先,仔细检查您是否在指令属性上正确设置了双向数据绑定,该指令属性公开了您要在范围之间共享的变量。在控制器中,如果您需要在值更改时执行某些操作,则可以使用 $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 your example works for me without it.
您不必担心这个问题 ("make controller aware ... that [something] modified a value on a scope"); Angular 的数据绑定会自动处理。
这里有点复杂,因为使用指令,需要考虑多个范围。外部作用域属于 <div ng-controller=myCtrl>
,该作用域有一个 .val 属性,还有一个由 <my-directive>
创建的内部作用域,它也有一个 .val 属性,并且 myDirective
中的 buttonClick
处理程序修改了内部处理程序。但是您使用 value: '='
声明了 myDirective 的范围,它设置了内部和外部范围之间 属性 值的双向同步。
所以它应该会自动工作,在我根据你的问题代码创建的 plunker 中,它确实会自动工作。
那么 scope.$apply
是从哪里来的呢?它明确用于在 Angular 不知道需要时触发摘要循环。 (如果你在 Angular 知道它已经需要一个摘要循环时使用它,你会得到一个嵌套的摘要循环和你注意到的 "inprog" 错误。)Here's the doc link,我引用“ $apply() 用于从 angular 框架之外执行 angular 中的表达式”。您需要使用它,例如,在响应使用非 Angular 方法设置的事件处理程序时——直接 DOM 事件绑定、jQuery、socket.io 等. 如果您在 Angular 应用程序中使用这些机制,通常最好将它们包装在处理 Angular-to-non-Angular 接口的指令或服务中,以便其余的您的应用不必担心。
(scope.$apply
实际上是 scope.$digest
的包装器,它还管理异常处理。这在文档中不是很清楚。我发现它更容易理解 name/behavior $digest
,然后认为$apply
为"the friendlier version of $digest
that I'm actually supposed to use"。)
关于 $apply
的最后一个说明;它需要一个函数回调参数,你应该在这个回调中完成工作。如果你做了一些工作然后调用 $apply
之后没有参数,它会起作用,但在那一点上它与 $digest
相同。所以如果你确实需要在这里使用$apply
,它应该看起来更像:
scope.buttonClick = function() {
scope.$apply(function() {
scope.value = newValue;
});
});