AngularJSでデータバインディングはどのように機能しますか?


1957

AngularJSフレームワークでデータバインディングはどのように機能しますか?

彼らのサイトで技術的な詳細は見つかりませんでした。データがビューからモデルに伝達されるときの動作は多かれ少なかれ明確です。しかし、AngularJSは、セッターとゲッターなしでモデルプロパティの変更をどのように追跡するのでしょうか。

この作業を行うJavaScriptウォッチャーがあることがわかりました。ただし、Internet Explorer 6およびInternet Explorer 7 ではサポートされていません。では、AngularJSは、たとえば次の変更を行い、この変更をビューに反映したことをどのようにして知るのでしょうか。

myobject.myproperty="new value";

10
angular 1.0.0rc1以降、モデラーを瞬時に更新するにはng-model-instant(docs-next.angularjs.org/api/…)を指定する必要があることに注意してください。それ以外の場合は、ぼかしイベントで更新されます。
Sotomajor 2012年

8
マルチェロのリンクが明らかに壊れているので、ここでは、再びです:github.com/mhevery/angular.js/blob/master/docs/content/guide/...
riffraff

6
@orian、そのリンクは悪いです。更新済み(私は想定)は同じ-docs.angularjs.org/guide/databinding
Kevin Meredith

11
この質問をまだ読んでいる人のために、Angular 2.0は、Angular 1.x以降、Webコンポーネントを操作し、以下の回答で多くの問題に対処するために、データバインディングの方法を大きく変更していることに注意してください。
2015

回答:


2745

AngularJSは値を記憶し、以前の値と比較します。これは基本的なダーティチェックです。値に変更があると、変更イベントが発生します。

この$apply()メソッドは、AngularJS以外の世界からAngularJSの世界に移行するときに呼び出すメソッドで、を呼び出します$digest()。ダイジェストは、単純に古いダーティーチェックです。すべてのブラウザで動作し、完全に予測可能です。

ダーティチェック(AngularJS)と変更リスナー(KnockoutJSBackbone.js)を対比するには:ダーティチェックは単純に見え、効率が悪いように見えるかもしれませんが(後で対処します)、常に意味的に正しいことがわかります。一方、変更リスナーには多くの奇妙なコーナーケースがあり、依存関係の追跡などにより意味的に正確にする必要があります。KnockoutJSの依存関係の追跡は、AngularJSにはない問題に対する賢い機能です。

変更リスナーの問題:

  • ブラウザはネイティブでサポートしていないため、構文はひどいです。はい、プロキシはありますが、すべてのケースで意味的に正しいわけではなく、もちろん古いブラウザにはプロキシはありません。一番下の行は、そのダーティチェックはあなたが行うことができますですPOJOを KnockoutJS、あなたが自分のクラスから継承するBACKBONE.JS力、およびアクセスアクセサを通して、あなたのデータのに対し、。
  • 合体を変更します。アイテムの配列があるとします。追加するためにループしているときに、アイテムを配列に追加するとします。追加するたびに、変更時にイベントを発生させ、UIをレンダリングします。これはパフォーマンスにとって非常に悪いです。必要なのは、UIを最後に一度だけ更新することです。変更イベントが細かすぎます。
  • 変更リスナーはデータをさらに変更でき、変更イベントをさらに起動できるため、変更リスナーはセッターですぐに起動します。これは問題です。スタックで一度にいくつかの変更イベントが発生する可能性があるため、これは悪いことです。何らかの理由で同期を保つ必要のある2つの配列があるとします。追加できるのはどちらか一方のみですが、追加するたびに変更イベントが発生し、一貫性のない世界のビューが表示されるようになりました。これは、各コールバックが排他的に実行されて完了するため、JavaScriptが回避するスレッドロックと非常によく似た問題です。変更イベントはこれを壊します。セッターが意図しない明白ではない広範囲にわたる結果をもたらす可能性があるため、スレッドの問題が繰り返し発生します。あなたがしたいことは、リスナーの実行を遅らせ、保証することです。

