Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does AngularJS implement its two-way data binding mechanism?

AngularJS allows you to implement two-way data binding. However, the interesting part is how it detects model changes? The model is usually a plain object like the code below. We can change the name property of $scope.user but how does AngularJS detect the model changed? Does AngularJS enum all the properties of the $scope object?

angular.module('myApp', [])
      .controller('BusinessCardController', function($scope){
        $scope.user = {
          name: 'Tanay Pant'
        }
      });

<input type="text" ng-model="user.name" placeholder="Full Name" />
like image 377
mind1n Avatar asked May 24 '15 15:05

mind1n


People also ask

What technique does AngularJS use for two way binding?

AngularJS creates a two way data-binding between the select element and the $ctrl. orderProp model. $ctrl. orderProp is then used as the input for the orderBy filter.

How is 2 way data binding implemented?

For two-way data binding, declare a private property and access its value using get and set methods in the component class. Then, assign that property to [(ngModel)] . For example, declare a private property with a get and set method, as shown below. Now, assign userName to [(ngModel)] in the template.

Is AngularJS support two way binding?

AngularJS follows Two-Way data binding model.

What is one way and two way data binding in Angular?

In one-way binding, the flow is one-directional. In a two-way binding, the flow is two-directional. This means that the flow of code is from ts file to Html file. This means that the flow of code is from ts file to Html file as well as from Html file to ts file.


2 Answers

There is a digest cycle, where the scope examines all of the $watch expressions and compares them with the previous value. It looks at the object models for changes, if the old value isn't the same as the new value, AngularJS will update the appropriate places, a.k.a dirty checking.

In order for the digest cycle to be execute $apply(fn) has to be run, this is how you enter the Angular world from JavaScript. How does $apply(fn) get called (taken from AngularJs integration with browser):

  1. The browser's event-loop waits for an event to arrive. An event is a user interaction, timer event, or network event (response from a server).
  2. The event's callback gets executed. This enters the JavaScript context. The callback can modify the DOM structure.
  3. Once the callback executes, the browser leaves the JavaScript context and re-renders the view based on DOM changes.

Data Binding

Digest Cycle Explanation

In order to achieve two-way binding, directives register watchers. For a page to be fast and efficient we need to try and reduce all these watchers that we create. So you should be careful when using two-way binding - i.e. only use it when you really needed. Otherwise use one-way:

<h1> {{ ::vm.title }} </h1>

Here it is quite obvious that the title of the page probably won't be changed while the user is on the page - or needs to see the new one if it is changed. So we can use :: to register a one-way binding during the template linking phase.

The main issues I've seen with explosions of watchers are grids with hundreds of rows. If these rows have quite a few columns and in each cell there is two-way data binding, then you're in for a treat. You can sit back and wait like in modem times for the page to load!

like image 104
Callum Linington Avatar answered Sep 22 '22 18:09

Callum Linington


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.

like image 45
Michael Hays Avatar answered Sep 20 '22 18:09

Michael Hays