Greg Smith
Greg Smith

Reputation: 2469

Angularjs get form field validity inside directive

I'm hoping this isn't a duplicate - plenty of similar questions about but I can't find an answer that works.

I have an Angular directive, thus:

app.directive('emailInput', function(){
    return {
        restrict: 'E',
        templateUrl: 'template.html',
        link: function(scope, elem, attrs, ctrl){
            elem.bind('keyup', function(){
                // TODO - what?
            })
        }
    }
}

and in the template html:

<input type="email" required ng-model="emailAddress" />

Without knowing the name of the form, inside the link function, I want to know the value of the emailAddress.$valid property - how can I get this?

Upvotes: 23

Views: 28109

Answers (6)

Felipez
Felipez

Reputation: 468

Let me give you another way to do it, it can be useful in some cases

link: function (scope, element, attrs, formCtrl) {
    scope.fileSizeError=false;
    scope.$watch(function () {
               return formCtrl.fileP.$error.maxSize;
             },function(newValue) {
                scope.fileSizeError=newValue;
             });          
}

In my case I was inside a directive that is used to upload a file so I needed to know the state of the var $error.maxSize in the template so I did in that way.

Upvotes: 0

Base33
Base33

Reputation: 3215

Here is a directive that will set dirty to true even if nothing has been typed in.

By default $dirty is set if something is typed in and wouldn't show a required error message until the user submits. With this

function() {
    return function (scope, element, attrs) {
        $(element).blur(function () {
            scope.$apply(function() {
                var field = scope.$eval(attrs.makeDirty);
                field.$dirty = true;
            });
        });
    };

HTML:

<label class="fieldLabel" for="confirmEmail">Confirm Email*</label>
<input type="text" id="confirmEmail" name="confirmEmail" ng-model="confirmEmail" ng-pattern="{{Ctrl.Model.Email.EmailAddress}}" required make-dirty="form.confirmEmail">
<span class="error" ng-show="form.confirmEmail.$error.pattern && form.confirmEmail.$dirty">Emails must match</span>
<span class="error" ng-show="form.confirmEmail.$error.required && (form.$submitted || form.confirmEmail.$dirty)">Confirm your email</span>

That allows me to give feedback as the user is filling out or tabbing on the form.

Upvotes: 0

Viktor Eriksson
Viktor Eriksson

Reputation: 6241

Know it's an old thread but if someone runs into this problem this is how I solved it:

app.directive('emailInput', function(){
  return {
      restrict: 'E',
      templateUrl: 'template.html',
      controller:function($scope){
         $scope.isInvalid = function(){
            return $scope.myelem.data().$ngModelController.$invalid;
         }
      },
      link: function(scope, elem, attrs){
          $scope.myelem = $(elem).find("input");
      }
  }
}

Upvotes: 1

Sam
Sam

Reputation: 93

This is an old post but for the people who get here by googling, this is the cleanest way to check validity of an input in your directive without knowing its name, so you can use your directive on any input element.

You just need to require the ngModelcontroller:

app.directive('emailInput', function(){
  return {
    require: 'ngModel'
    restrict: 'E',
    templateUrl: 'template.html',
    link: function(scope, elem, attrs, ngModelCtrl){
      elem.bind('keyup', function(){
          ngModelCtrl.$valid //check validity
      })
    }
  }
}

See the AngularJS document for ngModel.NgModelController, $valid under the Properties section:

https://docs.angularjs.org/api/ng/type/ngModel.NgModelController

Upvotes: 1

Upalr
Upalr

Reputation: 2148

We can check validity more easily without knowing the name of input elements.

app.directive('emailInput', function(){
  return {
      require: '^form', // We look for it on a parent, since it will be defined somewhere higher on the DOM.
      restrict: 'E',
      templateUrl: 'template.html',
      link: function(scope, elem, attrs, ctrl){
          elem.bind('keyup', function(){
              ctrl.$valid //check validity here
          })
      }
  }
}

Upvotes: 2

Adam
Adam

Reputation: 1143

You can require the formController which would give you access to all of the inputs registered to the form

app.directive('emailInput', function(){
  return {
      require: '^form', // We look for it on a parent, since it will be defined somewhere higher on the DOM.
      restrict: 'E',
      templateUrl: 'template.html',
      link: function(scope, elem, attrs, ctrl){
          elem.bind('keyup', function(){
              ctrl.emailAddress.$valid //check validity
          })
      }
  }
}

Remember that Angular keeps track of input elements by name. So you have to give your input a name attribute

<input type="email" required ng-model="emailAddress" name="emailAddress" />

I would also recommend possibly just passing all of this through a directive attribute. You probably don't want to hard code the field names. So you could just have an attribute that takes the validity

inputIsValid='formName.emailAddress.$valid'

And evaluate (or $watch it) in your directive.

Upvotes: 33

Related Questions