AngularJS formuna özel doğrulama nasıl eklenir?


278

Giriş alanları ve doğrulama ayarları requiredöznitelikleri ve benzeri ekleyerek bir form var . Ancak bazı alanlar için ekstra doğrulama yapmam gerekiyor. Kontrol eden doğrulamaya nasıl "ulaşabilirim" FormController?

Özel doğrulama "bu 3 alan doldurulmuşsa, bu alanın doldurulması ve belirli bir şekilde biçimlendirilmesi gerekir" gibi bir şey olabilir.

Bir yöntem var FormController.$setValidityama bu genel bir API gibi görünmüyor, bu yüzden kullanmak yerine. Özel bir yönerge oluşturmak ve kullanmak NgModelControllerbaşka bir seçenek gibi görünür, ancak temelde istemediğim her özel doğrulama kuralı için bir yönerge oluşturmamı gerektirir.

Aslında, denetleyiciden bir alanı geçersiz olarak işaretlemek (aynı zamanda FormControllersenkronize ederken de ) işi yapmak için en basit senaryoda ihtiyacım olan şey olabilir, ancak bunu nasıl yapacağımı bilmiyorum.


4
Açısal JS'de özel doğrulamaları işlemek için canavar kodlama hakkında güzel bir makale var. Kontrol bu Çıkış
Anshu

Özel direktifler gerektirdiğinden tam olarak aradığım şey değil, ama yine de iyi bir makale olduğu için cevabınızı kabul edeceğim.
botteaap

Aynı şeyi merak ediyorum, FormController düzeyinde biraz kontrol isterdim. Örneğin, belirli özel yönergeleri FormController örneği gibi bir şey olarak işaretlemek istiyorum formName.$warning.
Adam Waselnuk

2
Bunun $$kamuya açık olmayan apislerden önce, $kamusal olmaktan önce olduğuna inanıyorum . Bkz. Stackoverflow.com/questions/19338493/…
Daniel F

Yanıtlar:


370

Düzenleme: Aşağıdaki ngMessages (> = 1.3.X) hakkında bilgi ekledi.

Standart form doğrulama iletileri (1.0.X ve üstü)

Google "Açısal Form Doğrulama" Eğer bu en iyi sonuçlardan biri olduğu için, şu anda oradan gelen herkes için başka bir cevap eklemek istiyorum.

FormController. $ SetValidity içinde bir yöntem var, ancak genel bir API gibi görünmüyor, bu yüzden kullanmak yerine.

"Herkese açık", endişelenme. Kullanın. Bunun için. Kullanılmasaydı, Açısal geliştiriciler onu bir kapanışta özelleştirecekti.

Özel doğrulama yapmak için, önerilen diğer yanıt olarak Açısal Kullanıcı Arabirimi'ni kullanmak istemiyorsanız, kendi doğrulama yönergelerinizi uygulayabilirsiniz.

app.directive('blacklist', function (){ 
   return {
      require: 'ngModel',
      link: function(scope, elem, attr, ngModel) {
          var blacklist = attr.blacklist.split(',');

          //For DOM -> model validation
          ngModel.$parsers.unshift(function(value) {
             var valid = blacklist.indexOf(value) === -1;
             ngModel.$setValidity('blacklist', valid);
             return valid ? value : undefined;
          });

          //For model -> DOM validation
          ngModel.$formatters.unshift(function(value) {
             ngModel.$setValidity('blacklist', blacklist.indexOf(value) === -1);
             return value;
          });
      }
   };
});

İşte bazı örnek kullanım:

<form name="myForm" ng-submit="doSomething()">
   <input type="text" name="fruitName" ng-model="data.fruitName" blacklist="coconuts,bananas,pears" required/>
   <span ng-show="myForm.fruitName.$error.blacklist">
      The phrase "{{data.fruitName}}" is blacklisted</span>
   <span ng-show="myForm.fruitName.$error.required">required</span>
   <button type="submit" ng-disabled="myForm.$invalid">Submit</button>
</form>

Not: yerine muhtemelen preferrable var 1.2.x ng-ifiçin ng-showyukarıda

İşte zorunlu bir dalgıç bağlantısı

Ayrıca, bu konu hakkında biraz daha ayrıntıya giren birkaç blog girişi yazdım:

Açısal Form Doğrulama

Özel Doğrulama Yönergeleri