パフォーマンスはどうですか?

したがって、ダーティーチェックは非効率的であるため、私たちは遅いように見えるかもしれません。ここでは、理論的な議論だけでなく実数を調べる必要がありますが、まず、いくつかの制約を定義しましょう。

人間は:

  • 遅い — 50ミリ秒より速いものは人間には感知できないため、「インスタント」と見なすことができます。

  • 制限あり —実際には、1つのページで約2000を超える情報を人間に表示することはできません。それ以上のものは本当に悪いUIであり、人間はとにかくこれを処理することはできません。

だから本当の質問はこれです:50ミリ秒でブラウザー上でいくつの比較ができますか?これは、多くの要因が遊びに来るような答えに難しい質問ですが、ここではテストケースである:http://jsperf.com/angularjs-digest/6万のウォッチャーが作成されます。最新のブラウザでは、これには6ミリ秒未満かかります。上のInternet Explorer 8には、約40ミリ秒かかります。ご覧のとおり、最近の遅いブラウザでも問題ありません。注意点があります:比較は時間制限に合わせるために単純である必要があります...残念ながら、AngularJSに遅い比較を追加するのは非常に簡単です。やっている。しかし、私たちはインストルメンテーションモジュールを提供することで回答を得たいと考えています。これにより、比較が遅いことがわかります。

特に一貫性があるため、ビデオゲームとGPUはダーティチェックアプローチを使用していることがわかりました。モニターのリフレッシュレート(通常50〜60 Hz、または16.6〜20 msごと)を超えている限り、それ以上のパフォーマンスは無駄になるため、FPSを高くするよりも、より多くのものを描画する方が得策です。


32
@Mark-はい、KOで.extend({throttle:500})を追加するだけで、最後の変更イベントから500ミリ秒待機してからアクションを実行します。
Daniel Earwicker 2013年

158
この全体的な答えは、「50 fpsを取得する限り、人間の目ではそれを理解できないため、それを超えるパフォーマンスは無駄になるため、fpsを高くするよりも、より多くのものを描画する方がよい」以外の素晴らしい答えです。そのステートメントは、アプリケーションによっては完全に正しくありません。目は間違いなく50 fps以上を鑑賞でき、VRショーのさまざまな問題(John CarmackまたはMichael Abrashの最新の記事、特に後者のGDC 2013 VRトークを読む)として、50 fpsは実際には非常に遅いです。それ以外は、あなたの答えは素晴らしいです。誤報を広めたくないだけです。
Nate Bundy 2013

10
@DavidRivers私たちはちょうどuTorrentの1μsの= 0.000001sのようμsです
Thorgeir

33
「ダーティーチェックはノックアウトにない問題に対しては賢い機能である」として、この文は簡単に逆に言えます。ES6はオブザーバブルを使用しており、angularはダーティーチェックを排除しています。現実の世界はこの答えに追いつき、それが偽であることを示しました。
円錐形の

17
「50ミリ秒よりも速いものは人間には感知できない」というのは本当ではありません。テストでは、50msの更新レイテンシ(20fps)と16.6msの更新レイテンシ(60fps)を簡単に区別できることがわかりました。以前の速度で実行されているシーンは、人々が意識的にフレームレートを登録しなかった場合でも、一貫して全体的な「どのように感じた」評価が低くなります。
Crashworks 2014年

323

Miskoはすでにデータバインディングのしくみについて優れた説明をしていましたが、データバインディングのパフォーマンスの問題に関する見解を追加したいと思います。

Miskoが述べたように、約2000のバインディングで問題が発生し始めますが、いずれにしても、1ページに2000を超える情報を含めることはできません。これは本当かもしれませんが、すべてのデータバインディングがユーザーに見えるわけではありません。双方向バインディングを使用してあらゆる種類のウィジェットまたはデータグリッドの構築を開始すると、悪いUXを発生させることなく、2000バインディングに簡単にアクセスできます

