javascript AngularJS:父范围未在指令中更新(具有独立范围)双向绑定
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19391773/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AngularJS: Parent scope not updated in directive (with isolated scope) two way binding
提问by Steve
I have the following code, which can also be fiddled on http://jsfiddle.net/garukun/u69PT/.
我有以下代码,也可以在http://jsfiddle.net/garukun/u69PT/上摆弄。
View:
看法:
<div data-ng-app="testApp">
<div data-ng-controller="testCtrl">
<strong>{{pkey}}</strong>
<span data-test-directive data-parent-item="pkey"
data-parent-update="update(pkey)"></span>
</div>
</div>
JS:
JS:
var testApp = angular.module('testApp', []);
testApp.directive('testDirective', function ($timeout) {
return {
scope: {
key: '=parentItem',
parentUpdate: '&'
},
replace: true,
template: '<div><p>{{key}}</p>' +
'<button data-ng-click="lock()">Lock</button>' +
'</div>',
controller: function ($scope, $element, $attrs) {
$scope.lock = function () {
$scope.key = 'D+' + $scope.key;
console.log('DIR :', $scope.key);
// Expecting $scope.$parent.pkey to have also been
// updated before invoking the next line.
$scope.parentUpdate();
// $timeout($scope.parentUpdate); // would work.
};
}
};
});
testApp.controller('testCtrl', function ($scope) {
$scope.pkey = 'golden';
$scope.update = function (k) {
// Expecting local variable k, or $scope.pkey to have been
// updated by calls in the directive's scope.
console.log('CTRL:', $scope.pkey, k);
$scope.pkey = 'C+' + k;
console.log('CTRL:', $scope.pkey);
};
});
Basically, I'm setting up the directive with an isolated scope, in which I'm two-way binding a property (key) from the parent scope (pkey), and also delegating a method (parentUpdate) to be called in the context of the parent scope.
基本上,我正在设置具有隔离作用域的指令,其中我从父作用域 (pkey) 双向绑定属性 (key),并委托在上下文中调用的方法 (parentUpdate)父作用域的。
Now, during a ng-click event handler in the directive, I want to invoke the parentUpdate method and do something within. When I'm invoking that method, I'm expecting my parent scope's model to have been updated. But in reality, it is not, and this is what's puzzling me.
现在,在指令中的 ng-click 事件处理程序期间,我想调用 parentUpdate 方法并在其中执行某些操作。当我调用该方法时,我希望我的父作用域的模型已经更新。但实际上,事实并非如此,这让我感到困惑。
It's probably because of some missing $digest cycles in the middle, since wrapping the parentUpdate call with $timeout would work as expected.
这可能是因为中间缺少一些 $digest 周期,因为用 $timeout 包装 parentUpdate 调用会按预期工作。
Could someone shed some light on what's missing? Or how to properly invoked parentUpdate?
有人可以阐明缺少的内容吗?或者如何正确调用parentUpdate?
回答by jandersen
OK, I'm going to take a crack at this one... It seems you're changing both the isolated child AND parent variables before a $digest
cycle where the bi-direction logic syncs the two. Here's the details:
好的,我将尝试解决这个问题...看来您在$digest
双向逻辑同步两者的循环之前更改了孤立的子变量和父变量。以下是详细信息:
- First your
lock()
function is executed by clicking on the button. This updates the isolated$scope.key
variable. NOTE: This does NOT immediatelyupdate the parent$scope.pKey
; that would normally happen at the next$digest
cycle but does not in this case. Read on... - Within
lock()
you are callingparentUpdate()
which updates the parent's$scope.pKey
variable. - THEN the
$digest
cycle executes. When it loops it's way to the parent scope a change to$scope.pKey
is correctly detected. - The change to
$scope.pKey
triggers awatch()
that was created by the bi-directional binding in the isolated scope. These linesare the critical ones.. - The
watch()
created by the isolated scope checks whether it's value for the bi-directional binding is in sync with the parent's value. If it isn't (and it's not in this scenario) the parent's value is copied to the isolated scope even though the isolated scope's value has changed also and in fact was changed first.
- 首先,您的
lock()
功能是通过单击按钮来执行的。这会更新隔离$scope.key
变量。注意:这不会立即更新父级$scope.pKey
;这通常会在下一个$digest
周期发生,但在这种情况下不会。继续阅读... - 在
lock()
您调用parentUpdate()
它更新父$scope.pKey
变量的内部。 - 然后
$digest
循环执行。当它循环时,它$scope.pKey
会正确检测到父作用域的更改。 - 对
$scope.pKey
触发 a的更改watch()
由隔离范围中的双向绑定创建。 这些线是关键的。 - 在
watch()
由分离范围检查其对双向结合值是否在与所述父级的值同步产生。如果不是(并且它不在这种情况下),即使隔离范围的值也已更改并且实际上已首先更改,父项的值也会复制到隔离范围。
Misko's famous post on Angular data-bindingdescribes the benefits of the $digest
cycle approach. What you're seeing here is a conscious side-effect of the $digest
's approach to change coalesence wherein, as the source code comment says, parent changed and it has precedence
... and that means your isolated scope's change loses.
Misko 关于 Angular 数据绑定的著名文章描述了$digest
循环方法的好处。你在这里看到的是$digest
改变合并的方法的一个有意识的副作用,正如源代码注释所说,parent changed and it has precedence
......这意味着你的隔离范围的变化丢失了。
The $timeout()
approach you noted above avoids this issue by changing only the isolated scope's value in the first $digest
cycle which allows it to be copied to the parent scope successfully and THEN calling parentUpdate()
$timeout()
您上面提到的方法通过在第一个$digest
循环中仅更改隔离作用域的值来避免此问题,这允许将其成功复制到父作用域,然后调用parentUpdate()
The $compile
documentationsays:
该$compile
文件说:
Often it's desirable to pass data from the isolated scope via an expression and to the parent scope, this can be done by passing a map of local variable names and values into the expression wrapper fn. For example, if the expression is increment(amount) then we can specify the amount value by calling the localFn as localFn({amount: 22}).
通常希望通过表达式将数据从隔离作用域传递到父作用域,这可以通过将局部变量名称和值的映射传递到表达式包装器 fn 中来完成。例如,如果表达式是 increment(amount),那么我们可以通过将 localFn 调用为 localFn({amount: 22}) 来指定数量值。
This means, at step #2 you could pass in your value for pkey
via an object map like this:
这意味着,在第 2 步,您可以pkey
通过这样的对象映射传递您的值:
parentUpdate({pkey: 'D+' + $scope.key })
Here's the updated fiddle: http://jsfiddle.net/KbYcr/
这是更新的小提琴:http: //jsfiddle.net/KbYcr/
回答by Valerie
Using $scope.$apply()
instead of $scope.$digest()
works too. This will also trigger the digest on the rootScope.
使用$scope.$apply()
代替也$scope.$digest()
有效。这也将触发 rootScope 上的摘要。