1116

$scope.$watchと の使い方がわかりません$scope.$apply。公式ドキュメントは役に立ちません。

具体的にわからないこと:

  • それらは DOM に接続されていますか?
  • モデルに対する DOM の変更を更新するにはどうすればよいですか?
  • それらの間の接続点は何ですか?

このチュートリアルを試してみましたが$watch、当然の理解が必要$applyです。

$applyをし、何を$watchし、どのようにそれらを適切に使用するのですか?

4

6 に答える 6

1776

AngularJS を理解するには、AngularJS がどのように機能するかを知っておく必要があります。

ダイジェスト サイクルと $scope

何よりもまず、AngularJS はいわゆるダイジェスト サイクルの概念を定義します。このサイクルはループと見なすことができます。その間、AngularJS は、すべてのによって監視されているすべての変数に変更があるかどうかを確認します$scope。したがって$scope.myVar、コントローラーで定義し、この変数が監視対象としてマークされているmyVar場合、ループの各反復で変更を監視するように AngularJS に暗黙的に指示していることになります。

自然なフォローアップの質問は、次のようになります$scope。幸いなことに、いいえ。内のすべてのオブジェクトの変更を監視すると$scope、すぐにダイジェスト ループの評価に時間がかかり、すぐにパフォーマンスの問題が発生します。$scopeそのため、AngularJS チームは、いくつかの変数を監視対象として宣言する 2 つの方法を提供してくれました(以下を参照)。

$watch は $scope の変更をリッスンするのに役立ちます

$scope変数を監視対象として宣言するには、2 つの方法があります。

  1. 式を介してテンプレートで使用する<span>{{myVar}}</span>
  2. $watchサービスを介して手動で追加する

広告 1) これは最も一般的なシナリオであり、以前に見たことがあると思いますが、これがバックグラウンドで監視を作成していることを知りませんでした。はい、ありました!AngularJS ディレクティブ ( などng-repeat) を使用すると、暗黙的なウォッチも作成できます。

広告 2) これは、独自の時計を作成する方法です。サービスは、に添付された値が変更さ$watchれたときにコードを実行するのに役立ちます。$scopeめったに使用されませんが、役立つ場合があります。たとえば、'myVar' が変更されるたびに何らかのコードを実行する場合は、次のようにします。

function MyController($scope) {

    $scope.myVar = 1;

    $scope.$watch('myVar', function() {
        alert('hey, myVar has changed!');
    });

    $scope.buttonClicked = function() {
        $scope.myVar = 2; // This will trigger $watch expression to kick in
    };
}

$apply を使用すると、変更をダイジェスト サイクルに統合できます

$applyこの機能は統合メカニズムと考えることができます。ご覧のとおり、オブジェクトに直接アタッチされた監視変数$scopeを変更するたびに、AngularJS は変更が発生したことを認識します。これは、AngularJS がこれらの変更を監視することを既に知っているためです。そのため、フレームワークによって管理されるコードで発生した場合、ダイジェスト サイクルは続行されます。

ただし、AngularJS の世界の外で何らかの値を変更し、変更が正常に反映されることを確認したい場合があります。これを考慮してください-jQueryのハンドラー$scope.myVar内で変更される値があります。$.ajax()これは、将来のある時点で発生します。AngularJS は、jQuery を待機するように指示されていないため、これが発生するのを待つことができません。

これに取り組むために、$applyが導入されました。消化サイクルを明示的に開始できます。ただし、これは一部のデータを AngularJS に移行する (他のフレームワークとの統合) 場合にのみ使用する必要があります。AngularJS がエラーをスローするため、この方法を通常の AngularJS コードと組み合わせて使用​​しないでください。

これらすべてが DOM とどのように関連しているのでしょうか?

さて、これですべてがわかったので、もう一度チュートリアルに従う必要があります。$scopeダイジェスト サイクルは、何も変更がない限り、すべての にアタッチされたすべてのウォッチャーを評価することにより、UI と JavaScript コードの同期を維持します。ダイジェスト ループでそれ以上変更が発生しない場合は、終了したと見なされます。

コントローラーで明示的にオブジェクトをオブジェクトにアタッチする$scope{{expression}}、ビューで直接フォームで宣言することにより、オブジェクトをアタッチできます。

さらなる読み物:

于 2013-02-27T13:14:33.173 に答える
162

AngularJS では、モデルを更新し、ビュー/テンプレートが DOM を「自動的に」(組み込みまたはカスタム ディレクティブを介して) 更新します。

$apply と $watch はどちらも Scope メソッドであり、DOM とは関係ありません。

概念ページ (セクション「実行時」) には、$digest ループ、$apply、$evalAsync キュー、および $watch リストのかなり適切な説明があります。テキストに添えられた写真は次のとおりです。

$ダイジェスト ループ

スコープにアクセスできるコード (通常はコントローラーとディレクティブ (それらのリンク関数および/またはコントローラー)) は、AngularJS がそのスコープに対して評価する「 watchExpression 」を設定できます。この評価は、AngularJS が $digest ループ (特に、「$watch list」ループ) に入るたびに発生します。個々のスコープ プロパティを監視したり、2 つのプロパティを一緒に監視する関数を定義したり、配列の長さを監視したりできます。

「AngularJS の内部」で何かが起こった場合 – たとえば、AngularJS の双方向データバインディングが有効になっている (つまり、ng-model を使用している) テキストボックスに入力すると、$http コールバックが起動します。 – $apply は既に呼び出されているため、上の図の「AngularJS」の長方形の中にあります。すべての watchExpressions が評価されます (さらに変更が検出されなくなるまで、複数回評価される可能性があります)。

