10

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) からプロパティ (キー) を双方向バインディングし、コンテキストで呼び出されるメソッド (parentUpdate) を委任しています。親スコープの。

ここで、ディレクティブの ng-click イベント ハンドラー中に、parentUpdate メソッドを呼び出して、その中で何かをしたいと考えています。そのメソッドを呼び出すとき、親スコープのモデルが更新されていることを期待しています。しかし、実際にはそうではなく、これが私を困惑させていることです.

これは、parentUpdate 呼び出しを $timeout でラップすると期待どおりに機能するため、途中で $digest サイクルが欠落していることが原因である可能性があります。

誰かが欠けているものに光を当てることができますか? または、parentUpdate を適切に呼び出す方法は?

4

2 に答える 2

27

OK、私はこれでクラックを取るつもりです...$digest双方向ロジックが2つを同期するサイクルの前に、分離された子変数と親変数の両方を変更しているようです。詳細は次のとおりです。

  1. まずlock()、ボタンをクリックして関数を実行します。これにより、分離$scope.key変数が更新されます。注: これはすぐに親を更新しません。これは通常、次のサイクルで発生しますが、この場合は発生しません。読む...$scope.pKey$digest
  2. あなたの中では、親の変数を更新するlock()呼び出しがあります。parentUpdate()$scope.pKey
  3. THEN$digestサイクルが実行されます。ループすると、親スコープへの変更$scope.pKeyが正しく検出されます。
  4. への変更は、分離スコープ内の双方向バインディングによって作成された を$scope.pKeyトリガーします。これらの行は重要なものです..watch()
  5. 分離されたスコープによって作成されたwatch()は、双方向バインディングの値が親の値と同期しているかどうかをチェックします。そうでない場合 (このシナリオではそうでない場合)、分離スコープの値も変更され、実際には最初に変更されたにもかかわらず、親の値が分離スコープにコピーされます。

Angular データ バインディングに関する Misko の有名な投稿で$digestは、サイクル アプローチの利点について説明しています。ここに表示されているのは、$digest合体を変更するための のアプローチの意識的な副作用であり、ソース コードのコメントにあるように、parent changed and it has precedence...つまり、分離されたスコープの変更が失われることを意味します。

上記の$timeout()アプローチは、最初のサイクルで分離されたスコープの値のみを変更することでこの問題を回避$digestし、親スコープに正常にコピーして THEN を呼び出すことを可能にします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 に答える