たとえば、テキストを入力して使用可能なオプションをフィルタリングできるコンボボックスを考えてみます。この種のコントロールは、最大150個のアイテムを持つことができ、それでも非常に使いやすいです。いくつかの追加機能(たとえば、現在選択されているオプションの特定のクラス)がある場合、オプションごとに3〜5個のバインディングを取得し始めます。これらのウィジェットの3つをページに配置し(1つは国を選択し、もう1つはその国の都市を選択し、3つ目はホテルを選択します)、すでに1000から2000のバインディングのどこかにあります。

または、企業のWebアプリケーションのデータグリッドを検討してください。ページあたり50行は無理ではなく、各行に10〜20列ある場合があります。これをng-repeatsで構築したり、いくつかのバインディングを使用するいくつかのセルに情報がある場合、このグリッドのみで2000バインディングに近づいている可能性があります。

AngularJSを使用する場合、これは大きな問題であることがわかりました。これまでに確認できた唯一の解決策は、ngOnceを使用せずに、ウォッチャーと同様のトリックを登録解除する代わりに、双方向バインディングを使用せずにウィジェットを構築することです。 jQueryとDOM操作でDOMを構築するディレクティブ。そもそも、これはAngularを使用する目的に反していると思います。

これを処理する他の方法についての提案を聞きたいと思いますが、多分私は自分の質問を書く必要があります。私はこれをコメントに入れたかったのですが、それはあまりにも長すぎることがわかりました...

TL; DR
データバインディングは、複雑なページでパフォーマンスの問題を引き起こす可能性があります。


26
ええ、私はこれを2番目にします。私たちのアプリの主な責任は、異なるエンティティ間の接続を表示することです。特定のページに10のセクションがある場合があります。各セクションにはテーブルがあります。各テーブルには2〜5個の先行入力フィルターがあります。各テーブルには2〜5列があり、それぞれに10行があります。すぐにパフォーマンスの問題に遭遇し、「同様のトリック」オプションを使用します。
Scott Silvi、2013

10
Angularはデータバインディングだけでなく、他のアプリが引用した理由から、この機能を使用したくないアプリがあると言っても過言ではありませんか?DIとモジュール性のアプローチ自体は非常に価値があると思います。魔法の自動バインディングがあると便利ですが、既存のすべての実装でパフォーマンスのトレードオフがあります。Angularの方法は、CRUD Webアプリケーションの大部分にとって間違いなく優れており、人々はそれを極端にしようとすることで壁にぶつかっています。イベントリスニングの代替方法をサポートするのは良いことですが、単一のフレームワークでは基本的に複雑すぎますか?
Jason Boyd

8
Angularには、この問題を解決するための1つの方法とbind-once databindingがあります。さらに、リピーターソースのインデックスが追加され、コンテンツ全体のdomを再構築せずにリストを変更できるようになりました。
GauteLøken

6
@MW。正直なところ、私はbind-onceがコアにあると思いました。しかし、そうではないようです。これは、独自のディレクティブを作成するときに実行できるもので、基本的には監視せずにリンクします。しかしそれのためUXのmodがあります:github.com/pasvaz/bindonce
Gauteローケン

9
この読んで、誰のために未来からの叫び:結合1時間は今角度V1.3の中核機能である、もっとここで読む:docs.angularjs.org/guide/expression
のび太

158

$scopeオブジェクトをダーティチェックする

Angular array$scopeオブジェクトのウォッチャーをシンプルに維持します。検査$scopeするarrayと、呼び出されたが含まれていることがわかります$$watchers

各ウォッチャーは、objectとりわけ、

  1. ウォッチャーが監視している式。これは単なるattribute名前の場合もあれば、もっと複雑なものの場合もあります。
  2. 式の最後の既知の値。これは、式の現在の計算値に対してチェックできます。値が異なる場合、ウォッチャーは関数をトリガーし、$scopeダーティとしてマークします。
  3. ウォッチャーが汚れている場合に実行される関数。