Düzenleme: 1.3.X içinde ngMessages kullanarak

Hata mesajlarınızı göstermek için ngShow yerine ngMessages modülünü kullanabilirsiniz. Aslında herhangi bir şeyle çalışacak, bir hata mesajı olmak zorunda değil, ancak temel bilgiler:

  1. Dahil etmek <script src="angular-messages.js"></script>
  2. ngMessagesModül bildiriminizdeki referans :

    var app = angular.module('myApp', ['ngMessages']);
  3. Uygun işaretlemeyi ekleyin:

    <form name="personForm">
      <input type="email" name="email" ng-model="person.email" required/>
    
      <div ng-messages="personForm.email.$error">
        <div ng-message="required">required</div>
        <div ng-message="email">invalid email</div>
      </div>
    </form>

Yukarıdaki işaretlemede, ng-message="personForm.email.$error"temel olarak ng-messagealt yönergeler için bir bağlam belirtir . Sonra ng-message="required"ve ng-message="email"saatine bu bağlamda üzerinde özelliklerini belirtin. En önemlisi, onları kontrol etmek için bir sipariş de belirtiyorlar . Listede bulduğu ilk "doğruluk" kazanır ve bu mesajı gösterecek ve diğerlerinin hiçbirini göstermeyecektir.

Ve ngMessages örneği için bir dalgıç


6
$ Parsers.unshift işlevine ilettiğiniz işlevde değer döndürürseniz, hatalı değerler de modele kaydedilir - inanıyorum tanımsız döndürmek daha iyi olur (değer geçerli olmadığında).
georgiosd

5
+1 @ georgiosd ...% 100 doğru. Angular'ın ne yaptığına bakarak tanımsız dönüyorlar. Muhtemelen değeri döndürmek büyük bir şey değildir , çünkü (umarım) geçersiz formlardan modeller gönderilmez ... ama üzgünümden daha güvenli.
Ben Lesh

2
Harika şeyler! Angular'da özel doğrulama hakkında iyi bir yazı bulmak için burada Googled ederseniz, @blesh'in ne yazdığını kontrol edin
maaachine

AngularJS ve filtrelerle Gelişmiş form doğrulamasını kontrol ettiniz mi? Filtre doğrulamasını genel olarak çözer.
Benny Bottema

1
Bence return value ? valid : undefinedyukarıda yapmak isteyebilirsiniz .
GChorn

92

Açısal kullanıcı arayüzü projesi, muhtemelen bu konuda size yardımcı olacak bir ui-validate yönergesi içerir. Doğrulamayı yapmak için çağrılacak bir işlev belirleyelim.

Demo sayfasına bir göz atın: http://angular-ui.github.com/ , Doğrulama başlığına bakın.

Demo sayfasından:

<input ng-model="email" ui-validate='{blacklist : notBlackListed}'>
<span ng-show='form.email.$error.blacklist'>This e-mail is black-listed!</span>

sonra kumandanızda:

function ValidateCtrl($scope) {
  $scope.blackList = ['bad@domain.com','verybad@domain.com'];
  $scope.notBlackListed = function(value) {
    return $scope.blackList.indexOf(value) === -1;
  };
}

Angular 1.4
Nick

46

