Angular.js Two Way Data Binding

What is two way data binding?
Angular template engine binding the data in two way, which means data-binding in Angular apps is automatic synchronization of data between the model and view components. The way that Angular implements data-binding lets treat the model as the single-source-of-truth in 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 template 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. 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.

data1.jpg

Data Binding in Angular Templates:
Angular templates work differently. First the template 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.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 controller in isolation without the view and the related DOM/browser dependency.

data.jpg

After getting the general idea in data-binding, let us see a basic example of this. Afterwards we will see more advanced example.

In the below example we have two buttons. Which will fire two separate on-click methods. In result we will get output of certain information and the count of the method firing. At first lets look through the html file.

Html file:

<div ng-app="myApp" ng-controller="Ctrl1">
    <button type="button" ng-click="myClick()">From Controller</button>
    <my-element my-attr="name" my-cnt="counter"></my-element>
    <div>{{name}}</div>
    <div>{{counter}}</div>
</div>

Javascript file:

function Ctrl1($scope) {
    $scope.name = 'angular';
    $scope.counter = 0;

    $scope.myClick = function() {
        $scope.counter++;
        $scope.name = 'ctrl';
    }
}

angular.module('myApp', []).directive('myElement', function() {
    return {
        restrict: 'E',
        scope: {
            'myAttr': '=',
            'myCnt': '='
        },
        template: '<button ng-click="myOtherClick()">From Directive</button>',
        link: function(scope, iElement, iAttrs) {

            scope.myOtherClick = function() {
                scope.myCnt++;
                scope.myAttr = 'dir';
            }
        }
    }
});

Now let us go through a more advanced example. For this example let’s create a shopping cart. We will add the features to calculate total price of the cart, adding items to cart and removing items from cart. We have to add this logic to the controller. An Angular JS controller must follow the following conventions:

  • It should be a JavaScript function accepting an argument named $scope.
  • All of the model variables and functions should be added to the $scope object.
  • Controllers are usually suffixed with Ctrl, but it is not necessary.

Following is the controller with the required functionalities added:

function ShoppingCartCtrl($scope)  {
		$scope.items = [
			{Name: "Soap", Price: "25", Quantity: "10"},
			{Name: "Shaving cream", Price: "50", Quantity: "15"},
			{Name: "Shampoo", Price: "100", Quantity: "5"},
            {Name: "Razor", Price: "300", Quantity: "2"}
		];

		$scope.addItem = function(item) {
			$scope.items.push(item);
			$scope.item = {};
		}

		$scope.totalPrice = function(){
			var total = 0;
			for(count=0;count<$scope.items.length;count++){
				total += $scope.items[count].Price*$scope.items[count].Quantity;
			}
			return total;
		}
		$scope.removeItem = function(index){
			$scope.items.splice(index,1);
		}

	}

To bind data using members of the controller, we have to specify the controller using ng-controller directive. Ensure that the element containing ng-controller directive is a child of an element declared as ng-app. So, lets see how the html should look like.

<div ng-app="">
      <h1>
        <strong>E-shopping Center</strong>
      </h1>
      <div ng-controller="ShoppingCartCtrl">
        <br />
        <table>
          <tbody>
            <tr>
              <td>Name: </td>
              <td>
                <input type="text" ng-model="item.Name" />
              </td>
            </tr>
            <tr>
              <td>Price: </td>
              <td>
                <input type="text" ng-model="item.Price" />
              </td>
            </tr>
            <tr>
              <td>Quantity: </td>
              <td>
                <input type="text" ng-model="item.Quantity" />
              </td>
            </tr>
            <tr>
              <td colspan="2">
                <input type="Button" value="Add" ng-click="addItem(item)" />
              </td>
            </tr>
          </tbody>
        </table>
        <table border="1">
          <thead>
            <tr>
              <td>Name</td>
              <td>Price</td>
              <td>Quantity</td>
              <td>Remove Item</td>
            </tr>
          </thead>
          <tbody>
            <tr ng-repeat="item in items">
              <td>{{item.Name}}</td>
              <td>{{item.Price}}</td>
              <td>{{item.Quantity}}</td>
              <td>
                <input type="button" value="Remove" ng-click="removeItem($index)" />
              </td>
            </tr>
          </tbody>
        </table>
        <br />
        <div>Total Price: {{totalPrice()}}</div>
        <br />
              </div>
    </div>

let us break the above code and try to analyze what we have done. Let’s display the items added to items array in a table. Let’s also add a button on each row to remove the item. We have to use the following blocks to achieve this:

  • ng-repeat directive to iterate through items.
  • Binding controller’s properties using {{}}.
  • ng-click directive to bind button click event.
  • $index to use current index in an array.

Following is the table displaying items:

<table border="1">
    <thead>
 <tr>
  <td>Name</td>
  <td>Price</td>
  <td>Quantity</td>
                <td>Remove Item</td>
 </tr>
    </thead>
    <tbody>
 <tr ng-repeat="item in items">
  <td>{{item.Name}}</td>
  <td>{{item.Price}}</td>
  <td>{{item.Quantity}}</td>
  <td><input type="button" value="Remove" ng-click="removeItem($index)" /></td>
 </tr>
    </tbody>
</table>

Let’s display the total price of cart below this table. For this, we need to call the totalPrice() function of controller.

<div>Total Price: {{totalPrice()}}</div>

Finally, let’s add a form to accept values from user and add the new item to items array. We have to use ng-model directive to automatically add an input field to a property of the controller. Following is the form: 

<table>
 <tr>
  <td>Name: </td>
  <td><input type="text" ng-model="item.Name" /></td>
 </tr>
 <tr>
  <td>Price: </td>
  <td><input type="text" ng-model="item.Price" /></td>
 </tr>
 <tr>
  <td>Quantity: </td>
  <td><input type="text" ng-model="item.Quantity" /></td>
 </tr>
 <tr>
  <td colspan="2"><input type="Button" value="Add" ng-click="addItem(item)" /> </td>

 </tr>
</table>

data

When we enter something in the text boxes, a property named item is automatically added to $scope. This property is used in the addItem function.Try removing some items from the table and observe that totalPrice is updated immediately. It also happens when an item is added to the array as well.

As we saw, two-way data binding is made very easy using directives and binding syntax of Angular JS. All we need is a controller with some members in it. We don’t need to invoke any special functions to send notification when something changes in the controller.

Related Links:
1>Directive in Angular.js – Part 1
2>Directive in Angular.js – Part 2
3>Working with Modules in Angular.js
4>Angular Router and UI-Router
5>Angularjs and Services
6>Angular.js Promise
7>How To Use Filter In Angular.js
8>Angular Templates
9>Using Controllers in Angular.Js
10>Angularjs with Server Side Interaction
11>Working Through Angular.js With Transclude
12>Angular.js Event Handling

If you find this article helpful, you can connect us in Google+ and Twitter.