How ng-model-options will help to reduce event digest cycles?
Yes, ng-model-options
can help you limit the number of $digest
cycles. If you were to use just ng-model without setting any options for it, then your $digest cycle will run for each change in the value of ng-model. If $digest
cycle is packed full of data to be dirty-checked, the user is going to see lag in the UI whilst (for instance) typing inside an .Here is an example referenced from toddmotto's blog.
// app.js
angular
.module('app', []);
function trackDigests($rootScope) {
function link($scope, $element, $attrs) {
var count = 0;
function countDigests(newValue, oldValue) {
count++;
$element[0].innerHTML = '$digests: ' + count;
}
$rootScope.$watch(countDigests);
}
return {
restrict: 'EA',
link: link
};
}
angular
.module('app')
.directive('trackDigests', trackDigests);
<script src="//code.angularjs.org/1.4.7/angular.min.js"></script>
<div ng-app="app">
<div>
<form name="myForm">
<h3>Standard <input></h3>
<track-digests></track-digests>
<input
type="text"
name="test"
ng-model="test">
</form>
</div>
</div>
As you can see from our standard input, $digest
cycle is getting triggered for each character we type in the input field. This may cause end user delay for large applications.
Now we will see the case for inputs with ng-model options.
// app.js
angular
.module('app', []);
function trackDigests($rootScope) {
function link($scope, $element, $attrs) {
var count = 0;
function countDigests(newValue, oldValue) {
count++;
$element[0].innerHTML = '$digests: ' + count;
}
$rootScope.$watch(countDigests);
}
return {
restrict: 'EA',
link: link
};
}
angular
.module('app')
.directive('trackDigests', trackDigests);
<script src="//code.angularjs.org/1.4.7/angular.min.js"></script>
<div ng-app="app">
<div>
<form name="myForm">
<h3>ngModelOptions <input></h3>
<track-digests></track-digests>
<input
type="text"
name="test"
ng-model="test"
ng-model-options="{
updateOn: 'blur'
}">
</form>
</div>
</div>
Here we can see that the $digest
cycle is getting triggered only when we lose focus from the input. So, basically the ngModelOptions
are giving us control over how and when $digest
cycles occur.
Let us take even more control over the $digest
cycle by introducing debounce so that we can tell angular when to update.
// app.js
angular
.module('app', []);
function trackDigests($rootScope) {
function link($scope, $element, $attrs) {
var count = 0;
function countDigests(newValue, oldValue) {
count++;
$element[0].innerHTML = '$digests: ' + count;
}
$rootScope.$watch(countDigests);
}
return {
restrict: 'EA',
link: link
};
}
angular
.module('app')
.directive('trackDigests', trackDigests);
<script src="//code.angularjs.org/1.4.7/angular.min.js"></script>
<div ng-app="app">
<div>
<form name="myForm">
<h3>ngModelOptions <input></h3>
<track-digests></track-digests>
<input
type="text"
name="test"
ng-model="test"
ng-model-options="{
updateOn: 'default blur',
debounce: {
'default': 250,
'blur': 0
}
}">
</form>
</div>
</div>
The above illustrates that default will be updated 250ms after the event stops, and blur will update immediately as the user leaves the input (if this is the desired behaviour we want).
Start typing again, then stop and note the $digest
count is severely lower than the initial demonstration. You can then click/tab out the to call another $digest
immediately.
What is difference between default and change in debounce?
Default and change in debounce objects property are nothing but events. Default is not a DOM event, this is simply part of the ng-model-options api. Suppose you are setting your ngModelOptions like
ng-model-options="{
updateOn: 'default'
}"
Then there will be no change in the behaviour of your input field from default behaviour. This configuration is not really useful until we combine it with debounce like
ng-model-options="{
updateOn: 'default',
debounce: { 'default': 500 }
}"
This will make the input to update after 500ms. So basically this answers what default is. You can use other DOM events like change,blur,mouseover
...etc for your debounce.
Update:
When you used ng-model-options="{updateOn:'default blur',debounce:{default:1000,blur:0}}"
, the ng-blur was getting triggered with the old value of ng-model and after that only the updateOn events were fired.So basically the output will contain the old value of ng-model though the myname will be updated.
Working Example: https://plnkr.co/edit/2JPHXvXd992JJ0s37YC9?p=preview
Now, when you used ng-model-options="{updateOn:'default change blur',debounce:{default:1000,blur:0,change:0}}"
,the ng-blur was getting triggered with the new value of ng-model because setting change:0 made the updateOn events to fire before ng-blur.So basically the output was updated with the new value of ng-model along with myname.
Working Example : https://plnkr.co/edit/9wdA0he2YVcsPRLJ1Ant?p=preview