Nijeesh Nijeesh - 6 months ago 116
AngularJS Question

Angular $compile in link function gives an error "RangeError: Maximum call stack size exceeded"

I am trying to add a ng-class attribute to a custom directive from the link function. But when using compile function after adding the ng-class attribute, It throws an error like "RangeError: Maximum call stack size exceeded"

Please see the code below

MyApp.directive('twinField',function($compile){
return {
restrict:'A',
require:'ngModel',
scope:{
fval:'='
},
link:function(scope,ele,attr,ctrl){
ctrl.$validators.compareTo=function(val){
//alert(scope.fval)
return scope.fval==val
}
scope.$watch('fval', function(newValue, oldValue, scope) {
ctrl.$validate()
});
ele.attr("ng-class","addForm.cpassword.$error.compareTo?'errorpswd':''")//=""
$compile(ele)(scope);
}
}


})

It is working when I add the ng-class directly in the html.

Answer

$compile(ele)(scope); line in compiling directive element, which will leads to call compile your directive code in infinite loop, that's why it is giving “RangeError: Maximum call stack size exceeded” error.

Ideally you should use combination of compile and link function together. From compile function you need to add ng-class attribute & then remove the directive attribute to avoid directive element to compile indefinitely. Then compile your directive element with scope from directive link function.

Code

myApp.directive('twinField', function($compile) {
  return {
    restrict: 'A',
    require: 'ngModel',
    scope: {
      fval: '='
    },
    compile: function(tElement, tAttrs) {
      console.log(tElement)

      tElement.removeAttr('twin-field');

      return function(scope, ele, attr, ctrl) {
        ele.attr("ng-class", "addForm.cpassword.$error.compareTo?'errorpswd':''");
        ele.attr("test", "{{test}}':''");
        var compileFn = $compile(ele);
        ctrl.$validators.compareTo = function(val) {
          //alert(scope.fval)
          return scope.fval == val
        }
        scope.$watch('fval', function(newValue, oldValue, scope) {
          ctrl.$validate()
        });
        compileFn(scope);
      }
    }
  }
})

Similar answer

Demo here

But the other thing, I don't see any advantage with your code of adding and removing class using ng-class directive. As you are setting validity of your form control, implicitly you are adding and removing ng-valid-compare-to(on valid) & ng-invalid-compare-to(on invalid) class. So there is no need to create extra overhead to have ng-class logic to putting same thing again.