Data Binding

Data-binding in AngularJS apps is the automatic synchronization of data between the model and view components. The way that AngularJS implements data-binding lets you treat the model as the single-source-of-truth in your application. The view is a projection of the model at all times. When the model changes, the view reflects the change, and vice versa.

Data Binding in Classical Template Systems

Most templating systems bind data in only one direction: they merge template and model components together into a view. After the merge occurs, changes to the model or related sections of the view are NOT automatically reflected in the view. Worse, any changes that the user makes to the view are not reflected in the model. This means that the developer has to write code that constantly syncs the view with the model and the model with the view.

Data Binding in AngularJS Templates

AngularJS templates work differently. First the template (which is the uncompiled HTML along with any additional markup or directives) is compiled on the browser. The compilation step produces a live view. Any changes to the view are immediately reflected in the model, and any changes in the model are propagated to the view. The model is the single-source-of-truth for the application state, greatly simplifying the programming model for the developer. You can think of the view as simply an instant projection of your model.

Because the view is just a projection of the model, the controller is completely separated from the view and unaware of it. This makes testing a snap because it is easy to test your controller in isolation without the view and the related DOM/browser dependency.

Data binding in AngularJS is the synchronization between the model and the view.

One-way dataflow and Events

One-way dataflow was introduced in AngularJS 1.5, and redefines component communication.

Here are some advisories for using one-way dataflow:

  • In components that receive data, always use one-way databinding syntax ‘<‘
  • Do not use ‘=’ two-way databinding syntax anymore, anywhere
  • Components that have bindings should use $onChanges to clone the one-way binding data to break Objects passing by reference and updating the parent data
  • Use $event as a function argument in the parent method (see stateful example below $ctrl.addTodo($event))
  • Pass an $event: {} Object back up from a stateless component (see stateless example below this.onAddTodo).
  • Bonus: Use an EventEmitter wrapper with .value() to mirror Angular, avoids manual $event Object creation
  • Why? This mirrors Angular and keeps consistency inside every component. It also makes state predictable.

Data Model

AngularJS applications usually have a data model. The data model is a collection of data available for the application.

Example

var app = angular.module(‘myApp’, []);

app.controller(‘myCtrl’, function($scope) {

$scope.firstname = “Demo”;

$scope.lastname = “User”;

});

HTML View

The HTML container where the AngularJS application is displayed, is called the view. The view has access to the model, and there are several ways of displaying model data in the view. You can use the ng-bind directive, which will bind the innerHTML of the element to the specified model property:

Example

<p ng-bind=”firstname”></p>

You can also use double braces {{ }} to display content from the model:

Example

<p>First name: {{firstname}}</p>

The ng-model Directive

Use the ng-model directive to bind data from the model to the view on HTML controls (input, select, textarea)

Example

<input ng-model=”firstname”>

The ng-model directive provides a two-way binding between the model and the view.

Two-way Binding

Data binding in AngularJS is the synchronization between the model and the view. When data in the model changes, the view reflects the change, and when data in the view changes, the model is updated as well. This happens immediately and automatically, which makes sure that the model and the view is updated at all times.

Example

<div ng-app=”myApp” ng-controller=”myCtrl”>

Name: <input ng-model=”firstname”>

<h1>{{firstname}}</h1>

</div>

<script>

var app = angular.module(‘myApp’, []);

app.controller(‘myCtrl’, function($scope) {

$scope.firstname = “Demo”;

$scope.lastname = “User”;

});

</script>

AngularJS Controller

Applications in AngularJS are controlled by controllers. Because of the immediate synchronization of the model and the view, the controller can be completely separated from the view, and simply concentrate on the model data. Thanks to the data binding in AngularJS, the view will reflect any

changes made in the controller.

Example

<div ng-app=”myApp” ng-controller=”myCtrl”>

<h1 ng-click=”changeName()”>{{firstname}}</h1>

</div>

<script>

