How Does Data Binding Work in Angularjs

How does data binding work in AngularJS?

AngularJS remembers the value and compares it to a previous value. This is basic dirty-checking. If there is a change in value, then it fires the change event.

The $apply() method, which is what you call when you are transitioning from a non-AngularJS world into an AngularJS world, calls $digest(). A digest is just plain old dirty-checking. It works on all browsers and is totally predictable.

To contrast dirty-checking (AngularJS) vs change listeners (KnockoutJS and Backbone.js): While dirty-checking may seem simple, and even inefficient (I will address that later), it turns out that it is semantically correct all the time, while change listeners have lots of weird corner cases and need things like dependency tracking to make it more semantically correct. KnockoutJS dependency tracking is a clever feature for a problem which AngularJS does not have.

Issues with change listeners:

  • The syntax is atrocious, since browsers do not support it natively. Yes, there are proxies, but they are not semantically correct in all cases, and of course there are no proxies on old browsers. The bottom line is that dirty-checking allows you to do POJO, whereas KnockoutJS and Backbone.js force you to inherit from their classes, and access your data through accessors.
  • Change coalescence. Suppose you have an array of items. Say you want to add items into an array, as you are looping to add, each time you add you are firing events on change, which is rendering the UI. This is very bad for performance. What you want is to update the UI only once, at the end. The change events are too fine-grained.
  • Change listeners fire immediately on a setter, which is a problem, since the change listener can further change data, which fires more change events. This is bad since on your stack you may have several change events happening at once. Suppose you have two arrays which need to be kept in sync for whatever reason. You can only add to one or the other, but each time you add you fire a change event, which now has an inconsistent view of the world. This is a very similar problem to thread locking, which JavaScript avoids since each callback executes exclusively and to completion. Change events break this since setters can have far-reaching consequences which are not intended and non obvious, which creates the thread problem all over again. It turns out that what you want to do is to delay the listener execution, and guarantee, that only one listener runs at a time, hence any code is free to change data, and it knows that no other code runs while it is doing so.

What about performance?

So it may seem that we are slow, since dirty-checking is inefficient. This is where we need to look at real numbers rather than just have theoretical arguments, but first let's define some constraints.

Humans are:

  • Slow — Anything faster than 50 ms is imperceptible to humans and thus can be considered as "instant".

  • Limited — You can't really show more than about 2000 pieces of information to a human on a single page. Anything more than that is really bad UI, and humans can't process this anyway.

So the real question is this: How many comparisons can you do on a browser in 50 ms? This is a hard question to answer as many factors come into play, but here is a test case: http://jsperf.com/angularjs-digest/6 which creates 10,000 watchers. On a modern browser this takes just under 6 ms. On Internet Explorer 8 it takes about 40 ms. As you can see, this is not an issue even on slow browsers these days. There is a caveat: The comparisons need to be simple to fit into the time limit... Unfortunately it is way too easy to add a slow comparison into AngularJS, so it is easy to build slow applications when you don't know what you are doing. But we hope to have an answer by providing an instrumentation module, which would show you which are the slow comparisons.

It turns out that video games and GPUs use the dirty-checking approach, specifically because it is consistent. As long as they get over the monitor refresh rate (typically 50-60 Hz, or every 16.6-20 ms), any performance over that is a waste, so you're better off drawing more stuff, than getting FPS higher.

1-way, 2-way, 3-way, ... or more data binding in AngularJS?

(from JohnAndrews answer)
1-way data binding = your data model gets inserted into your views / templates usually from a controller and changes to your model in the controller change the data in your views.
2-way data binding = same as above, but you can make changes to your data model in the view as well.

3-way = your data is in sync with a remote storage (loke CouchDB)
4-way = your data is in sync with a local database (like localStorage or similar) and that database is in sync with a remote storage

Source https://docs.google.com/presentation/d/1NByDXl6YL6BJ6nL0G2DLyZs5Og2njE_MNJv6vNK5aoo/edit#slide=id.g34d447b28_10

AngularJS Directive and one way data binding