Doğrulama senaryonuz için ng-required komutunu kullanabilirsiniz ("bu 3 alan doldurulmuşsa, bu alan gereklidir":

<div ng-app>
    <input type="text" ng-model="field1" placeholder="Field1">
    <input type="text" ng-model="field2" placeholder="Field2">
    <input type="text" ng-model="field3" placeholder="Field3">
    <input type="text" ng-model="dependentField" placeholder="Custom validation"
        ng-required="field1 && field2 && field3">
</div>

2
Bu benim için çalıştı. Diğer alan değerlerine bağlı basit doğrulamalar için bu, karmaşık doğrulama kuralları yazmak yerine gitmenin yoludur
VimalKumar

28

Açısal Doğrulayıcı'yı kullanabilirsiniz .

Örnek: bir alanı doğrulamak için işlev kullanma

<input  type = "text"
    name = "firstName"
    ng-model = "person.firstName"
    validator = "myCustomValidationFunction(form.firstName)">

Sonra kumandanızda şöyle bir şey olurdu

$scope.myCustomValidationFunction = function(firstName){ 
   if ( firstName === "John") {
       return true;
    }

Bunun gibi bir şey de yapabilirsiniz:

<input  type = "text"
        name = "firstName"
        ng-model = "person.firstName"
        validator = "'!(field1 && field2 && field3)'"
        invalid-message = "'This field is required'">

(burada alan1 alan2 ve alan3 kapsam değişkenleridir. Alanların boş dizeye eşit olup olmadığını da kontrol etmek isteyebilirsiniz)

Alan geçmezse validator, alan geçersiz olarak işaretlenir ve kullanıcı formu gönderemez.

Daha fazla kullanım örneği ve örneği için bkz. Https://github.com/turinggroup/angular-validator

Feragatname: Angular-Validator yazarım


13

Son zamanlarda açısal form girişlerinin ifade tabanlı geçersiz kılınmasına izin vermek için bir direktif oluşturdum. Geçerli herhangi bir açısal ifade kullanılabilir ve nesne gösterimini kullanarak özel doğrulama anahtarlarını destekler. Açısal v1.3.8 ile test edildi

        .directive('invalidIf', [function () {
        return {
            require: 'ngModel',
            link: function (scope, elm, attrs, ctrl) {

                var argsObject = scope.$eval(attrs.invalidIf);

                if (!angular.isObject(argsObject)) {
                    argsObject = { invalidIf: attrs.invalidIf };
                }

                for (var validationKey in argsObject) {
                    scope.$watch(argsObject[validationKey], function (newVal) {
                        ctrl.$setValidity(validationKey, !newVal);
                    });
                }
            }
        };
    }]);

Bu şekilde kullanabilirsiniz:

<input ng-model="foo" invalid-if="{fooIsGreaterThanBar: 'foo > bar',
                                   fooEqualsSomeFuncResult: 'foo == someFuncResult()'}/>

Veya yalnızca bir ifadeyi ileterek (varsayılan olarak "invalidIf" ifadesinin validasyon anahtarı verilir)

<input ng-model="foo" invalid-if="foo > bar"/>

13

Bir formda özel joker karakter ifadesi doğrulamaları yapmanın harika bir yolu (from: AngularJS ve filtrelerle gelişmiş form doğrulaması ):

<form novalidate="">  
   <input type="text" id="name" name="name" ng-model="newPerson.name"
      ensure-expression="(persons | filter:{name: newPerson.name}:true).length !== 1">
   <!-- or in your case:-->
   <input type="text" id="fruitName" name="fruitName" ng-model="data.fruitName"
      ensure-expression="(blacklist | filter:{fruitName: data.fruitName}:true).length !== 1">
</form>
app.directive('ensureExpression', ['$http', '$parse', function($http, $parse) {
    return {
        require: 'ngModel',
        link: function(scope, ele, attrs, ngModelController) {
            scope.$watch(attrs.ngModel, function(value) {
                var booleanResult = $parse(attrs.ensureExpression)(scope);
                ngModelController.$setValidity('expression', booleanResult);
            });
        }
    };
}]);

jsFiddle demosu (ifade adlandırma ve çoklu ifadeleri destekler)

Buna benzer ui-validate, ancak kapsama özel bir doğrulama işlevine ihtiyacınız yoktur (bu genel olarak çalışır) ve tabii ki ui.utils'e bu şekilde ihtiyacınız yoktur .


Teşekkürler. Çok havalı. Dinamik formlar için doğrulama kuralları uygulamak özellikle yararlıdır. Ancak, geçersiz olsa bile model değerini ayarlamaya devam eder. Yine de geçersiz olması durumunda modelValue ayarlamasını önlemek için?
YuMei

5

Güncelleme:

Aynı işleve sahip önceki direktifin geliştirilmiş ve basitleştirilmiş sürümü (iki yerine bir):

.directive('myTestExpression', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {
            var expr = attrs.myTestExpression;
            var watches = attrs.myTestExpressionWatch;

            ctrl.$validators.mytestexpression = function (modelValue, viewValue) {
                return expr == undefined || (angular.isString(expr) && expr.length < 1) || $parse(expr)(scope, { $model: modelValue, $view: viewValue }) === true;
            };

            if (angular.isString(watches)) {
                angular.forEach(watches.split(",").filter(function (n) { return !!n; }), function (n) {
                    scope.$watch(n, function () {
                        ctrl.$validate();
                    });
                });
            }
        }
    };
}])

