Angular - Error: $ rootScope: infdig while setting directive attribute using controller variable
I have a directive that prevents certain values ββfrom being entered into the input. For example, this ...
<input type="number" name="testValue" ng-model="testValue"
block="[0, 10, 17]" />
... will give a validation error if the user enters 0, 10, or 17.
This works fine, but now I need to conditionally set value locks based on a variable in my controller, so I tried using ternary setting like this ...
<input type="number" name="testValue" ng-model="testValue"
block="blockValues ? [0, 10, 17] : []" />
However, this raises the Error: $ rootScope: infdig Infinite $ digest Loop and I don't understand why. Can anyone explain this error to me and what can I do to fix it? Or any alternative would be appreciated. Thank!
Here is a code snippet to demonstrate:
var myApp = angular.module("myApp", []);
myApp.controller("myCtrl", function($scope) {
$scope.blockValues = true;
$scope.testValue = '';
});
myApp.directive('block', function() {
'use strict';
return {
restrict: 'A',
require: 'ngModel',
scope: {
block: '='
},
link: function(scope, element, attrs, ngModel) {
ngModel.$validators.allowedValues = function (value) {
return !scope.block || scope.block.indexOf(value) === -1;
};
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<form name="myForm">
<!-- Errors -->
<input type="number" name="testValue" ng-model="testValue"
block="blockValues ? [0] : []" />
<!-- No Errors
<input type="number" name="testValue" ng-model="testValue"
block="false ? [0] : []" />
-->
<!-- No Errors
<input type="number" name="testValue" ng-model="testValue"
block="true ? [0] : []" />
-->
<!-- No Errors
<input type="number" name="testValue" ng-model="testValue"
block="[0]" />
-->
<!-- No Errors
<input type="number" name="testValue" ng-model="testValue"
ng-min="blockValues ? 1 : 0" />
-->
</form>
<div>{{myForm.testValue.$error}}</div>
</div>
One of the common mistakes is binding to a function that generates a new array every time it is called. In this case, a new array is created each time [0]
, creating an infinite digest error.
<!-- Infinite Digest Errors
<input type="number" name="testValue" ng-model="testValue"
block="blockValues ? [0] : []" />
-->
Since it returns a new array, AngularJS detects that the model is different in every loop $digest
, which results in an error. The solution is to return the same array object if the elements haven't changed:
<!-- FIXED -->
<input type="number" name="testValue" ng-model="testValue"
ng-init="a1=[0];a0=[]" block="blockValues ? a1 : a0" />
For more information see AngularJS Error Reference - $ rootScope / infdig
Demo
var myApp = angular.module("myApp", []);
myApp.controller("myCtrl", function($scope) {
$scope.blockValues = true;
$scope.testValue = '';
});
myApp.directive('block', function() {
'use strict';
return {
restrict: 'A',
require: 'ngModel',
scope: {
block: '='
},
link: function(scope, element, attrs, ngModel) {
ngModel.$validators.allowedValues = function (value) {
return !scope.block || scope.block.indexOf(value) === -1;
};
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<form name="myForm">
<!-- Infinite Digest Errors
<input type="number" name="testValue" ng-model="testValue"
block="blockValues ? [0] : []" />
-->
<!-- FIXED -->
<input type="number" name="testValue" ng-model="testValue"
ng-init="a1=[0];a0=[]" block="blockValues ? a1 : a0" />
</form>
<div>{{myForm.testValue.$error}}</div>
</div>
I found using ng-model-options
helped:
ng-model-options="{ allowInvalid: true, debounce: 200 }"
Read more in the docs: https://docs.angularjs.org/api/ng/directive/ngModelOptions