ウォッチャーの定義方法

AngularJSでウォッチャーを定義するには、さまざまな方法があります。

  • 明示的$watchattributeon することができ$scopeます。

    $scope.$watch('person.username', validateUnique);
  • {{}}テンプレートに補間を配置できます(現在のにウォッチャーが作成されます$scope)。

    <p>username: {{person.username}}</p>
  • ng-modelウォッチャーを定義するなどのディレクティブを要求できます。

    <input ng-model="person.username" />

$digestサイクルは、彼らの最後の値に対するすべてのウォッチャーをチェックします

通常のチャネル(ng-model、ng-repeatなど)を介してAngularJSとやり取りすると、ディレクティブによってダイジェストサイクルがトリガーされます。

ダイジェストサイクルは、そのすべての子の深さ優先のトラバーサルです$scope。それぞれについて$scope object、繰り返し処理を行い$$watchers array、すべての式を評価します。新しい式の値が最後の既知の値と異なる場合、ウォッチャーの関数が呼び出されます。この関数は、DOMの一部を再コンパイルし、の値を再計算し$scope、をトリガーしAJAX request、必要なものを何でも実行できます。

すべてのスコープがトラバースされ、すべての監視式が最後の値に対して評価およびチェックされます。

ウォッチャーがトリガーされると、$scopeダーティです

ウォッチャーがトリガーされると、アプリは変更があったことを認識し$scope、ダーティとしてマークされます。

監視関数は$scope、親または親の他の属性を変更できます$scope。1つの$watcher関数がトリガーされた場合、他$scopeのがまだクリーンであることを保証できないため、ダイジェストサイクル全体を再度実行します。

これは、AngularJSに双方向バインディングがあるため、データを$scopeツリーに戻すことができるためです。$scopeすでに消化されているより高い値を変更する場合があります。おそらく、の値を変更します$rootScope

$digestが汚れている場合は、$digestサイクル全体を再度実行します

$digestダイジェストサイクルがクリーンになるまで(すべての$watch式は前のサイクルと同じ値になります)、またはダイジェストの制限に達するまで、サイクルをループし続けます。デフォルトでは、この制限は10に設定されています。

ダイジェストの制限に達すると、AngularJSによってコンソールでエラーが発生します。

10 $digest() iterations reached. Aborting!

ダイジェストはマシンでは難しいですが、開発者にとっては簡単です

ご覧のとおり、AngularJSアプリで何かが変更されるたびに、AngularJSは$scope階層内のすべてのウォッチャーをチェックして、応答方法を確認します。開発者にとってこれは非常に生産性の恩恵です。配線コードをほとんど作成する必要がないので、AngularJSは値が変更されたかどうかに気づき、アプリの残りの部分をその変更に一致させます。

マシンの観点からすると、これは非常に非効率的であり、あまりにも多くのウォッチャーを作成すると、アプリケーションの速度が低下します。Miskoは、アプリが古いブラウザーで遅く感じる前に、約4000人のウォッチャーの数字を引用しています。

この制限は、たとえばng-repeat大きなものJSON arrayを超えた場合に簡単に到達できます。ウォッチャーを作成せずにテンプレートをコンパイルするワンタイムバインディングなどの機能を使用して、これを軽減できます。

あまりにも多くのウォッチャーを作成しないようにする方法

ユーザーがアプリを操作するたびに、アプリ内のすべてのウォッチャーが少なくとも1回評価されます。AngularJSアプリの最適化の大きな部分は、$scopeツリー内のウォッチャーの数を減らすことです。これを行う簡単な方法の1つは、1回限りのバインディングです。

ほとんど変更されないデータがある場合は、次のように::構文を使用して一度だけバインドできます。

<p>{{::person.username}}</p>

または

<p ng-bind="::person.username"></p>

