пароль-проверьте директивы в AngularJS



Я пишу директиву проверки пароля:



 Directives.directive("passwordVerify",function(){
return {
require:"ngModel",
link: function(scope,element,attrs,ctrl){
ctrl.$parsers.unshift(function(viewValue){
var origin = scope.$eval(attrs["passwordVerify"]);
if(origin!==viewValue){
ctrl.$setValidity("passwordVerify",false);
return undefined;
}else{
ctrl.$setValidity("passwordVerify",true);
return viewValue;
}
});

}
};
});


html:



<input data-ng-model='user.password' type="password" name='password' placeholder='password' required>
<input data-ng-model='user.password_verify' type="password" name='confirm_password' placeholder='confirm password' required data-password-verify="user.password">


учитывая 2 поля пароля в форме, если оба значения пароля равны, то поле, на которое влияет директива, является допустимым.
Проблема в том, что он работает в одну сторону (т. е. когда я ввожу пароль в поле password-verify). Однако при обновлении исходного поля пароля проверка пароля становится недействительной.



любая идея, как я мог бы иметь " двухстороннюю привязку проверить?"

545   24  

24 ответов:

Это должно решить:

View:

<div ng-controller='Ctrl'>
   <form name='form'>
      <input data-ng-model='user.password' type="password" name='password' placeholder='password' required>
      <div ng-show="form.password.$error.required">
        Field required</div>
      <input ng-model='user.password_verify' type="password" name='confirm_password' placeholder='confirm password' required data-password-verify="user.password">
      <div ng-show="form.confirm_password.$error.required">
        Field required!</div>
      <div ng-show="form.confirm_password.$error.passwordVerify">
        Fields are not equal!</div>
   </form
</div>

директива

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

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 + '_' + ctrl.$viewValue; 
            }                    
            return combined;
        }, function(value) {
            if (value) {
                ctrl.$parsers.unshift(function(viewValue) {
                    var origin = scope.passwordVerify;
                    if (origin !== viewValue) {
                        ctrl.$setValidity("passwordVerify", false);
                        return undefined;
                    } else {
                        ctrl.$setValidity("passwordVerify", true);
                        return viewValue;
                    }
                });
            }
        });
     }
   };
});

Я использую следующую директиву, потому что я хочу повторно проверить оба поля ввода независимо от того, было ли изменено значение 1 или значение 2:

создание отдельной директивы для этого не нужны. Там уже есть построить в инструмент угловой пользовательского интерфейса проверки пароля. С этим вы могли бы сделать:

<input name="password" required ng-model="password">
<input name="confirm_password"
       ui-validate=" '$value==password' "
       ui-validate-watch=" 'password' ">

 Passwords match? {{!!form.confirm_password.$error.validator}}

еще один подход заключается в том, чтобы сопоставить модель одного входа с значением другого входа.

app.directive('nxEqual', function() {
    return {
        require: 'ngModel',
        link: function (scope, elem, attrs, model) {
            if (!attrs.nxEqual) {
                console.error('nxEqual expects a model as an argument!');
                return;
            }
            scope.$watch(attrs.nxEqual, function (value) {
                model.$setValidity('nxEqual', value === model.$viewValue);
            });
            model.$parsers.push(function (value) {
                var isValid = value === scope.$eval(attrs.nxEqual);
                model.$setValidity('nxEqual', isValid);
                return isValid ? value : undefined;
            });
        }
    };
});

Итак, если модель поля пароля login.password затем вы устанавливаете следующий атрибут в поле проверки:nx-equal="login.password" и тест для formName.elemName.$error.nxEqual. Вот так:

<form name="form">
    <input type="password" ng-model="login.password">
    <input type="password" ng-model="login.verify" nx-equal="login.password" name="verify">
    <span ng-show="form.verify.$error.nxEqual">Must be equal!</span>
</form>

Расширенная версия:

для моего нового проекта мне пришлось изменить вышеуказанную директиву, чтобы она отображала только nxEqual ошибка, когда и только когда вход проверки имел значение. В противном случае nxEqual ошибка должна быть приглушенной. Вот Расширенная версия:

