Angular ng-messages: how to check password confirmation?

26,410

Solution 1

The easiest approach is to use a pattern. Works fine for me!

<input type="password" name="new_password1" ng-model="new_password1">

<input type="password" name="new_password2" ng-pattern="\b{{new_password1}}\b" ng-model="new_password2">
<div ng-messages="passwordForm.new_password2.$error">
    <div ng-message="pattern">Not equal!!!</div>
</div>

Solution 2

The best approach is to use a directive. The major point of problem here is that both password and password confirmation inputs need to be watched.

Here's the solution that could help

angular.module('app', ['ngMessages'])

.controller('ctrl', function($scope) {
  $scope.registerData = {};
})


.directive('confirmPwd', function($interpolate, $parse) {
  return {
    require: 'ngModel',
    link: function(scope, elem, attr, ngModelCtrl) {

      var pwdToMatch = $parse(attr.confirmPwd);
      var pwdFn = $interpolate(attr.confirmPwd)(scope);

      scope.$watch(pwdFn, function(newVal) {
          ngModelCtrl.$setValidity('password', ngModelCtrl.$viewValue == newVal);
      })

      ngModelCtrl.$validators.password = function(modelValue, viewValue) {
        var value = modelValue || viewValue;
        return value == pwdToMatch(scope);
      };

    }
  }
});
<html ng-app="app">

<head>
  <script data-require="angular.js@~1.4.3" data-semver="1.4.3" src="https://code.angularjs.org/1.4.3/angular.js"></script>
  <script data-require="[email protected]" data-semver="1.4.3" src="https://code.angularjs.org/1.4.3/angular-messages.js"></script>
  <script src="https://code.angularjs.org/1.3.15/angular.js"></script>
  <script src="script.js"></script>
</head>

<body ng-controller="ctrl">
  <form name="autentication_form" novalidate="" ng-submit="submit_register()">
    <label class="item item-input">
      <span class="input-label">Email</span>
      <input type="text" name="email" ng-model="registerData.email" required="" />
      <div class="form-errors" ng-messages="autentication_form.email.$error" ng-if='autentication_form.email.$touched'>
        <span class="form-error" ng-message="required">You did not enter the email</span>
      </div>
    </label>
    <label class="item item-input">
      <span class="input-label">Password</span>
      <input type="password" name="password" ng-model="registerData.password" required />
      <div class="form-errors" ng-messages="autentication_form.password.$error" ng-if='autentication_form.password.$touched'>
        <span class="form-error" ng-message="required">Please enter the password</span>
      </div>
    </label>
    <label class="item item-input">
      <span class="input-label">Password confirmation</span>
      <input type="password" name="password_confirmation" ng-model="registerData.password_confirmation" required="" confirm-pwd="registerData.password" />
      <div class="form-errors" ng-messages="autentication_form.password_confirmation.$error" ng-if='autentication_form.password_confirmation.$touched'>
        <span class="form-error" ng-message="required">Password confirmation required</span>
        <span class="form-error" ng-message="password">Password different</span>
      </div>
    </label>
  </form>
</body>

</html>

Solution 3

When developing, you can face the fact that you need to create your own checks, which will affect the validity of the form. If these checks are simple, such as a comparison of the two values, it is better to use a general guideline, than write your own checks for each situation. Look at use-form-error directive.

Live example on jsfiddle.

angular.module('ExampleApp', ['use', 'ngMessages'])
  .controller('ExampleController', function($scope) {

  });