Örnek kullanım:

<input ng-model="price1" 
       my-test-expression="$model > 0" 
       my-test-expression-watch="price2,someOtherWatchedPrice" />
<input ng-model="price2" 
       my-test-expression="$model > 10" 
       my-test-expression-watch="price1" 
       required />

Sonuç: Doğrulayıcıların diğerinin yönerge modelinin ve mevcut modelinin değiştirilmesi üzerine yürütüldüğü, karşılıklı olarak bağımlı test ifadeleri.

Test ifadesi, $modeldiğer değişkenlerle karşılaştırmak için kullanmanız gereken yerel değişkene sahiptir.

Önceden:

Ekstra yönerge ekleyerek @Plantface kodunu geliştirmeye çalıştım. Bu ekstra yönerge, birden fazla ngModel değişkeninde değişiklik yapıldığında ifademizin yürütülmesi gerekiyorsa çok kullanışlıdır.

.directive('ensureExpression', ['$parse', function($parse) {
    return {
        restrict: 'A',
        require: 'ngModel',
        controller: function () { },
        scope: true,
        link: function (scope, element, attrs, ngModelCtrl) {
            scope.validate = function () {
                var booleanResult = $parse(attrs.ensureExpression)(scope);
                ngModelCtrl.$setValidity('expression', booleanResult);
            };

            scope.$watch(attrs.ngModel, function(value) {
                scope.validate();
            });
        }
    };
}])

.directive('ensureWatch', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        require: 'ensureExpression',
        link: function (scope, element, attrs, ctrl) {
            angular.forEach(attrs.ensureWatch.split(",").filter(function (n) { return !!n; }), function (n) {
                scope.$watch(n, function () {
                    scope.validate();
                });
            });
        }
    };
}])

Çapraz doğrulanmış alanlar oluşturmak için nasıl kullanılacağına örnek:

<input name="price1"
       ng-model="price1" 
       ensure-expression="price1 > price2" 
       ensure-watch="price2" />
<input name="price2" 
       ng-model="price2" 
       ensure-expression="price2 > price3" 
       ensure-watch="price3" />
<input name="price3" 
       ng-model="price3" 
       ensure-expression="price3 > price1 && price3 > price2" 
       ensure-watch="price1,price2" />

ensure-expressionDeğişkenler ng-modelveya ensure-watchdeğişkenlerden herhangi biri değiştirildiğinde modeli doğrulamak için yürütülür .


4

@synergetic @blesh işlev aşağıdaki gibi doğrulamak koymak için varsayalım düşünüyorum

function validate(value) {
    var valid = blacklist.indexOf(value) === -1;
    ngModel.$setValidity('blacklist', valid);
    return valid ? value : undefined;
}

ngModel.$formatters.unshift(validate);
ngModel.$parsers.unshift(validate);

4

Sunucu çağıran Özel Doğrulamalar

Arka uca$asyncValidators$http istekte bulunmak gibi eşzamansız doğrulamayı işleyen ngModelController API'sini kullanın . Nesneye eklenen işlevler, geçerli olduğunda çözülmesi veya geçersiz olduğunda reddedilmesi gereken bir söz vermelidir. Devam eden eşzamansız doğrulamalar, anahtar girişi ile saklanır ngModelController.$pending. Daha fazla bilgi için bkz. AngularJS Geliştirici Kılavuzu - Formlar (Özel Doğrulama) .

ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
  var value = modelValue || viewValue;

  // Lookup user by username
  return $http.get('/api/users/' + value).
     then(function resolved() {
       //username exists, this means validation fails
       return $q.reject('exists');
     }, function rejected() {
       //username does not exist, therefore this validation passes
       return true;
     });
};

Daha fazla bilgi için, bkz


$validatorsAPI'yı kullanma

Kabul edilen cevap, özel bir senkronize doğrulayıcı eklemek için $parsersve $formattersboru hatlarını kullanır . AngularJS 1.3+ bir $validatorsAPI ekledi, böylece doğrulayıcıları $parsersve $formattersboru hatlarına koymaya gerek yok :

app.directive('blacklist', function (){ 
   return {
      require: 'ngModel',
      link: function(scope, elem, attr, ngModel) {           
          ngModel.$validators.blacklist = function(modelValue, viewValue) {
              var blacklist = attr.blacklist.split(',');
              var value = modelValue || viewValue;
              var valid = blacklist.indexOf(value) === -1;
              return valid;
          });    
      }
   };
});