app.directive('nxEqualEx', function() {
    return {
        require: 'ngModel',
        link: function (scope, elem, attrs, model) {
            if (!attrs.nxEqualEx) {
                console.error('nxEqualEx expects a model as an argument!');
                return;
            }
            scope.$watch(attrs.nxEqualEx, function (value) {
                // Only compare values if the second ctrl has a value.
                if (model.$viewValue !== undefined && model.$viewValue !== '') {
                    model.$setValidity('nxEqualEx', value === model.$viewValue);
                }
            });
            model.$parsers.push(function (value) {
                // Mute the nxEqual error if the second ctrl is empty.
                if (value === undefined || value === '') {
                    model.$setValidity('nxEqualEx', true);
                    return value;
                }
                var isValid = value === scope.$eval(attrs.nxEqualEx);
                model.$setValidity('nxEqualEx', isValid);
                return isValid ? value : undefined;
            });
        }
    };
});

и вы бы использовали его так:

<form name="form">
    <input type="password" ng-model="login.password">
    <input type="password" ng-model="login.verify" nx-equal-ex="login.password" name="verify">
    <span ng-show="form.verify.$error.nxEqualEx">Must be equal!</span>
</form>

попробуйте:http://jsfiddle.net/gUSZS/

Я сделал это без директивы.

<input type="password" ng-model="user.password" name="uPassword" required placeholder='Password' ng-minlength="3" ng-maxlength="15" title="3 to 15 characters" />
    <span class="error" ng-show="form.uPassword.$dirty && form.uPassword.$error.minlength">Too short</span>
    <span ng-show="form.uPassword.$dirty && form.uPassword.$error.required">Password required.</span><br />

    <input type="password" ng-model="user.confirmpassword" name="ucPassword" required placeholder='Confirm Password' ng-minlength="3" ng-maxlength="15" title="3 to 15 characters" />
    <span class="error" ng-show="form.ucPassword.$dirty && form.ucPassword.$error.minlength">Too short</span>
    <span ng-show="form.ucPassword.$dirty && form.ucPassword.$error.required">Retype password.</span>
    <div ng-show="(form.uPassword.$dirty && form.ucPassword.$dirty) && (user.password != user.confirmpassword)">
        <span>Password mismatched</span>
    </div>

https://github.com/wongatech/angular-confirm-field - это хороший проект для этого.

пример здесь http://wongatech.github.io/angular-confirm-field/

приведенный ниже код показывает 2 поля ввода с реализованной функциональностью

<input ng-confirm-field ng-model="emailconfirm" confirm-against="email" name="my-email-confirm"/>
<input ng-model="email" name="my-email" />

начиная с углового 1.3.0-beta12, недопустимые входы не записываются в ngModel, поэтому вы не можете смотреть, а затем проверять, как вы можете видеть здесь:http://plnkr.co/edit/W6AFHF308nyKVMQ9vomw?p=preview. был введен новый конвейер валидаторов, и вы можете подключиться к нему, чтобы достичь того же.

на самом деле, на этой ноте я создал компонент bower для общих дополнительных валидаторов:https://github.com/intellix/angular-validators который включает в себя этот.

angular.module('validators').directive('equals', function() {
    return {
        restrict: 'A',
        require: '?ngModel',
        link: function(scope, elem, attrs, ngModel)
        {
            if (!ngModel) return;

            attrs.$observe('equals', function() {
                ngModel.$validate();
            });

            ngModel.$validators.equals = function(value) {
                return value === attrs.equals;
            };
        }
    };
});

angular.module('validators').directive('notEquals', function() {
    return {
        restrict: 'A',
        require: '?ngModel',
        link: function(scope, elem, attrs, ngModel)
        {
            if (!ngModel) return;

            attrs.$observe('notEquals', function() {
                ngModel.$validate();
            });

            ngModel.$validators.notEquals = function(value) {
                return value === attrs.notEquals;
            };
        }
    };
});

