Two-way binding is limited almost exclusively to elements that use ng-model
. The direction going from view to model uses standard event handlers to detect changes that must be updated within the model (e.g., onchange
). The direction going from the model back to the view is updated during a $digest
. But we do not call $digest
directly.
Every element that is on your page that is going to respond to the digest cycle will, somewhere, attach a listener and an expression to its scope using $watch
. When you write {{ foo() }}
, or when you use ng-model='user.name'
, internally there is a call to $watch
made on your behalf with a Javascript expression that will be run every time a digest cycle is run. This registration might happen during the compile of the template (our first example), or it might happen during the link phase of a directive (our second).
There is no magic here. The listeners that are attached are regular functions -- in our example, the listener for the expression foo()
is provided for you, and it will update the html text on the page, while the listener for the expression user.name
will call setText
, or setOption
, or whatever is required by the particular input which ng-model
has been attached.
While angular can handle most of the listening, you can attach your own watch expressions with your own listeners manually inside any function that has access to a scope (scope is important because we will tear down those watchers if the corresponding parts of the page are removed). Be mindful of excess. Bindings aren't free, and the more things that are bound, the slower the page will respond. One-time bindings are one way of reducing this cost. Using $on
with $emit
and $broadcast
are another.
So when is digest called? It is certainly not automatic. If the digest cycle is running, it means someone somewhere called $apply
on their scope or on the root scope. ng-model
attaches handlers which will respond to regular html events and will make calls to $apply
on your behalf. But foo()
, on the other hand, will never get called until some other bit of script somewhere calls $apply
. Fortunately, most functions that you fill out for angular wrap those functions with a call to $apply
, so you don't often have to make the call yourself (e.g., $timeout
is wrapped with $apply
, which is why we use it instead of setTimeout
). But if you were using something outside of the scope of angular (a 3rd party library that connects to events), you would need to remember to call $apply
yourself, and just like above, you can do this manually by calling $apply
anywhere you have access to a scope.