4

I would like to set the validity of a form element based on a custom boolean value. Consider the following password fields:

<input type="password" name="password" ng-model="user.password" required>
<input type="password" name="passwordRepeat" ng-model="user.passwordRepeat" required>

I would like to mark the second input field valid if the repeated password matches the original password. Something like:

<input type="password" name="passwordRepeat" ng-model="user.passwordRepeat" my-validation-check="user.passwordRepeat === user.password" required>

I was not able to find any Angular directive for this purpose. Any ideas? Perhaps create my own directive for this? Unfortunately, I'm not an Angular expert... it should be something like this:

angular.module('app').directive('myValidationCheck', function() {
    return {
        scope: true,
        require: 'ngModel',
        link: function(scope, elm, attrs, ngModel) {
            // eval and watch attrs.myValidationCheck
            // and use ngModel.$setValidity accordingly
        }
    };
});

Thanks!

Onestone
  • 609
  • 2
  • 10
  • 23

3 Answers3

4

I have spent quite a bit of time finding the best answer based on your answers below (thanks a lot!). What did the trick for me was simply:

angular.module('myApp').directive('myValidationCheck', function() {
    return {
        scope: {
            myValidationCheck: '='
        },
        require: 'ngModel',
        link: function(scope, elm, attrs, ngModel) {

            scope.$watch('myValidationCheck', function(value) {
                ngModel.$setValidity('checkTrue', value ? true : false);
            });

        }
    };
});

for

<input type="password" name="passwordRepeat" my-validation-check="user.password === user.passwordRepeat" ng-model="user.passwordRepeat" required>

And this is really flexible. You can use anything you want in my-validation-check, e.g. make sure a checkbox is checked or any more complex expression is true.

Hope this helps not just myself.. :-)

Onestone
  • 609
  • 2
  • 10
  • 23
  • This just seems totally unnecessary to me. Use ng-required like I proposed and you don't have to write any extra code! You can do all your form checking like this, that's the beauty of Angular. – Sander_P Oct 27 '14 at 15:47
  • 1
    But ng-required is used for letting Angular know whether the input field is required ie. needs to be filled in. Even if your expression is true, the form validity is true (if filled in) or false (if empty). In the passwordRepeat case this would not work, right..: if password and passwordRepeat do not match, the field is not required and hence the form is valid, which it should NOT be. – Onestone Oct 28 '14 at 09:58
  • I can understand that people get that impression when they read the docs and it says 'Sets required attribute if set to true', but in fact, ngRequired can take an Angular expression, and then it turns into 'this expression needs to be true for the form (not the field)'. See also: [http://stackoverflow.com/questions/13466133/how-can-i-conditionally-require-form-inputs-with-angularjs](http://stackoverflow.com/questions/13466133/how-can-i-conditionally-require-form-inputs-with-angularjs) – Sander_P Oct 29 '14 at 10:16
1

Why do you need special directive for it?

Why not make so:

<div ng-controller="MyCtrl">
  <form name="myForm" ng-submit="processForm()"> 
      <input type="password" ng-model="password" placeholder="password" required/>
      <input type="password" ng-model="repeatedPassword" placeholder="repeat password" required/>
      <input type="Submit" value="Submit" ng-disabled="passwordsMissmatched()"/>
      <span ng-show="passwordsMissmatched()">
          Password mismatched
      </span>
   </form>
</div>

And your JS:

function MyCtrl($scope) {
    $scope.passwordsMissmatched = function(){
        return $scope.password && $scope.repeatedPassword 
               && ($scope.password != $scope.repeatedPassword);
    }

    $scope.processForm = function(){
        if($scope.password == $scope.repeatedPassword){
            alert("Form processing..");
        }
    };
}

This approach should work like a charm.

I've created JSFiddle for you.

Artyom Pranovich
  • 6,814
  • 8
  • 41
  • 60
1

Please see demo below

var app = angular.module('app', []);

app.directive('mcheck', function() {
  return {

    require: 'ngModel',
    link: function(scope, elm, attrs, ngModel) {

      scope.$watch(attrs.ngModel, function(value) {



        if (value == attrs.mcheck) {
          ngModel.$setValidity('notEquals', true);


        } else {

          ngModel.$setValidity('notEquals', false);

        }




      });

    }
  };
});


app.controller('fCtrl', function($scope) {



});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="app">
  <div ng-controller="fCtrl">
    <form novalidate name="login">
      <input type="text" name="password" ng-model="user.password" mcheck="{{user.passwordRepeat}}" required>



      <input type="text" name="passwordRepeat" ng-model="user.passwordRepeat" mcheck="{{user.password}}" required>
      <HR/>
      <span ng-show="login.password.$error.notEquals && login.passwordRepeat.$error.notEquals && login.$dirty">Passwords are not equal</span>
      <HR/>


    </form>
  </div>
</div>
sylwester
  • 16,498
  • 1
  • 25
  • 33