The reason you have to access the "one-way binding" in this way is because & denotes that the attribute expects an expression. The variable scope.oneWayBind is ALWAYS set to a function (even if you don't set the attribute to anything in your html code) that when called, evaluates the expression passed into that attribute. You showed that it can be called like this to get the value

scope.oneWayBind()

whereas this

scope.oneWayBind

will just return a reference to the function wrapping the expression passed in.

For reference: https://docs.angularjs.org/api/ng/service/$compile#-scope-

& or &attr -
...
Given <my-component my-attr="count = count + value"> and the isolate scope definition scope: { localFn:'&myAttr' }, the isolate scope property localFn will point to a function wrapper for the count = count + value expression...


You can also do this with & properties:

scope.oneWayBind({someProperty: 'someValue'})

which will cause someProperty to be locally available to the expression passed to one-way-bind. In other words, one-way-bind="method(someProperty)" will cause scope.oneWayBind({someProperty: 'someValue'}) to actually do method('someValue').

This is documented in the same section of that angular docs page:

Often it's desirable to pass data from the isolated scope via an expression to the parent scope. This can be done by passing a map of local variable names and values into the expression wrapper fn. For example, if the expression is increment(amount) then we can specify the amount value by calling the localFn as localFn({amount: 22}).

AngularJS: Access value of data binding from within directive

You can access it via scope e.g:

.directive('rszvers', function() {
return function(scope, element, attrs) {
console.log(scope.data.opts.a, scope.data.opts.b, scope.data.opts.c);
});

Angular JS two way data binding with state()

The data entered in the view can always be bound with the controller. All you have to do is to use $scope in the controller to define the variable and change it from the view. The last value that you will get in the controller will be updated one.

Try to implement this. You will get it clear.

Here is my index.html

<html>
<head>
<script src="bower_components/jquery/dist/jquery.js"></script>
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">
<script type="text/javascript" src="bower_components/angular/angular.js"></script>
<script type="text/javascript" src="bower_components/angular-ui-router/release/angular-ui-router.js"></script>

<script type = "text/javascript" src = "index.js"></script>
</head>
<body ng-app="myApp">
<div ui-view>
</div>

</body>
</html>

Here is my index.js

angular.module("myApp",['ui.router'])

.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'first.html'
})
$urlRouterProvider.otherwise('/login');
})

.controller('LoginCtrl', function($scope, $http) {

$scope.username = "x";
$scope.password = "x";

$scope.loginProcess = function () {

var JSON_data = {
email: $scope.username,
password: $scope.password
};
}
});

Here is my first.html

<div class="list padding"  ng-controller="LoginCtrl">
<label class="item item-input rounded-box">
<input type="text" placeholder="Username" ng-model="username">
</label>

<label class="item item-input rounded-box">
<input type="password" placeholder="Password" ng-model="password">
</label>
</div>

And it does bind. It binds a little late than the state() controller declaration but it does.

Here is the plunker https://plnkr.co/edit/JSMawagSsy4ucfW4SE8M?p=preview

one way and two way data binding in angularJs

from the docs: One-time expressions
will stop recalculating once they are stable, which happens after the
first digest if the expression result is a non-undefined value.

My understanding of one-time binding is after the first initialization of the scope variable if the object value changes the view will NOT change.
because the watchers are not in effect.
ex

$scope.myVar=null;
<p>{{::myVar}}</p>

if the there are any changes to $scope.myVar those will not effect in the view
because it will take only its first initialization value. thats null.

Data Binding between pages in Angularjs

Found the Solution to what I was looking for, The solution is in the Angular docs, here is the link http://docs.angularjs.org/cookbook/deeplinking.

Some part of the example on that link answers my question.

AngularJS data binding when using ng-repeat

I would also recommend to see the ng-options directive to popolate the select HTML element. As you can see from the link, you can have your week bounded to the ng-model scope variable.

https://docs.angularjs.org/api/ng/directive/select

AngularJS - using data binding {{}} in ng-click

From the docs, ngClick just evaluates the expression in the context of the scope. There's nothing stopping you from referencing a function dynamically, but I'm not sure this is the intended method. I would probably call a function explicitly and switch the behavior based on a parameter instead like ng-click='myFunction(myParams)'. Nonetheless, here's an example of what you what to accomplish. http://jsfiddle.net/8cvGt/2/

HTML

<div ng-app='foo' ng-controller='ctrl'>
<div ng-click='this[myVar]()'>{{ bar }}</div>
</div>

JavaScript

var app = angular.module('foo',[]).controller('ctrl',function($scope) {
$scope.myVar = 'callIt';
$scope.bar = 'before';
$scope.callIt = function() {
$scope.bar = 'after';
}
});


Related Topics



Leave a reply



Submit