バインディングは、含まれているテンプレートがレンダリングされ、データがに読み込まれたときにのみトリガーされ$scopeます。

これは、ng-repeatアイテム数が多い場合に特に重要です。

<div ng-repeat="person in people track by username">
  {{::person.username}}
</div>

@ user2864740に感謝-Miskoの回答がトップになるのは正しいことです。彼は誰よりもフレームワークをよく知っており、彼がスタックオーバーフローと関わっていることはかなりクールです
。–

4
上記の回答を最上位にするべきだとは思わない。何かを知ることと、特定の質問に関連する/詳細な回答を書くことには違いがあります。称賛を得るためのより良い方法があります。とにかく..
user2864740 '10

1
私はそのようなことが本当であることを疑いませんが、質問と回答が質問に答えます:)
user2864740

3
ダーティチェックの動作と実際の評価をカバーする良い答えは、ミスコの答えでは明確ではなかったことが1つあります。
ストライダー、2015年

3
すばらしい詳細な答え。@superluminary、そのような答えに感謝します。また、この答えを読んだ後、注目すべき表現として非べき等表現を加えてはいけないということになりました。
Mangu Singh Rajpurohit 16

81

これは私の基本的な理解です。間違いかもしれません!

  1. アイテムは、$watchメソッドに関数(監視するものを返す)を渡すことで監視されます。
  2. 監視対象アイテムへの変更は、$applyメソッドによってラップされたコードのブロック内で行う必要があります。
  3. 終わりに、彼らは最後の時間以降に変更かどうかを確認するために時計や小切手のそれぞれを通過され呼び出されるメソッド走りました。$apply$digest$digest
  4. 変更が見つかると、すべての変更が安定するまでダイジェストが再度呼び出されます。

通常の開発では、HTMLのデータバインディング構文は、AngularJSコンパイラーにウォッチを作成するように指示し、コントローラーメソッドは$apply既に内部で実行されます。したがって、アプリケーション開発者にとってはすべてが透過的です。


4
applyメソッドはいつトリガーされますか?
numan salati 2012

3
@EliseuMonarダイジェストループは、何らかのイベントまたは$ apply()の呼び出しの結果として実行され、タイマーに基づいて定期的に呼び出されることはありません。AngularJSの$ watch関数どのように機能しますか?そして、AngularJSでバインディングとダイジェストはどのように機能しますか?
adl

1
@ remi、AngularJSの最新バージョンについては心配していません。彼らはすでにプロキシまたはObject.observeを使用していますか?そうでない場合、それらはまだダーティチェック時代にあり、モデル属性が変更されたかどうかを確認するタイミングループを構築します。
Eliseu Monar dos Santos 2014

1
ダイジェストは最大10回実行されるということを読んだsitepoint.com/understanding-angulars-apply-digest
user137717

62

私はしばらくこれを自分で考えました。セッターがなければAngularJS$scopeオブジェクトの変更はどのように変化しますか?それらをポーリングしますか?

実際に行うことは次のとおりです。モデルを変更する「通常の」場所は、すでにの根拠から呼び出されてAngularJSいる$applyため、コードの実行後に自動的に呼び出されます。コントローラーに、ng-clickある要素に接続されたメソッドがあるとします。AngularJSそのメソッドの呼び出しを一緒に配線するため$apply、適切な場所でを実行する機会があります。同様に、ビューに直接現れる式の場合、それらはによって実行されるAngularJSので実行され$applyます。

ドキュメンテーションがの外の$applyコードを手動で呼び出す必要があることについて述べている場合、それは実行時にコールスタック内のそれ自体に由来しないコードについて述べています。AngularJSAngularJS


32

写真で説明する:

データバインディングにはマッピングが必要です

スコープ内の参照は、テンプレート内の参照ではありません。2つのオブジェクトをデータバインドする場合、最初のオブジェクトをリッスンし、もう1つのオブジェクトを変更する3番目のオブジェクトが必要です。

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