var app = angular.module(‘myApp’, []);

app.controller(‘myCtrl’, function($scope) {

$scope.firstname = “Demo”;

$scope.changeName = function() {

$scope.firstname = “Nelly”;

}

});

</script>

Interpolation and data-binding

Interpolation markup with embedded expressions is used by AngularJS to provide data-binding to text nodes and attribute values. An example of interpolation is shown below:

<a ng-href=”img/{{username}}.jpg”>Hello {{username}}!</a>

How text and attribute bindings work – During the compilation process the compiler uses the $interpolate service to see if text nodes and element attributes contain interpolation markup with embedded expressions.

If that is the case, the compiler adds an interpolateDirective to the node and registers watches on the computed interpolation function, which will update the corresponding text nodes or attribute values as part of the normal digest cycle.

The interpolateDirective has a priority of 100 and sets up the watch in the preLink function.

How the string representation is computed – If the interpolated value is not a String, it is computed as follows:

  • undefined and null are converted to ”
  • if the value is an object that is not a Number, Date or Array, $interpolate looks for a custom toString() function on the object, and uses that. Custom means that myObject.toString !== Object.prototype.toString.
  • if the above doesn’t apply, JSON.stringify is used.

Binding to boolean attributes – Attributes such as disabled are called boolean attributes, because their presence means true and their absence means false. We cannot use normal attribute bindings with them, because the HTML specification does not require browsers to preserve the values of boolean attributes. This means that if we put an AngularJS interpolation expression into such an attribute then the binding information would be lost, because the browser ignores the attribute value.

In the following example, the interpolation information would be ignored and the browser would simply interpret the attribute as present, meaning that the button would always be disabled.

Disabled: <input type=”checkbox” ng-model=”isDisabled” />

<button disabled=”{{isDisabled}}”>Disabled</button>

For this reason, AngularJS provides special ng-prefixed directives for the following boolean attributes: disabled, required, selected, checked, readOnly , and open.

These directives take an expression inside the attribute, and set the corresponding boolean attribute to true when the expression evaluates to truthy.

Disabled: <input type=”checkbox” ng-model=”isDisabled” />

<button ng-disabled=”isDisabled”>Disabled</button>

ngAttr for binding to arbitrary attributes – Web browsers are sometimes picky about what values they consider valid for attributes. For example, considering this template:

<svg>

<circle cx=”{{cx}}”></circle>

</svg>

We would expect AngularJS to be able to bind to this, but when we check the console we see something like Error: Invalid value for attribute cx=”{{cx}}”. Because of the SVG DOM API’s restrictions, you cannot simply write cx=”{{cx}}”.

With ng-attr-cx you can work around this problem.

If an attribute with a binding is prefixed with the ngAttr prefix (denormalized as ng-attr-) then during the binding it will be applied to the corresponding unprefixed attribute. This allows you to bind to attributes that would otherwise be eagerly processed by browsers (e.g. an SVG element’s circle[cx] attributes). When using ngAttr, the allOrNothing flag of $interpolate is used, so if any expression in the interpolated string results in undefined, the attribute is removed and not added to the element.

For example, we could fix the example above by instead writing:

<svg>

<circle ng-attr-cx=”{{cx}}”></circle>

</svg>

If one wants to modify a camelcased attribute (SVG elements have valid camelcased attributes), such as viewBox on the svg element, one can use underscores to denote that the attribute to bind to is naturally camelcased.

For example, to bind to viewBox, we can write:

<svg ng-attr-view_box=”{{viewBox}}”>

</svg>

Other attributes may also not work as expected when they contain interpolation markup, and can be used with ngAttr instead. The following is a list of known problematic attributes:

  • size in <select> elements
  • placeholder in <textarea> in Internet Explorer 10/11
  • type in <button> in Internet Explorer 11
  • value in <progress> in Internet Explorer = 11

Get industry recognized certification – Contact us

Menu