2

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>

2 Answers 2

2

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

Sign up to request clarification or add additional context in comments.

2 Comments

use case is exactly as above: my wrapper directive reduces boilerplate html and moves all angular directives on the inner input tag, any idea how can I solve this
james... using your plunker is a different question of mine
0

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' : '='}
  }

});

2 Comments

Lol, why did u down-vote my answer? My solution works for your original question, I cannot know what else you need. Also, you say you need the scope, but I just checked your updated plunker and I dont see any usage of the scope there...
@JoeSamanek this solution doesn't appear to work when applied to the plnkr. It displays that the original value is a duplicate, but doesn't update when the input changes. Admittedly i might be missing something, as i think the original posted plnkr may have been different, so maybe it worked with that? - plnkr.co/edit/ZK4CQfFqxFXgxdAHdFkY?p=preview

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.