ここで、を変更するときに<input>data-ref3に触れます。そして、古典的なデータバインドメカニズムはdata-ref4を変更します。では、他の{{data}}表現はどのように動くのでしょうか?

イベントは$ digest()につながります

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

角度は維持oldValueし、newValueすべての結合の。そして、すべてのAngularイベントの後、有名な$digest()ループはWatchListをチェックして、何かが変更されたかどうかを確認します。これらの角度のイベントはあるng-clickng-change$http完成... $digest()限り、いずれかのような意志ループoldValueから異なりnewValue

前の図では、data-ref1とdata-ref2が変更されていることがわかります。

結論

卵とチキンに少し似ています。誰が開始するかはわかりませんが、期待どおりにほとんどの場合うまくいくと思います。

もう1つのポイントは、メモリとCPUに対する単純なバインディングの深い影響を簡単に理解できることです。うまくいけば、デスクトップはこれを処理するのに十分な太さです。携帯電話はそれほど強くありません。


22

Scopeアタッチされているオブジェクトに変更があるかどうかの定期的なチェックはありません。スコープにアタッチされているすべてのオブジェクトが監視されるわけではありません。スコープはプロトタイプで$$ watchersを保守します。が呼び出されたときにScopeのみ、これを繰り返します。$$watchers$digest

Angularはこれらのそれぞれの$$ watchersにウォッチャーを追加します

  1. {{expression}} —テンプレート(および式が存在する他の場所)またはng-modelを定義するとき。
  2. $ scope。$ watch( 'expression / function')— JavaScriptで、angularが監視するスコープオブジェクトをアタッチできます。

$ watch関数は3つのパラメーターを受け取ります。

  1. 1つ目は、オブジェクトを返すだけのウォッチャー関数か、式を追加するだけです。

  2. 2つ目は、オブジェクトに変更があったときに呼び出されるリスナー関数です。DOMの変更などのすべてのものは、この関数で実装されます。

  3. 3番目は、ブール値を受け取るオプションのパラメーターです。trueの場合、angular deepはオブジェクトを監視し、falseの場合、Angularはオブジェクトを参照するだけです。$ watchの大まかな実装は次のようになります

Scope.prototype.$watch = function(watchFn, listenerFn) {
   var watcher = {
       watchFn: watchFn,
       listenerFn: listenerFn || function() { },
       last: initWatchVal  // initWatchVal is typically undefined
   };
   this.$$watchers.push(watcher); // pushing the Watcher Object to Watchers  
};

Angularにはダイジェストサイクルと呼ばれる興味深いものがあります。$ scope。$ digest()への呼び出しの結果として、$ digestサイクルが開始します。ng-clickディレクティブを介してハンドラー関数の$ scopeモデルを変更するとします。その場合、AngularJSは$ digest()を呼び出すことで$ digestサイクルを自動的にトリガーします。ng-clickに加えて、モデルを変更できる組み込みディレクティブ/サービスが他にもいくつかあります(ng-model、$ timeoutなど)。そして$ digestサイクルを自動的にトリガーします。$ digestの大まかな実装は次のようになります。

Scope.prototype.$digest = function() {
      var dirty;
      do {
          dirty = this.$$digestOnce();
      } while (dirty);
}
Scope.prototype.$$digestOnce = function() {
   var self = this;
   var newValue, oldValue, dirty;
   _.forEach(this.$$watchers, function(watcher) {
          newValue = watcher.watchFn(self);
          oldValue = watcher.last;   // It just remembers the last value for dirty checking
          if (newValue !== oldValue) { //Dirty checking of References 
   // For Deep checking the object , code of Value     
   // based checking of Object should be implemented here
             watcher.last = newValue;
             watcher.listenerFn(newValue,
                  (oldValue === initWatchVal ? newValue : oldValue),
                   self);
          dirty = true;
          }
     });
   return dirty;
 };