я использовал эту директиву с успехом до:

 .directive('sameAs', function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      ctrl.$parsers.unshift(function(viewValue) {
        if (viewValue === scope[attrs.sameAs]) {
          ctrl.$setValidity('sameAs', true);
          return viewValue;
        } else {
          ctrl.$setValidity('sameAs', false);
          return undefined;
        }
      });
    }
  };
});

использование

     <input ... name="password" />
    <input type="password" placeholder="Confirm Password" 
name="password2" ng-model="password2" ng-minlength="9" same-as='password' required>

Я имел дело с той же проблемой и нашел хороший блоге об этом написал Петр Будаев. Это хорошее чтение, и это объясняет процесс очень хорошо. Код выглядит следующим образом:

directives.directive("repeatPassword", function() {
    return {
        require: "ngModel",
        link: function(scope, elem, attrs, ctrl) {
            var otherInput = elem.inheritedData("$formController")[attrs.repeatPassword];

            ctrl.$parsers.push(function(value) {
                if(value === otherInput.$viewValue) {
                    ctrl.$setValidity("repeat", true);
                    return value;
                }
                ctrl.$setValidity("repeat", false);
            });

            otherInput.$parsers.push(function(value) {
                ctrl.$setValidity("repeat", value === ctrl.$viewValue);
                return value;
            });
        }
    };
});

Так что вы могли бы сделать что-то вроде:

<input type="password" name="repeatPassword" id="repeatPassword" placeholder="repeat password" ng-model="user.repeatPassword" repeat-password="password" required>

заслуга автора

разве этого недостаточно:

<input type="password" ng-model="passwd1" />
<input type="password" ng-model="passwd2" />
<label ng-show="passwd1 != passwd2">Passwords do not match...</label>
<button ng-disabled="passwd1 != passwd2">Save</button>

просто, и работает просто отлично для меня.

это решение похоже на то, которое дал Доминик Уотсон, который использует $validators и является тем, что мне больше всего нравится. Единственное изменение заключается в том, что вы можете наблюдать выражение.

$validators коллекция валидаторов, которые применяются всякий раз, когда изменение значения модели. Ключевое значение внутри объекта относится к имя валидатора, в то время как функция ссылается на проверку операция. Операция проверки предоставляется со значением модели в качестве аргумента и должен возвращать значение true или false в зависимости от ответ этой проверки

от https://code.angularjs.org/1.3.15/docs/api/ng/type/ngModel.NgModelController

Я использую угловой 1.3. Моя директива выглядит примерно так

angular.module('app').directive("passwordConfirm", function() {
    "use strict";
    return {
        require : "ngModel",
        restrict : "A",
        scope : {
            //We will be checking that our input is equals to this expression
            passwordConfirm : '&'
        },
        link : function(scope, element, attrs, ctrl) {
            //The actual validation
            function passwordConfirmValidator(modelValue, viewValue) {
                return modelValue == scope.passwordConfirm();
            }
            //Register the validaton when this input changes
            ctrl.$validators.passwordConfirm = passwordConfirmValidator;
            //Also validate when the expression changes
            scope.$watch(scope.passwordConfirm, ctrl.$validate);
        }
    };
});

использовать

<input type="password" ng-model="user.password"/>
<input type="password" ng-model="user.confirmPassword" 
                password-confirm="user.password" />

для проверки формы с двумя полями ввода, я нахожу наиболее подходящий способ

директива

app.directive('passwordVerify', function() {
return {
    require: 'ngModel',
    link: function (scope, elem, attrs, ctrl) {
        if (!attrs.passwordVerify) {
            return;
        }
        scope.$watch(attrs.passwordVerify, function (value) {
          if( value === ctrl.$viewValue && value !== undefined) {
             ctrl.$setValidity('passwordVerify', true);
             ctrl.$setValidity("parse",undefined);
          }
          else {
             ctrl.$setValidity('passwordVerify', false);
          }
        });
        ctrl.$parsers.push(function (value) {
            var isValid = value === scope.$eval(attrs.passwordVerify);
            ctrl.$setValidity('passwordVerify', isValid);
            return isValid ? value : undefined;
        });
    }
  };
});

