AngularJS:父范围未在指令(具有隔离范围)双向绑定中更新

Ste*_*eve 10 javascript scope directive two-way angularjs

我有以下代码,也可以在http://jsfiddle.net/garukun/u69PT/上摆弄.

视图:

<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>
Run Code Online (Sandbox Code Playgroud)

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);
    };
});
Run Code Online (Sandbox Code Playgroud)

基本上,我正在设置一个带有隔离范围的指令,其中我从父作用域(pkey)双向绑定属性(键),并且还委托在上下文中调用的方法(parentUpdate)父范围.

现在,在指令中的ng-click事件处理程序中,我想调用parentUpdate方法并在其中执行某些操作.当我调用该方法时,我希望我的父范围的模型已经更新.但实际上,事实并非如此,这让我感到困惑.

这可能是因为中间缺少一些$ digest周期,因为使用$ timeout包装parentUpdate调用将按预期工作.

有人可以解释一下缺少的东西吗?或者如何正确调用parentUpdate?

jan*_*sen 27

好的,我要在这个问题上采取行动......看起来你在$digest双向逻辑同步两个循环之前改变了孤立的子AND变量.这是详细信息:

  1. 首先lock(),单击按钮执行您的功能.这会更新隔离$scope.key变量.注意:这不会立即更新父母$scope.pKey; 这通常会发生在下一个$digest周期,但在这种情况下不会发生.继续阅读......
  2. lock()你调用parentUpdate()哪些更新家长的$scope.pKey变量.
  3. 然后$digest循环执行.当它循环到父作用域时,$scope.pKey会正确检测到更改.
  4. 更改以$scope.pKey触发watch()由隔离范围中的双向绑定创建的更改. 这些线是关键的......
  5. 所述watch()由分离的范围检查是否它是双向的结合值来创建与所述父级的值同步.如果不是(并且不在这种情况下),则父级的值将被复制到隔离的范围,即使隔离范围的值也已更改,实际上已更改.

Misko关于Angular数据绑定的着名帖子描述了$digest循环方法的好处.你在这里看到的是$digest改变coalesence的方法的有意识的副作用,正如源代码评论所说,parent changed and it has precedence......这意味着你的孤立范围的变化会失败.

$timeout()您在上面提到的方法通过仅更改第一个$digest循环中隔离范围的值来避免此问题,该值允许将其成功复制到父范围,然后调用parentUpdate()

$compile文件说:

通常需要通过表达式将数据从隔离范围传递到父范围,这可以通过将局部变量名称和值的映射传递到表达式包装器fn来完成.例如,如果表达式是increment(amount),那么我们可以通过将localFn称为localFn({amount:22})来指定金额值.

这意味着,在步骤#2,您可以通过pkey对象映射传递您的值,如下所示:

parentUpdate({pkey: 'D+' + $scope.key })
Run Code Online (Sandbox Code Playgroud)

这是更新的小提琴:http://jsfiddle.net/KbYcr/