JavaScriptのsetTimeout()関数を使用してスコープモデルを更新する場合、Angularは何を変更するかを知る方法がありません。この場合、$ apply()を手動で呼び出して$ digestサイクルをトリガーするのは私たちの責任です。同様に、DOMイベントリスナーを設定し、ハンドラー関数内の一部のモデルを変更するディレクティブがある場合は、$ apply()を呼び出して、変更を有効にする必要があります。$ applyの大きなアイデアは、Angularを認識しないコードを実行できるということです。そのコードは、スコープの設定を変更する可能性があります。そのコードを$ applyでラップすると、$ digest()の呼び出しが処理されます。$ apply()の大まかな実装。

Scope.prototype.$apply = function(expr) {
       try {
         return this.$eval(expr); //Evaluating code in the context of Scope
       } finally {
         this.$digest();
       }
};

15

AngularJSは、3つの強力な関数($ watch()$ digest()、および$ apply())を使用してデータバインディングメカニズムを処理します 。ほとんどの場合、AngularJSは$ scope。$ watch()および$ scope。$ digest()を呼び出しますが、場合によっては、これらの関数を手動で呼び出して新しい値で更新する必要があります。

$ watch():-

この関数は、$ scopeの変数の変更を監視するために使用されます。これは、式、リスナー、等価オブジェクトの3つのパラメーターを受け入れます。リスナーと等価オブジェクトはオプションのパラメーターです。

$ digest() -

この関数は、$ scopeオブジェクトとその子$ scopeオブジェクト
(ある場合)のすべての監視を反復処理します。$ digest()が監視を反復するとき、式の値が変更されたかどうかをチェックします。値が変更された場合、AngularJSは新しい値と古い値でリスナーを呼び出します。$ digest()関数は、AngularJSが必要だと考えるたびに呼び出されます。たとえば、ボタンをクリックした後、またはAJAX呼び出しの後。AngularJSが$ digest()関数を呼び出さない場合があります。その場合は、自分で呼び出す必要があります。

$ apply() -

Angularは、AngularJSコンテキスト内にあるモデルの変更のみを自動的に自動更新します。Angularコンテキスト以外のモデル(ブラウザーのDOMイベント、setTimeout、XHR、サードパーティライブラリなど)で変更を行う場合は、$ apply()を手動で呼び出して、Angularに変更を通知する必要があります。$ apply()関数呼び出しが完了すると、AngularJSが$ digest()を内部的に呼び出すため、すべてのデータバインディングが更新されます。


7

たまたま、人のデータモデルをフォームにリンクする必要がありました。私が行ったのは、データをフォームに直接マッピングすることでした。

たとえば、モデルに次のようなものがあるとします。

$scope.model.people.name

フォームの制御入力:

<input type="text" name="namePeople" model="model.people.name">

これにより、オブジェクトコントローラの値を変更すると、ビューに自動的に反映されます。

サーバーデータから更新されたモデルを渡した例は、郵便番号を要求すると、そのビューに関連付けられたコロニーと都市のリストをロードに基づいてロードし、デフォルトでユーザーに最初の値を設定する場合です。そして、これが私が非常にうまく機能したこと、何が起こるかというとangularJS、モデルを更新するのに数秒かかることがあります。これを行うには、データを表示しながらスピナーを配置できます。


14
私はこの答えを5回読みましたが、ここで何が意味されているのかまだわかりません。
sbedulin 2015年

1
答えは私にはパズルのようです
アマン

6
  1. 一方向データバインディングは、値がデータモデルから取得され、HTML要素に挿入されるアプローチです。ビューからモデルを更新する方法はありません。古典的なテンプレートシステムで使用されます。これらのシステムは、データを一方向にのみバインドします。

  2. Angularアプリのデータバインディングは、モデルとビューコンポーネント間のデータの自動同期です。

データバインディングを使用すると、アプリケーションでモデルを単一の真実のソースとして扱うことができます。ビューは常にモデルの投影です。モデルが変更された場合、ビューは変更を反映し、その逆も同様です。