.errors {
  color: maroon
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular-messages.min.js"></script>
<script src="https://cdn.rawgit.com/Stepan-Kasyanenko/use-form-error/master/src/use-form-error.js"></script>

<div ng-app="ExampleApp">
  <div ng-controller="ExampleController">

    <form name="ExampleForm">
      <label>Password</label>
      <input ng-model="password" required />
      <br>
      <label>Confirm password</label>
      <input ng-model="confirmPassword" name="confirmPassword" use-form-error="isNotSame" use-error-expression="password && confirmPassword && password!=confirmPassword" required />
      <div ng-show="ExampleForm.$error.isNotSame" class="errors">Passwords Do Not Match!</div>
      <div ng-messages="ExampleForm.confirmPassword.$error" class="errors">
        <div ng-message="isNotSame">
          Passwords Do Not Match (from ng-message)!
        </div>
      </div>
    </form>

  </div>
</div>

Solution 4

Here's what I did (using ng-pattern):

<md-input-container class="md-block">
  <label>New Password</label>
  <input ng-model="user.password" name="password" type="password" required ng-pattern="'.{8,}'" />
  <div ng-messages="form.password.$error">
    <div ng-message="required">Password required.</div>
    <div ng-message="pattern">Password must be at least 8 characters.</div>
  </div>
</md-input-container>
<md-input-container class="md-block">
  <label>Confirm Password</label>
  <input ng-model="user.confirmPassword" name="confirmPassword" type="password" ng-pattern="user.password|escapeRegex" required />
  <div ng-messages="form.confirmPassword.$error">
    <div ng-message="required">Password confirmation required.</div>
    <div ng-message="pattern">Passwords do not match.</div>
  </div>
</md-input-container>

And the following filter converts the ng-pattern regex to a literal:

module.filter('escapeRegex', function(){
  return function(str){
    return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
  }
});

Solution 5

ngMessage works by adding $error.message_field_name to the DOM field name in the form object (within the scope of course). So if your DOM form name is autentication_form and the DOM field name is password_confirmation, you need to set $scope.autentication_form.password_confirmation.$error.nomatch (or whatever ngMessage name you want) to true to display the "Doesn't match" error.

Markup:

<input type="password" name="password_confirmation" ng-model="registerData.password_confirmation" required />

<div ng-messages="autentication_form.password_confirmation.$error">
                <div ng-message="required">Please repeat your password.</div>
                <div ng-message="nomatch">Doesn't match.</div>
            </div>
</div>

Code, nothing special, just watching both passwords:

$scope.$watch("registerData.password + registerData.password_confirmation", function () {
            $scope.autentication_form.password_confirmation.$error.nomatch = $scope.registerData.password !== $scope.registerData.password_confirmation;
        });
Share:
26,410
FrancescoMussi
Author by

FrancescoMussi

Full-stack developer based in Riga, Latvia. Hope Socrates is proud of my Socratic badge on StackOverflow.

Updated on April 01, 2020

Comments

  • FrancescoMussi
    FrancescoMussi about 4 years

    THE SITUATION:

    I am using ng-messages directive for instant validation in my angular app. Everything is working fine except one thing: i need to validate the field 'password confirmation' and don't know how to do.

    THE CODE:

    <form name="autentication_form" novalidate="" ng-submit="submit_register()">
    
        <label class="item item-input">
            <span class="input-label">Email</span>
            <input type="text" name="email" ng-model="registerData.email" required>
    
            <div class="form-errors" ng-messages="autentication_form.email.$error" role="alert" ng-if='autentication_form.email.$dirty'>
                <div class="form-error" ng-message="required">You did not enter the email</div>
            </div>
        </label>
    
        <label class="item item-input">
            <span class="input-label">Password</span>
            <input type="password" name="password" ng-model="registerData.password" required>
    
            <div class="form-errors" ng-messages="autentication_form.password.$error" role="alert" ng-if='autentication_form.password.$dirty'>
                <div class="form-error" ng-message="required">Please enter the password</div>
            </div>
        </label>
    
        <label class="item item-input">
            <span class="input-label">Password confirmation</span>
            <input type="password" name="password_confirmation" ng-model="registerData.password_confirmation" required>
    
            <div class="form-errors" ng-messages="autentication_form.password_confirmation.$error" role="alert" ng-if='autentication_form.password_confirmation.$dirty'>
                <div class="form-error" ng-message="required">Password confirmation required</div>
            </div>
        </label>
    
    </form>
    

    THE QUESTION:

    How can i check that the password confirmation match using ng-messages?