HTML

     <div class="row">
        <div class="col-md-10 col-md-offset-1">
          <div class="form-group" ng-class="{ 'has-error': form.password.$dirty && form.password.$error.required || (form.password.$error.minlength || form.password.$error.maxlength)}">
              <input type="password" name="password" ng-minlength="6" ng-maxlength="16" id="password" class="form-control" placeholder="Password" ng-model="user.password" required />
              <span ng-show="form.password.$dirty && form.password.$error.required" class="help-block">Password is required</span>
              <span ng-show="form.password.$error.minlength || form.password.$error.maxlength" class="help-block">Password must be 6-16 character long</span>
          </div>
        </div>
       </div>
       <div class="row">
         <div class="col-md-10 col-md-offset-1">
           <div class="form-group" ng-class="{ 'has-error': (form.confirm_password.$dirty && form.confirm_password.$error.required) || form.confirm_password.$error.passwordVerify }">
              <input type="password" name="confirm_password" id="confirm_password" class="form-control" placeholder="Confirm Password" ng-model="user.confirm_password" required password-verify="user.password" />
              <span ng-show="form.confirm_password.$dirty && form.confirm_password.$error.required" class="help-block">Confirm Password is required</span>
              <span ng-show="form.confirm_password.$error.passwordVerify" class="help-block">Please make sure passwords match & must be 6-16 character long</span>
          </div>
        </div>
      </div>

это работает в обоих направлениях, и это просто и чисто

JavaScript

var app = angular.module("app");

