pipeline of ngModelController

ngModelController is undoubtedly one of the reasons why AngularJS is so awesome . It is responsible for two way data binding , which is what people use when they are asked to display Angular powers. It is the eye candy of Angular .

Yaa i sound like i am in love with it .. Well, yes i am.

Using ngModelController in its usual form ( inside input fields with ng-model) is all easy and fun. All you have to do is give a model value to ng-model attribute and you are good to go..

<div ng-controller="databinding">
<input type="text" ng-model="user" >
</div>
 
.controller('databinding',function($scope){
$scope.user="HiEveryone";
});
And there you have a two way data binding . But the heart pounding situation comes when you want to implement two way data binding on other tags or your custom directive . Yes it looks very complicated at first but once you understand the flow , you get all sorted.
So, what really is the flow .. The flow is :
Model->View

$modelValue->$formatters->$viewValue->$render

View->Model

$setViewValue->$viewValue->$parsers->$modelValue

 These names are methods and properties of ngModelController which you need to take hold of when creating your own custom two way data binding . To access ngModelController, you have to require ngModel , and you will have access to the controller as the fourth parameter in the link function.  
Suppose you have a custom directive with an ngmodel attribute :

<customdirective ng-model="bindvariable"></customdirective>

The directive definition will be :

.directive('customdirective',function(){
return {
require:'ngModel',
link: function(scope,element,attributes,ngModelController)
{
};
};
})
Now,
$modelValue - It is the value in the model , it retrives the value which is in the model.

$viewValue -   Actual string value in the view as given in Angular docs. But it sounds rather confusing to me becuase in your custom directive, unless you do a render, the value is not updated in the view . Yes, i know that obviously you will do render , but what if you give something else to render , like in this code .
Here, in the console, you can see that $viewValue is different and the value displayed in the view is different .

$render- It is called when the view needs to be updated, and yes you have to define a $render, else your view will not be rendered. 

$parsers- As explained in docs , $parsers accept an Array of functions to execute, as a pipeline, whenever the control reads value from the DOM. The functions are called in array order, each passing its return value through to the next. The last return value is forwarded to the $validators collection.
Parsers are used to sanitize / convert $viewValue .
$formatters :  As explained in the docs, It accepts an Array of functions to execute, as a pipeline, whenever the model value changes. The functions are called in reverse array order, each passing the value through to the next. The last return value is used as the actual DOM value. Used to format / convert values for display in the control.


So basically $parsers and $formatters are the workers who modify the values passed between the model and the view , In the example below, you can see that we have added a function in the formatter pipeline which will transform the model value to uppercase . 


function formatter(value) {
  if (value) {
    return value.toUpperCase();
  }
}
ngModel.$formatters.push(formatter);

$setViewValue : According to the docs, It Updates the view value.
This method should be called when an input directive want to change the view value; typically, this is done from within a DOM event handler.
For example input calls it when the value of the input changes and select calls it when an option is selected.
Again , you should understand that it updates the $viewValue and does not update the value in the view which is visible to you . $setViewValue will automatically call the $parsers and $validators pipeline. 
$validators is a simple concept , it is just a  collection of validators which are applied whenever the model value changes. AngularJS Docs are enough to understand it. 
You can see all these in action in the following plunker link 
So, here the 'Change Model' button will activate the Model->View pipeline , and you can see the $formatter in action , it converts the model value to uppercase and the value is rendered to the View using the $render function . 
And if you type in any value in the div element and click anywhere in the screen , it will activate the View->Model pipeline , $setViewValue and $parser is run , and the value is updated in the model in the uppercase form . 
$setViewValue is called inside $apply because we are calling it inside elm.on() , which is jquery . Since it is outside the AngularJS realm, to use any AngularJS feature inside it, we have to run it inside $apply . 

There are hell lot of properties and methods of ngModelController, but my aim with this doc was only to explain the bare minimum which you need to use two way data binding . You can understand the application of other properties and methods once you understand how the controller achieves what it is supposed to achieve. I hope this post eased your pain a bit . 

* Grabs a beer * 


0 comments:

Post a Comment