user3201167
user3201167

Reputation:

angularjs validators not working when used with another directive

I have a "uniqueCheck" directive which checks if the value is already present in a list or not and accordingly validates the ngModel. This directive when used on say an input tag works as expected but when used on a directive which renders an input tag the result is not as expected.

The validator function inside the directive is getting called but it doesn't validate or invalidate the ngModel of the input.
You can view the complete code of the directives on the plnkr link provided

Plnkr Link : plnkr

html is as follows :

<--! when used with a directive -->
<my-wrapper ng-model="values.abc" unique-check="" list="list" prop="name"> </my-wrapper>

<--! when used on an input tag-->    
 <div ng-form="myform">
     <input type="text" unique-check 
        list="list" prop="name" 
        name="myfield" 
        ng-model="values.pqr"/>
  <span>isDuplicate:{{myform.myfield.$error.isDuplicate}}</span>
</div>

Upvotes: 2

Views: 655

Answers (2)

james
james

Reputation: 4573

You're creating 2 separate ngModel instances, that are both updated when the input's changed.

The first is created by the <input> itself, which is the one assigned to 'myform'. This is the one that the <span> error message within my-wrapper is bound too.

The second one is the one created by the my-wrapper directive - which is the one that has the validator attached to it.

If you check the console (for the plnkr below) and inspect the values being output by the validator when the input is changed, you can see that the ngModel associated with the validator, is not the same ngModel that's associated with the form. But that both are actually being updated when the input's changed.

Clear the console once the page has loaded and then check the output when you change the first input.

http://plnkr.co/edit/nz6ODOVpn6lJlb055Svs?p=preview


Why is this happening?

Because both ng-model directives get passed the same string ('values.abc'), which are then evaluated against scope to determine which object property they should watch and update - i.e two way binding.

So when you change the input you're changing the value of scope.values.abc through the inputs ngModel instance. This change is picked up by the my-wrapper ngModelinstance - as it's watching the same object property - that then validates itself.

You can't solve the problem in this way, as the ngModel directive expects a string, not another ngModelinstance.


Solution

You could transfer the attributes from my-wrapper to the input at compile:

app.directive("myWrapper", function(){

    var templateFn = function(element, attrs){
        return '<div ng-form="myform">'+
                   '<input type="text" name="myfield"/>'+
                   '<span>(inside directive) : isDuplicate:{{myform.myfield.$error.isDuplicate}}</span>'
               '</div>';
    }

    return {
        restrict :'E',
        template : templateFn,
        require: 'ngModel',
        scope: true,
        compile: function(element, attrs) {
            var attr;
            angular.forEach(element.find('input'), function(elem) {
                elem = angular.element(elem)
                for(attr in attrs.$attr) {
                    elem.attr(attrs.$attr[attr], attrs[attr]);
                }
            });

            for(attr in attrs.$attr) {
                element.removeAttr(attrs.$attr[attr]);
            }
        }
    }
});

http://plnkr.co/edit/m2TV4BZKuyHz3JuLjHrY?p=preview

Upvotes: 2

Josef Joe Samanek
Josef Joe Samanek

Reputation: 1704

Dont use scope in your myWrapper directive, it creates a separate scope of variables. Also, you need to use element.ngModel, not just a string 'ngModel' as the ng-model.

Change your myWrapper directive like this to work:

app.directive("myWrapper", function(){
    var templateFn = function(scope, element, attrs){
    return '<div ng-form="myform">'+
          '<input type="text" name="myfield" ng-model="'+element.ngModel+'"/>'+
          '<span>isDuplicate:{{myform.myfield.$error.isDuplicate}}</span>'
          '</div>';
  }

  return {
      restrict :'E',
      template : templateFn,
      //require: 'ngModel',
      //scope: {'ngModel' : '='}
  }

});

Upvotes: 0

Related Questions