5

以下は、入力フィールドを使用した、AngularJSとのデータバインディングの例です。後で説明します

HTMLコード

<div ng-app="myApp" ng-controller="myCtrl" class="formInput">
     <input type="text" ng-model="watchInput" Placeholder="type something"/>
     <p>{{watchInput}}</p> 
</div>

AngularJSコード

myApp = angular.module ("myApp", []);
myApp.controller("myCtrl", ["$scope", function($scope){
  //Your Controller code goes here
}]);

上記の例でわかるように、AngularJSng-modelHTML要素、特にinputフィールドで何が発生するかをリッスンして監視するために使用します。何かが起こったら、何かしてください。私たちの場合、ng-model口ひげ表記を使用して、ビューにバインドされています{{}}。入力フィールドに入力されたものはすべて、画面に即座に表示されます。そして、それがデータバインディングの美点であり、AngularJSを最も単純な形で使用しています。

お役に立てれば。

Codepenの実際の例を 見る


5

AngularJsは、双方向のデータバインディングをサポートしています。
データビューにアクセスできることを意味します->コントローラーコントローラー->表示

例:

1)

// If $scope have some value in Controller. 
$scope.name = "Peter";

// HTML
<div> {{ name }} </div>

O / P

Peter

ng-modelLike:-2)でデータをバインドできます。

<input ng-model="name" />

<div> {{ name }} </div>

上記の例では、ユーザーが入力するものは何でも、<div>タグに表示されます。

入力をhtmlからコントローラーにバインドする場合:
-3)

<form name="myForm" ng-submit="registration()">
   <label> Name </lbel>
   <input ng-model="name" />
</form>

ここnameで、コントローラで入力を使用する場合は、

$scope.name = {};

$scope.registration = function() {
   console.log("You will get the name here ", $scope.name);
};

ng-modelビューをバインドし、それを式でレンダリングします{{ }}
ng-modelビューでユーザーに表示され、ユーザーが操作するデータです。
したがって、AngularJでデータをバインドするのは簡単です。


4

Angular.jsは、ビューで作成するすべてのモデルのウォッチャーを作成します。モデルが変更されるたびに、「ng-dirty」クラスがモデルに追加されるため、ウォッチャーはクラス「ng-dirty」を持つすべてのモデルを監視し、コントローラーでその値を更新します(逆も同様)。


3

データバインディング:

データバインディングとは何ですか?

ユーザーがビューのデータを変更するたびに、スコープモデルでその変更の更新が発生します。逆も同様です。

どのように可能ですか?

簡潔な答え : 消化サイクルの助けを借りて。

説明: Angular jsはスコープモデルにウォッチャーを設定し、モデルに変更があった場合にリスナー関数を起動します。

$scope.$watch('modelVar' , function(newValue,oldValue){

// Dom update code with new value

});

では、ウォッチャー関数はいつ、どのように呼び出されますか?

ウォッチャー関数は、ダイジェストサイクルの一部として呼び出されます。

ダイジェストサイクルは、ng-model、ng-bind、$ timeout、ng-clickなどの角度付きのjs組み込みディレクティブ/サービスの一部として自動的にトリガーされ、ダイジェストサイクルをトリガーできます。

ダイジェストサイクル機能:

$scope.$digest() -> digest cycle against the current scope.
$scope.$apply() -> digest cycle against the parent scope 

すなわち$rootScope.$apply()

注:$ apply()は$ rootScope。$ digest()と同じです。これは、ダーティチェックがルートまたはトップまたは親スコープから角度jsアプリケーションのすべての子$ scopesに至るまで開始することを意味します。

上記の機能は、前述のバージョンのブラウザーIEでも、アプリケーションがAngular jsアプリケーションであることを確認するだけで機能します。つまり、scriptタグで参照されるangularjsフレームワークスクリプトファイルを使用しています。

ありがとうございました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.