2016-04-01 6 views
9

コンポーネントのコントローラに実装できる「新しい」$ onChangesメソッドが本当に満足しています。しかし、既存の配列にアイテムが追加されたときなどではなく、バインドされた変数が自分のコンポーネントの外から上書きされた場合にのみトリガーされるようです。

これは意図した動作またはバグですか? $ scopeを実行する以外に、入力バインディングの更新を聞く別の方法がありますか?$ watch on it?私は角1.5.3

答えて

16

まずTLを使用してい

; DR 一方向の結合を介して制限され、配列の場合は、ウォッチ式は、オブジェクトの等価性をチェックしませんが追加が、参照を使用していますチェック。つまり、配列に要素を追加すると、ウォッチャーは決して 'ダーティ'にならないため、 '$ onChanges'メソッドは実行されません。

私はこれを示しplnkr作成しました:と「外の変化の配列参照」「の外側に野菜を追加する」と「$ onChanges呼び出しの数」を見てをクリックします http://plnkr.co/edit/25pdLE?p=preview

を。後者のボタンでのみ変更されます。完全に何が起こっているかを把握する

完全な説明 、我々は角度コードベースをチェックする必要があります。 '<'バインディングが見つかると、次のコードを使用してウォッチ式を設定します。

case '<': 
     if (!hasOwnProperty.call(attrs, attrName)) { 
      if (optional) break; 
      attrs[attrName] = void 0; 
     } 
     if (optional && !attrs[attrName]) break; 

     parentGet = $parse(attrs[attrName]); 

     destination[scopeName] = parentGet(scope); 
// IMPORTANT PART // 
     removeWatch = scope.$watch(parentGet, function  parentValueWatchAction(newParentValue) { 
      var oldValue = destination[scopeName]; 
      recordChanges(scopeName, newParentValue, oldValue); 
      destination[scopeName] = newParentValue; 
     }, parentGet.literal); 
// ------------- // 
     removeWatchCollection.push(removeWatch); 
     break; 

ここで重要な部分は、 'scope。$ watch'式がどのように設定されているかです。渡される唯一のパラメーターは、解析された式とリスナー関数です。リスナー関数は、 '$ watch'がダイジェストサイクルで汚れていると検出されます。呼び出されると、リスナーは 'recordChanges'メソッドを実行します。これは '$ postDigest'フェーズで実行される '$ onChanges'コールバックタスクを記録し、 '$ onChanges'ライフサイクルフックをリスンしているすべてのコンポーネントに通知し、値が変更された場合に通知します。

ここで留意すべき重要な点は、 '$ watcher'が決して汚れていない場合、 '$ onChanges'コールバックがトリガーされないことです。しかし、さらに重要なのは、 '$ watch'式が作成される方法によって、参照が変更されない限り、決して汚れてはいけないということです。このような場合は、途中でここにバインディングが設定されている一つの方法ではないので、

$watch: function(watchExp, listener, objectEquality, prettyPrintExpression) 

:あなたの代わりに参照のオブジェクトの間の等価性をチェックしたい場合は、このために要求する追加の三番目のパラメータを渡す必要がありますそれは常に参照のためにチェックします。

これは、要素を配列に追加すると、参照が変更されないことを意味します。つまり、 '$ watcher'は決して汚れてはいけません。つまり、 '$ onChanges'メソッドは配列の変更に対して呼び出されません。これを実証するために

、私はplnkrを作成しました: http://plnkr.co/edit/25pdLE?p=preview

それは、外側と内側の2つのコンポーネントが含まれています。 アウターには入力ボックスで変更可能なプリミティブな文字列値と、要素を追加したり参照を変更したりして拡張できる配列があります。
Innerには、値と配列の一方向限定変数が2つあります。すべての変更をリッスンします。

this.$onChanges = setType; 
function setType() { 
    console.log("called"); 
    vm.callCounter++; 
} 

入力フィールドに入力すると、毎回 '$ onChanges'コールバックが発生します。文字列はプリミティブなので、 '$ watcher'が汚れていて、 '$ onChanges'ライフサイクルフックが起動したことを意味しているため、これは論理的で予想通りです。私たちは、既存の固定長配列に値を追加します。ここ

this.changeValueArray = function() { 
     vm.valueArray.push("tomato"); 
    }; 

:あなたは「外で野菜を追加」をクリックすると

することは、それは次のコードを実行します。ここでは参考にしているので、 '$ watcher'は起動せず、コールバックもありません。あなたのコンソールでは、カウンターインクリメントまたは 'called'ステートメントは表示されません。

注:内部コンポーネント内の「配列に何かを追加」をクリックすると、外部コンポーネントの配列も変更されます。正確に同じ配列を参照で更新するので、これは論理的です。したがって、一方向バインディングであっても、配列は内部コンポーネントの内部から更新できます。

「外側の配列参照を変更」をクリックして外側のコンポーネントの参照を変更すると、 '$ onChanges'コールバックが期待通りに起動されます。

質問に答えるには:これは意図した動作またはバグですか?私はこれが意図された動作だと思います。そうでなければ、彼らはあなたに '<'バインディングをオブジェクトの等価性をチェックする方法で定義するオプションを与えていたでしょう。 githubでいつでも問題を作成することができますし、ご希望の場合は質問してください。

+0

ありがとうございます、私はGitHubで問題を作成します – jordydejong

+0

私の投稿は間違いなくここで参照できます。または私のplnkrを使用してください。 – KwintenP

+0

が作成されました:https://github.com/angular/angular.js/issues/14378 – jordydejong

関連する問題