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

时间:2013-10-15 21:51:32

标签: javascript angularjs scope directive two-way

我有以下代码,也可以在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>

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);
    };
});

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

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

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

有人能否对失踪的内容有所了解?或者如何正确调用parentUpdate?

2 个答案:

答案 0 :(得分:27)

好的,我将在这个问题上采取行动......似乎你在$digest周期之前改变了孤立的子AND和父变量,其中双向逻辑同步两者。这是详细信息:

  1. 首先点击按钮执行lock()功能。这会更新隔离的$scope.key变量。 注意:这不会立即更新父$scope.pKey;这通常会发生在下一个$digest周期,但在这种情况下不会发生。请继续阅读......
  2. lock() parentUpdate()内,您正在调用$scope.pKey来更新父级$digest变量。
  3. 然后$scope.pKey周期执行。当它循环到父作用域时,可以正确检测到$scope.pKey的更改。
  4. watch()的更改会触发由隔离范围内的双向绑定创建的watch()These lines是关键的......
  5. 隔离范围创建的$digest检查双向绑定的值是否与父级的值同步。如果不是(并且不在这种情况下),父级的值将被复制到隔离范围,即使隔离范围的值也已更改,实际上已更改
  6. Misko's famous post on Angular data-binding描述了$digest周期方法的好处。你在这里看到的是$timeout()改变coalesence的方法的有意识的副作用,正如源代码评论所说,parent changed and it has precedence ......这意味着你的孤立范围的变化会失去

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

    $compile documentation说:

      

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

    这意味着,在第2步,您可以通过以下对象地图传递parentUpdate({pkey: 'D+' + $scope.key }) 的值:

    {{1}}

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

答案 1 :(得分:0)

使用$scope.$apply()代替$scope.$digest()也可以。这也将触发rootScope上的摘要。