10

I have the following code, which can also be fiddled on 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:

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.

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.

It's probably because of some missing $digest cycles in the middle, since wrapping the parentUpdate call with $timeout would work as expected.

Could someone shed some light on what's missing? Or how to properly invoked parentUpdate?

4

2 回答 2

27

好的,我将对此进行破解...看来您正在更改孤立的子变量和父变量,然后再进行$digest双向逻辑同步两者的循环。这是详细信息:

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

Misko 关于 Angular 数据绑定的著名文章描述了$digest循环方法的好处。您在这里看到的是$digest' 更改合并方法的有意识的副作用,正如源代码注释所说,parent changed and it has precedence... 这意味着您的孤立范围的更改会丢失。

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

$compile文档说:

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

pkey这意味着,在第 2 步,您可以通过如下对象映射传入您的值:

parentUpdate({pkey: 'D+' + $scope.key })

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

于 2013-10-17T14:26:29.783 回答
0

使用$scope.$apply()而不是也$scope.$digest()有效。这也将触发 rootScope 上的摘要。

于 2015-02-04T14:06:10.070 回答