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>
      

Run code


+3


source to share


2 answers


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>
      

Run code


+2


source


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

0


source







All Articles