「AngularJS の外部」で何かが発生した場合 (たとえば、ディレクティブで bind() を使用した後にそのイベントが発生し、コールバックが呼び出されたり、jQuery に登録されたコールバックが発生したりする場合)、「ネイティブ」の四角形にとどまっています。コールバック コードが $watch が監視しているものを変更する場合は、$apply を呼び出して AngularJS の四角形に入り、$digest ループを実行します。したがって、AngularJS は変更を認識してその魔法を実行します。

于 2013-02-28T00:48:42.743 に答える
55

AngularJS は、このevents-loopを拡張して、 と呼ばれるものを作成しますAngularJS context

$watch()

UI で何かをバインドするたび$watchに、$watchリストに a を挿入します。

User: <input type="text" ng-model="user" />
Password: <input type="password" ng-model="pass" />

ここでは$scope.user、最初の入力に$scope.passバインドされている と、2 番目の入力にバインドされている があります。これを行うと、リストに 2 つの$watches が$watch追加されます。

テンプレートがロードされると、別名リンク段階で、コンパイラはすべてのディレクティブを探し、$watch必要なすべての es を作成します。

AngularJS は$watch$watchcollectionおよび を提供します$watch(true)以下は、ウォッチャーから取得した 3 つすべてを詳細に説明するきちんとした図です。

ここに画像の説明を入力してください

angular.module('MY_APP', []).controller('MyCtrl', MyCtrl)
function MyCtrl($scope,$timeout) {
  $scope.users = [{"name": "vinoth"},{"name":"yusuf"},{"name":"rajini"}];

  $scope.$watch("users", function() {
    console.log("**** reference checkers $watch ****")
  });

  $scope.$watchCollection("users", function() {
    console.log("**** Collection  checkers $watchCollection ****")
  });

  $scope.$watch("users", function() {
    console.log("**** equality checkers with $watch(true) ****")
  }, true);

  $timeout(function(){
     console.log("Triggers All ")
     $scope.users = [];
     $scope.$digest();

     console.log("Triggers $watchCollection and $watch(true)")
     $scope.users.push({ name: 'Thalaivar'});
     $scope.$digest();

     console.log("Triggers $watch(true)")
     $scope.users[0].name = 'Superstar';
     $scope.$digest();
  });
}

http://jsfiddle.net/2Lyn0Lkb/

$digestループ

ブラウザーが AngularJS コンテキストで管理できるイベントを受け取ると、$digestループが発生します。このループは、2 つの小さなループで構成されています。1 つは$evalAsyncキューを処理し、もう 1 つは$watch list. は、私たちが持って$digestいるリストをループします$watch

app.controller('MainCtrl', function() {
  $scope.name = "vinoth";

  $scope.changeFoo = function() {
      $scope.name = "Thalaivar";
  }
});

{{ name }}
<button ng-click="changeFoo()">Change the name</button>

$watchng-click はウォッチを作成しないため、ここでは 1 つしかありません。

ボタンを押します。

  1. ブラウザーは、AngularJS コンテキストに入るイベントを受け取ります
  2. ループが実行され、$digestすべての $watch に変更が求められます。
  3. $watch$scope.name の変更を監視していた が変更を報告するため、別のループが強制されます$digest
  4. 新しいループは何も報告しません。
  5. ブラウザはコントロールを取り戻し、$scope.name の新しい値を反映して DOM を更新します。
  6. ここで重要なことは、AngularJS コンテキストに入るすべてのイベントが$digestループを実行することです。つまり、入力に文字を書き込むたび$watchに、このページのすべてをチェックするループが実行されます。

$適用()

イベントが発生したときに呼び出すと$apply、角度コンテキストを通過しますが、呼び出さないと、その外側で実行されます。それはそれと同じくらい簡単です。$apply内部でループを呼び出し、$digest()すべてのウォッチを繰り返し処理して、新しく更新された値で DOM が更新されるようにします。

メソッドはチェーン$apply()全体でウォッチャーをトリガーしますが、メソッドは現在のウォッチャーとその. 上位のオブジェクトがローカルの変更について知る必要がない場合は、 を使用できます$scope$digest()$scopechildren$scope$digest()

于 2016-04-22T13:06:59.507 に答える
18

$watch$apply$digestおよびダイジェスト サイクルをカバーする非常に詳細なビデオを見つけました。

以下は、概念を説明するためにこれらのビデオで使用されている 2 枚のスライドです (念のため、上記のリンクが削除されているか機能していない場合)。

ここに画像の説明を入力してください

上の画像では、「$scope.c」はどのデータ バインディングでも (マークアップで) 使用されていないため、監視されていません。残りの 2 つ ($scope.a$scope.b) は監視されます。

ここに画像の説明を入力してください

上の画像から: それぞれのブラウザー イベントに基づいて、AngularJS はイベントをキャプチャし、ダイジェスト サイクルを実行し (すべての変更監視を通過します)、監視機能を実行し、DOM を更新します。$applyブラウザ イベントでない場合は、またはを使用してダイジェスト サイクルを手動でトリガーできます$digest

$applyとについての詳細$digest:

ここに画像の説明を入力してください

于 2016-11-20T16:28:37.220 に答える
17

などもあり$watchGroupます$watchCollection。具体的には、キャンバス、 WebGL、またはサーバー要求$watchGroupの別のビューなど、dom オブジェクトではないビューに複数のプロパティを持つオブジェクトを更新する関数を呼び出す場合に非常に役立ちます。

ここでは、ドキュメントリンク.

于 2015-03-18T10:50:18.770 に答える