Daha fazla bilgi için, bkz. AngularJS ngModelController API Reference - $ validators .


3

AngularJS'de Özel Doğrulamayı tanımlamak için en iyi yer Cutsom yönergesidir. AngularJS bir ngMessages modülü sağlar.

ngMessages dinlediği bir anahtar / değer nesnesinin durumuna göre iletileri göstermek ve gizlemek için tasarlanmış bir direktiftir. Yönergenin kendisi, ngModel $ hata nesnesiyle (anahtar / değer doğrulama hatalarını depolayan) hata iletisi raporlamasını tamamlar.

Özel form doğrulaması için Bir özel yönerge ile ngMessages Modülleri kullanmalısınız. Burada sayı uzunluğunun 6'dan küçük olup olmadığını kontrol edecek basit bir doğrulama var.

 <form name="myform" novalidate>
                <table>
                    <tr>
                        <td><input name='test' type='text' required  ng-model='test' custom-validation></td>
                        <td ng-messages="myform.test.$error"><span ng-message="invalidshrt">Too Short</span></td>
                    </tr>
                </table>
            </form>

Özel doğrulama yönergesinin nasıl oluşturulacağı aşağıda açıklanmıştır

angular.module('myApp',['ngMessages']);
        angular.module('myApp',['ngMessages']).directive('customValidation',function(){
            return{
            restrict:'A',
            require: 'ngModel',
            link:function (scope, element, attr, ctrl) {// 4th argument contain model information 

            function validationError(value) // you can use any function and parameter name 
                {
                 if (value.length > 6) // if model length is greater then 6 it is valide state
                 {
                 ctrl.$setValidity('invalidshrt',true);
                 }
                 else
                 {
                 ctrl.$setValidity('invalidshrt',false) //if less then 6 is invalide
                 }

                 return value; //return to display  error 
                }
                ctrl.$parsers.push(validationError); //parsers change how view values will be saved in the model
            }
            };
        });

$setValidity model durumunu geçerli / geçersiz olarak ayarlamak için dahili işlevdir


1

@Ben Lesh'un cevabını, validasyonun büyük / küçük harfe duyarlı olup olmadığını belirleme özelliği ile genişlettim (varsayılan)

kullanın:

<input type="text" name="fruitName" ng-model="data.fruitName" blacklist="Coconuts,Bananas,Pears" caseSensitive="true" required/>

kod:

angular.module('crm.directives', []).
directive('blacklist', [
    function () {
        return {
            restrict: 'A',
            require: 'ngModel',
            scope: {
                'blacklist': '=',
            },
            link: function ($scope, $elem, $attrs, modelCtrl) {

                var check = function (value) {
                    if (!$attrs.casesensitive) {
                        value = (value && value.toUpperCase) ? value.toUpperCase() : value;

                        $scope.blacklist = _.map($scope.blacklist, function (item) {
                            return (item.toUpperCase) ? item.toUpperCase() : item
                        })
                    }

                    return !_.isArray($scope.blacklist) || $scope.blacklist.indexOf(value) === -1;
                }

                //For DOM -> model validation
                modelCtrl.$parsers.unshift(function (value) {
                    var valid = check(value);
                    modelCtrl.$setValidity('blacklist', valid);

                    return value;
                });
                //For model -> DOM validation
                modelCtrl.$formatters.unshift(function (value) {
                    modelCtrl.$setValidity('blacklist', check(value));
                    return value;
                });
            }
        };
    }
]);

0

Bu konuda sunulan bazı harika örnekler ve kütüphaneler, ama aradığım şey tam olarak yoktu. Benim yaklaşımım: açısal geçerlilik - isteğe bağlı Bootstrap stilinde pişmiş, asenkron doğrulama için söz tabanlı bir doğrulama lib.

OP'nin kullanım durumu için açısal geçerlilik çözümü şöyle görünebilir:

<input  type="text" name="field4" ng-model="field4"
        validity="eval"
        validity-eval="!(field1 && field2 && field3 && !field4)"
        validity-message-eval="This field is required">

İşte bir Keman , eğer bir dönüş için almak istiyorsanız. Lib, GitHub'da mevcut , ayrıntılı belgeler ve çok sayıda canlı demo var.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.