Wednesday, 11 November 2015

Create a directive which will track the model changes and acts as a Converters between the View and the Model using $parsers and $formatters

In this post we are going to see how to create a converters between the View and the Model in angular js. For this we take an example that maintain a history in the model like oldvalue and newvalue in model, but display the newvalue in the view, how we can do this ? This can be only done by the directive which have implemented the ng-model.

Let we see in example: 
We are going to create a Directive which will tracking the model changes .... Let name it as track-change.

First we understand about the $parsers and $formatters.

$parsers : which consists of a collection of functions, where executes when the value  changes in the View. 
                   ie. View -> Model

$formatters: which consists of a collection of functions, where executes when the value changes in the model
                      i.e Model - . View

Now we create a Directive which will track the elements by maintaining the NewValue and OldValue.

Directive:




Controller:
*************************

appRoot.controller('MainController', function ($scope) {
    'use strict';   
     $scope.Product = {};
    
     $scope.sourceList = [{"id":1,"name":"Apple"},
                          {"id":2,"name":"Orange"},
                          {"id":3,"name":"Banana"},
                          {"id":4,"name":"Papaya"},
                          {"id":5,"name":"Jackfruit"}];
    $scope.Product.Selected = $scope.sourceList[0];
    
});




Html:
*************
Use the track-change directive in tag that you implement the ng-model, in this example i am used in select , where whenever user selects the new value, old value is retained in OldValue property, you can see the Model that maintains the history, but in view when we bind it shows only the latest value ,This is because of $formatters.




Output:
*******************




Full Code:
*********************

appRoot.directive('trackChange',function(){
    return{
        restrict:'A',
        require:'ngModel',
        link:function(scope,element,attrs,ngModel){
            
            var historyObject = {NewValue:undefined,OldValue:undefined};
            var OldValue = {};
            var NewValue = {};
            ngModel.$formatters.push(function(value){
                if(historyObject.NewValue!=undefined)
                    return historyObject.NewValue;
                if(value!=undefined){
                    historyObject.NewValue = value;
                }
                return value;
            });
            
            ngModel.$parsers.push(function(value){             
                
                historyObject.OldValue = historyObject.NewValue;;
                historyObject.NewValue =  value;
                ngModel.$setViewValue(historyObject.NewValue);
                ngModel.$render();
                ngModel.$setValidity('is_valid',true);
                return historyObject;
            });
            
        }
    }
})

var appRoot = angular.module('appRoot',[]);

appRoot.controller('MainController', function ($scope) {
    'use strict';   
     $scope.Product = {};
    
     $scope.sourceList = [{"id":1,"name":"Apple"},
                          {"id":2,"name":"Orange"},
                          {"id":3,"name":"Banana"},
                          {"id":4,"name":"Papaya"},
                          {"id":5,"name":"Jackfruit"}];
    $scope.Product.Selected = $scope.sourceList[0];
    
});

<div ng-app="appRoot">
    <div style="margin-left:40px;" ng-controller="MainController">
      
        <br />
        <select ng-change="modelChange()" track-change="" ng-model="Product.Selected" 
                ng-options="prod.name for prod in sourceList" >
        </select>  
        <span style="color:orange">[[Product.Selected]]</span>
</div>
</div>


From this post you can learn how to create a Directive which will track the model changes and acts as a Converters between the View and Model using $parsers and $formatters.

No comments:

Post a Comment