使用 AngularJS ngModel 和表单验证 $watch 两个元素,并在任一输入发生变化时测试它们是否相等

Using AngularJS ngModel and Form Validation to $watch two elements and test if they are equal whenever either input changes

我想做的是创建一个指令来比较两个密码输入并在其中一个更改时触发无效。我已经找到了一些例子并尝试了一些,并在我自己的尝试中结合了一些。但是,我只能在确认密码字段更改时使用 $setValidity 切换有效性。当您更改密码字段时,它不会触发比较无效。

这是我的指令:

app.directive("passwordVerify", function() {
    return {
        require: "ngModel",
        scope: {
            passwordVerify: '=',
        },
        link: function(scope, element, attrs, ctrl) {
            scope.$watch(function() {
                var combined;

                if (scope.passwordVerify || ctrl.$viewValue) {
                    combined = scope.passwordVerify + '_' + scope.$view; 
                }                    
                return combined;
            }, function(value) {
                if (value) {
                    ctrl.$parsers.unshift(function(viewValue) {
                        var origin = scope.passwordVerify;
                        if (origin !== viewValue) {
                            ctrl.$setValidity("pwd", false);
                            return undefined;
                        } else {
                            ctrl.$setValidity("pwd", true);
                            return viewValue;
                        }
                    });
                }
            });
        }
    };
});

这是指令的作用:

<input id="user_password" type="password" name='user_password' placeholder="password" value='' required ng-model="user.user_password">
<p class="help-text">Required</p>
<div class="help-block" ng-messages="add_user_form.user_password.$error" ng-show="add_user_form.user_password.$touched">
<div ng-messages-include="/app/views/messages.html" ></div>

<input id="confirm_password" ng-model="user.confirm_password" name="confirm_password" type="password" placeholder="confirm password" name="user_confirm_password" required password-verify="user.user_password">
<p class="help-text">Enter matching password</p>
<div class="help-block" ng-messages="add_user_form.confirm_password.$error" ng-show="add_user_form.confirm_password.$touched">
<div ng-messages-include="/app/views/messages.html" ></div>

使用此代码,当我更改确认密码字段的值时,我可以验证密码是否匹配,但是当您更改密码字段的值时,它不会重新验证输入。我很确定有一种成功的方法可以将 $watch 添加到两个元素或使用 $watchgroup 来执行此操作。我只是想不通。我知道有很多关于这个主题的问题,但我所做的一切只是让我想到了这一点。

我正在使用 Angular 1.5.7 顺便说一句...

这是一个双向工作的版本:

(function() {
  "use strict";
  angular.module('app', ['ngMessages'])
    .controller('mainCtrl', function($scope) {

    })

  .directive('passwordVerify', function() {
    return {
      restrict: 'A', // only activate on element attribute
      require: '?ngModel', // get a hold of NgModelController
      link: function(scope, elem, attrs, ngModel) {
        if (!ngModel) return; // do nothing if no ng-model

        // watch own value and re-validate on change
        scope.$watch(attrs.ngModel, function() {
          validate();
        });

        // observe the other value and re-validate on change
        attrs.$observe('passwordVerify', function(val) {
          validate();
        });

        var validate = function() {
          // values
          var val1 = ngModel.$viewValue;
          var val2 = attrs.passwordVerify;

          // set validity
          ngModel.$setValidity('passwordVerify', !val1 || !val2 || val1 === val2);
        };
      }
    }
  })
})();
<html ng-app="app">

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-messages/1.5.7/angular-messages.min.js"></script>
</head>

<body ng-controller="mainCtrl">
  <form name="add_user_form">
    <div class="col-md-12">
      <div class="form-group" ng-class="{ 'has-error' : add_user_form.user_password.$touched && add_user_form.user_password.$invalid }">
        <p class="help-text">Enter password</p>
        <input type="password" class="form-control" id="user_password" name="user_password" placeholder="password" required ng-model="user.user_password" password-verify="{{user.confirm_password}}">
        <div class="help-block" ng-messages="add_user_form.user_password.$error" ng-show="add_user_form.user_password.$touched">
          <p ng-message="required">This field is required</p>
          <p ng-message="minlength">This field is too short</p>
          <p ng-message="maxlength">This field is too long</p>
          <p ng-message="required">This field is required</p>
        </div>
      </div>
      <div class="form-group" ng-class="{ 'has-error' : add_user_form.confirm_password.$touched && add_user_form.confirm_password.$invalid }">
        <p class="help-text">Enter matching password</p>
        <input class="form-control" id="confirm_password" ng-model="user.confirm_password" name="confirm_password" type="password" placeholder="confirm password" required password-verify="{{user.user_password}}">
        <div class="help-block" ng-messages="add_user_form.confirm_password.$error" ng-show="add_user_form.confirm_password.$touched">
          <p ng-message="required">This field is required</p>
          <p ng-message="minlength">This field is too short</p>
          <p ng-message="maxlength">This field is too long</p>
          <p ng-message="required">This field is required</p>
          <p ng-message="passwordVerify">No match!</p>
        </div>
      </div>
    </div>
  </form>
</body>

</html>

希望对您有所帮助。