app.controller("SamePaswordController", function () {

  this.password;
  this.confirm;

  this.save = function () {
    alert("Saved!");
  };
}


app.directive("match", function () {
  return {
    restrict:"A",
    require:"ngModel",

    link: function(scope, element, attrs, ctrl) {

      function matchValidator(value) {      

        scope.$watch(attrs.match, function(newValue, oldValue) {

          var isValid = value === scope.$eval(attrs.match);                    
          ctrl.$setValidity('match', isValid);

        });

        return value;
      }

      ctrl.$parsers.push(matchValidator);
    }
  };
});

HTML: обратите внимание на директиву соответствия

<form name="regForm" ng-controller="SamePaswordController as regCtrl"
      ng-submit="regForm.$valid && regCtrl.save()" novalidate>

  <input name="password" ng-model="regCtrl.password" 
         type="password" required placeholder="Password"/>                

  <input name="confirm" ng-model="regCtrl.confirm" match="regCtrl.password"
         type="password" required placeholder="Confirm password"/>


  <div> regForm is valid:{{regForm.$valid}}</div>

  <input type="submit" value="Save"/>

</form>

вы можете клонировать РЕПО с помощью этого примера https://github.com/rogithub/roangularjs

не директивное решение, но работает для меня:

<input ng-model='user.password'
 type="password"
 name='password'
 placeholder='password'
 required>
<input ng-model='user.password_verify'
 type="password" 
 name='confirm_password'
 placeholder='confirm password'
 ng-pattern="getPattern()"
 required>

и в контроллере:

//Escape the special chars
    $scope.getPattern = function(){
        return $scope.user.password && 
              $scope.user.password.replace(/([.*+?^${}()|\[\]\/\])/g, '\');
    }

http://plnkr.co/edit/QDTnipCsHdg56vgygsqC?p=preview

ниже мой взгляд на проблему. Эта директива будет сравниваться со значением формы вместо области.

'use strict';
(function () {
    angular.module('....').directive('equals', function ($timeout) {
        return {
            restrict: 'A',
            require: ['^form', 'ngModel'],
            scope: false,
            link: function ($scope, elem, attrs, controllers) {
                var validationKey = 'equals';
                var form = controllers[0];
                var ngModel = controllers[1];

                if (!ngModel) {
                    return;
                }

                //run after view has rendered
                $timeout(function(){
                    $scope.$watch(attrs.ngModel, validate);

                    $scope.$watch(form[attrs.equals], validate);
                }, 0);

                var validate = function () {
                    var value1 = ngModel.$viewValue;
                    var value2 = form[attrs.equals].$viewValue;
                    var validity = !value1 || !value2 || value1 === value2;
                    ngModel.$setValidity(validationKey, validity);
                    form[attrs.equals].$setValidity(validationKey,validity);
                };
            }
        };
    });
})();

в HTML один теперь ссылается на фактическую форму вместо значения области:

<form name="myForm">
  <input type="text" name="value1" equals="value2">
  <input type="text" name="value2" equals="value1">
  <div ng-show="myForm.$invalid">The form is invalid!</div>
</form>

чтобы добиться проверки при изменении обоих входов, я использую следующий код (который был комбинацией всех других ответов):

angular.module('app.directives')
.directive('passwordVerify', [function () {
    return {
        require: '?ngModel',
        restrict: 'A',
        scope: {
            origin: '=passwordVerify'
        },
        link: function (scope, element, attrs, ctrl) {
            if(!ctrl) {
                return;
            }

            function validate(value) {
                ctrl.$setValidity('passwordMatch', scope.origin === value);
                return value;
            }

            ctrl.$parsers.unshift(validate);

            scope.$watch('origin', function(value) {
                validate(ctrl.$viewValue);
            });
        }
    };
}]);

во-первых, я хотел бы поблагодарить Фредрика за публикацию этого превосходного примера. Есть одна маленькая проблема, с которой я столкнулся случайно. на скрипке вы разместили http://jsfiddle.net/gUSZS/

Если вы вводите пароль, а затем вводите тот же пароль в элементе проверки ввода, все работает нормально, но попробуйте добавить пробел во второе поле, и angular автоматически обрезает это пространство. Это означает, что директива не "видит" дополнительное пространство. Сейчас пароли бывают разные, но форма все равно действительна.

чтобы исправить это, нам нужно добавить

ng-trim="false"

к элементам ввода. Это не работает в угловой 1.0.3 так что если вы хотите попробовать его в этой скрипке вам нужно добавить 1.1.1 к скрипке (http://ajax.googleapis.com/ajax/libs/angularjs/1.1.1/angular.js)

но опять же, thanx Фредерик, я буду использовать ваше решение в моем приложении!

Антон P. S. Я хотел прокомментировать пост Фредерика, но им новый для этого форума и, похоже, не имеет достаточного кредита. Поэтому было бы очень признательно, если некоторые из вас могут проголосовать за мой комментарий, если вам это нравится :-)

нет необходимости в дополнительной директиве, вот мой взгляд на это:

HTML:

<div class="form-group" data-ng-class="{ 'has-error': submitted && !form.new_passwd.$valid }">
    <input type="password" name="new_passwd" class="form-control" data-ng-model="data.new_passwd" placeholder="New Password" required data-ng-pattern="passwdRegex">
    <small class="help-block" data-ng-show="submitted && form.new_passwd.$error.required">New password is required!</small>
    <small class="help-block" data-ng-show="submitted && !form.new_passwd.$error.required && form.new_passwd.$error.pattern">New password is not strong enough!</small>
</div>

<div class="form-group" data-ng-class="{ 'has-error': submitted && !form.new_passwd_conf.$valid }">
    <input type="password" name="new_passwd_conf" class="form-control" data-ng-model="data.new_passwd_conf" placeholder="Confirm New Password" required data-ng-pattern="passwdConfRegex">
    <small class="help-block" data-ng-show="submitted && form.new_passwd_conf.$error.required">New password confirmation is required!</small>
    <small class="help-block" data-ng-show="submitted && !form.new_passwd_conf.$error.required && form.new_passwd_conf.$error.pattern">New password confirmation does not match!</small>
</div>

Javascript:

$scope.passwdRegex = /^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[^\da-zA-Z]).{8,}$/;
$scope.$watch('data.new_passwd', function() {
    $scope.passwdConfRegex = new RegExp(Regex.escape($scope.data.new_passwd));
});

где регулярное выражение.escape () можно найти здесь.

работает как шарм!

чтобы добавить к большому количеству уже существующих решений, это хорошо работает для меня.

(Ян Лаусманн ответ перестал работать с последними бета-релизами AngularJS).

   <input name="password" type="text" required="" ng-model="password" placeholder="password" class="ng-dirty ng-valid ng-valid-required">
   <input name="confirm_password" type="text" required="" ng-model="confirm_password" ui-validate=" '$value==password' " ui-validate-watch=" 'password' " placeholder="confirm password" class="ng-dirty ng-valid-required ng-invalid ng-invalid-validator"> 
   <span ng-show="form.confirm_password.$error.validator">Passwords do not match!</span>
        password errors: {
        "required": false,
        "validator": true
        }

это работает для меня.

у меня была такая же проблема, когда я пытался построить свою собственную директиву, и я исправил это add

ctrl.$validate();

где ctrl-это мой ngModelController

Это мое мнение

<input type="password" match="signupCtrl.registrationData.password" name="confirmPassword" class="form-control" placeholder="Confirm Password" data-ng-model="signupCtrl.registrationData.confirmPassword" required>
        <span ng-messages="registerForm.confirmPassword.$error">
            <span ng-message="match">The Password must match</span>
        </span>

- Это моя директива

(function () {
    'use strict';
    angular.module('matchDirective', [
        // Angular modules
        // Custom modules
        // 3rd Party Modules
    ]);
})(); 
(function () {
    'use strict';
    angular
        .module('matchDirective')
        .directive('match', match);
    match.$inject = ['$window'];

    function match($window) {
        // Usage:
        //     <element match="source"></element>
        // Creates:
        //
        var directive = {
            link: link,
            restrict: 'A',
            require: 'ngModel',
        };
        return directive;

        function link(scope, element, attrs, ctrl) {
            scope.$watch(attrs['match'], function (newVal, oldVal) {
                ctrl.$validators.match = function (modelValue, viewValue) {
                    if (newVal == modelValue) {
                        return true;
                    } else {
                        return false;
                    }
                }
                ctrl.$validate();
            });
        }
    }
})();

что-то вроде этого работает для меня:

js:

.directive('sameAs', function() { return {
    require : 'ngModel',
    link : function(scope, elm, attrs, ngModelCtrl) {

        ngModelCtrl.$validators.sameAs = function(modelValue, viewValue) {
            var checkedVal = attrs.sameAs;
            var thisInputVal = viewValue;

            if (thisInputVal == checkedVal) {
                return true; // valid
            } else {
                return false;
            }
        };
    }
}; });

html:

<input type="password" name="password" id="password" ng-model="password" />

<input type="password" name="passwordRepeat" id="passwordRepeat" 
    ng-model="passwordRepeat" same-as="{{password}}" />

принцип Keep It Simple And Stupid (KISS)может быть полезен на этом. Его более быстро и легко проверить, если оба пароля совпадают, выполнив следующие действия:

<div ng-app="app" ng-controller="passwordCheck">
  <form name="signUp" ng-submit="submitForm()" novalidate>
     <input type="password" name="password" ng-model="password" required>
     <input type="password" name="ConfirmPassword" ng-model="passwordconfirm"   required>
     <button type="submit"> Submit</button>
  </form>

  <hr>
  <span>Do they match?</span> {{signUp.password.$viewValue == signUp.confirmPassword.$viewValue}}
    </div>

и перед отправкой формы, вы можете сделать это в вашем js

var app = angular.module("app", []);
app.controller("passwordCheck", function($scope) {
   $scope.submitForm = function() {
      if ($scope.signUp.$valid && $scope.signUp.password.$viewValue == $scope.signUp.confirmPassword.$viewValue) {
            alert('Its a match!');
        };
};
});

вы можете проверить его в JSfiddle как хорошо.

Comments

    Ничего не найдено.