Làm cách nào để thêm xác thực tùy chỉnh vào biểu mẫu AngularJS?


278

Tôi có một biểu mẫu với các trường đầu vào và thiết lập xác nhận bằng cách thêm các requiredthuộc tính và như vậy. Nhưng đối với một số lĩnh vực tôi cần thực hiện một số xác nhận thêm. Làm thế nào tôi có thể "chạm vào" để xác nhận FormControllerđiều khiển?

Xác thực tùy chỉnh có thể giống như "nếu 3 trường này được điền vào, thì trường này là bắt buộc và cần được định dạng theo một cách cụ thể".

Có một phương thức trong FormController.$setValiditynhưng nó không giống API công khai nên tôi không sử dụng nó. Tạo một lệnh tùy chỉnh và sử dụng NgModelControllertrông giống như một tùy chọn khác, nhưng về cơ bản sẽ yêu cầu tôi tạo một lệnh cho mỗi quy tắc xác thực tùy chỉnh mà tôi không muốn.

Trên thực tế, việc đánh dấu một trường từ bộ điều khiển là không hợp lệ (trong khi vẫn giữ FormControllerđồng bộ hóa) có thể là điều tôi cần trong kịch bản đơn giản nhất để hoàn thành công việc, nhưng tôi không biết làm thế nào để làm điều đó.


4
Có một bài viết hay về quái vật mã hóa để xử lý các xác nhận tùy chỉnh trong JS góc. Kiểm tra này ra
Anshu

Đó không phải là chính xác những gì tôi đang tìm kiếm, vì nó yêu cầu các chỉ thị tùy chỉnh, nhưng tôi sẽ chấp nhận câu trả lời của bạn vì dù sao đó cũng là một bài viết hay.
chạm đáy

Tôi đang tự hỏi điều tương tự, tôi thích một số điều khiển ở cấp độ của Trình điều khiển. Ví dụ, tôi muốn một số chỉ thị tùy chỉnh nhất định gắn cờ đối tượng FormContoder như một cái gì đó giống như formName.$warning.
Adam Waselnuk

2
Tôi tin rằng có $$trước apis không công khai, với $công khai. Xem stackoverflow.com/questions/19338493/ Mạnh
Daniel F

Câu trả lời:


370

Chỉnh sửa: thêm thông tin về ngMessages (> = 1.3.X) bên dưới.

Thông báo xác thực mẫu chuẩn (1.0.X trở lên)

Vì đây là một trong những kết quả hàng đầu nếu bạn Google "Xác thực hình thức góc", hiện tại, tôi muốn thêm một câu trả lời khác cho điều này cho bất kỳ ai đến từ đó.

Có một phương thức trong FormContoder. $ SetValid nhưng nó không giống API công khai nên tôi không sử dụng nó.

Đó là "công khai", không phải lo lắng. Sử dụng nó. Đó là những gì nó làm. Nếu nó không được sử dụng, các nhà phát triển Angular sẽ tư nhân hóa nó trong một bao đóng.

Để thực hiện xác thực tùy chỉnh, nếu bạn không muốn sử dụng Angular-UI như câu trả lời khác được đề xuất, bạn chỉ cần cuộn chỉ thị xác thực của riêng mình.

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;
          });
      }
   };
});

Và đây là một số ví dụ sử dụng:

<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>

Lưu ý: trong 1.2.X nó có thể là preferrable để thay thế ng-ifcho ng-showtrên

Đây là một liên kết plunker bắt buộc

Ngoài ra, tôi đã viết một vài mục blog về chủ đề này chi tiết hơn một chút:

Xác nhận mẫu góc

Chỉ thị xác nhận tùy chỉnh

Chỉnh sửa: sử dụng ngMessages trong 1.3.X

Bây giờ bạn có thể sử dụng mô-đun ngMessages thay vì ngShow để hiển thị các thông báo lỗi của bạn. Nó thực sự sẽ hoạt động với bất cứ điều gì, nó không phải là một thông báo lỗi, nhưng đây là những điều cơ bản:

  1. Bao gồm <script src="angular-messages.js"></script>
  2. Tham khảo ngMessagestrong khai báo mô-đun của bạn:

    var app = angular.module('myApp', ['ngMessages']);
  3. Thêm đánh dấu thích hợp:

    <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>

Trong phần đánh dấu ở trên, ng-message="personForm.email.$error"về cơ bản chỉ định một bối cảnh cho các ng-messagechỉ thị con. Sau đó ng-message="required"ng-message="email"chỉ định các thuộc tính trên bối cảnh đó để xem. Quan trọng nhất, họ cũng chỉ định một lệnh để kiểm tra chúng . Cái đầu tiên nó tìm thấy trong danh sách là "sự thật" chiến thắng, và nó sẽ hiển thị thông báo đó và không ai khác.

Và một plunker cho ví dụ ngMessages


6
Nếu bạn trả về giá trị trên hàm mà bạn chuyển cho $ Parsers.unshift, các giá trị sai cũng sẽ được lưu vào mô hình - tốt hơn là tôi nên trả lại không xác định (khi giá trị không hợp lệ).
georgiosd

5
+1 @georgiosd ... đúng 100%. Nhìn qua những gì Angular làm, họ trở lại không xác định. Có lẽ nó không phải là một vấn đề lớn để trả lại giá trị, vì (hy vọng) các mô hình từ các biểu mẫu không hợp lệ không được gửi ... nhưng an toàn tốt hơn là xin lỗi, tôi cho rằng.
Ben Lesh

2
Công cụ tuyệt vời! Nếu bạn đã tìm đường đến đây để tìm kiếm một bài viết tốt về xác thực tùy chỉnh trong Angular, hãy xem những gì @bledh đã viết
maaachine

Bạn đã kiểm tra xác thực biểu mẫu Nâng cao với AngularJS và bộ lọc chưa? Nó giải quyết việc xác thực bộ lọc một cách khái quát.
Benny Bottema

1
Tôi nghĩ rằng bạn có thể có nghĩa là để làm return value ? valid : undefinedở trên.
GChorn

92

Dự án của Angular-UI bao gồm một lệnh xác thực ui, có thể sẽ giúp bạn với điều này. Nó cho phép bạn chỉ định một chức năng để gọi để thực hiện xác nhận.

Hãy xem trang demo: http://angular-ui.github.com/ , tìm kiếm xuống tiêu đề Xác thực.

Từ trang demo:

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

sau đó trong bộ điều khiển của bạn:

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

Thật kỳ lạ khi điều này không hiệu quả với tôi khi sử dụng Angular 1.4
Nick

46

Bạn có thể sử dụng ng-required cho kịch bản xác thực của mình ("nếu 3 trường này được điền vào, thì trường này là bắt buộc":

<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
Điều này làm việc cho tôi. Đối với các xác nhận đơn giản phụ thuộc vào các giá trị trường khác, đây là cách để đi thay vì viết các quy tắc xác thực phức tạp
VimalKumar

28

Bạn có thể sử dụng Angular-Validator .

Ví dụ: sử dụng hàm để xác thực trường

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

Sau đó, trong bộ điều khiển của bạn, bạn sẽ có một cái gì đó như

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

Bạn cũng có thể làm một cái gì đó như thế này:

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

(trong đó field1 field2 và field3 là các biến phạm vi. Bạn cũng có thể muốn kiểm tra xem các trường không bằng chuỗi rỗng)

Nếu trường không vượt qua validatorthì trường sẽ được đánh dấu là không hợp lệ và người dùng sẽ không thể gửi biểu mẫu.

Để biết thêm các trường hợp sử dụng và ví dụ, hãy xem: https://github.com/turinggroup/angular-validator

Tuyên bố miễn trừ trách nhiệm: Tôi là tác giả của Angular-Validator


13

Gần đây tôi đã tạo một lệnh để cho phép vô hiệu hóa dựa trên biểu thức của các đầu vào dạng góc. Bất kỳ biểu thức góc hợp lệ nào cũng có thể được sử dụng và nó hỗ trợ các khóa xác thực tùy chỉnh bằng cách sử dụng ký hiệu đối tượng. Đã thử nghiệm với v1.3.8 góc

        .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);
                    });
                }
            }
        };
    }]);

Bạn có thể sử dụng nó như thế này:

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

Hoặc chỉ bằng cách chuyển vào một biểu thức (nó sẽ được cung cấp xác thực mặc định là "không hợp lệ")

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

13

Đây là một cách hay để thực hiện xác thực biểu thức ký tự đại diện tùy chỉnh trong một biểu mẫu (từ: Xác thực biểu mẫu nâng cao với AngularJS và bộ lọc ):

<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);
            });
        }
    };
}]);

bản demo jsFiddle (hỗ trợ đặt tên biểu thức và nhiều biểu thức)

Nó tương tự ui-validate, nhưng bạn không cần một chức năng xác thực cụ thể phạm vi (điều này hoạt động một cách khái quát) và dĩ nhiên bạn không cần ui.utils theo cách này.


Cảm ơn. Rất tuyệt. Nó đặc biệt hữu ích để áp dụng các quy tắc xác nhận cho các hình thức động. Tuy nhiên, nó vẫn đặt giá trị mô hình ngay cả khi nó không hợp lệ. Dù sao để ngăn chặn nó đặt modelValue nếu nó không hợp lệ?
YuMei

5

Cập nhật:

Phiên bản cải tiến và đơn giản hóa của chỉ thị trước đó (một thay vì hai) với cùng chức năng:

.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();
                    });
                });
            }
        }
    };
}])

Ví dụ sử dụng:

<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 />

Kết quả: Các biểu thức kiểm tra phụ thuộc lẫn nhau trong đó các trình xác nhận được thực thi khi thay đổi mô hình chỉ thị và mô hình hiện tại khác.

Biểu thức kiểm tra có $modelbiến cục bộ mà bạn nên sử dụng để so sánh nó với các biến khác.

Trước đây:

Tôi đã cố gắng cải thiện mã @Plantface bằng cách thêm chỉ thị bổ sung. Lệnh bổ sung này rất hữu ích nếu biểu thức của chúng ta cần được thực thi khi các thay đổi được thực hiện trong nhiều hơn một biến ngModel.

.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();
                });
            });
        }
    };
}])

Ví dụ về cách sử dụng nó để tạo các trường được xác thực chéo:

<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-expressionđược thực thi để xác nhận mô hình khi ng-modelhoặc bất kỳ ensure-watchbiến nào được thay đổi.


4

@synergetic Tôi nghĩ rằng @bledh giả sử đặt chức năng xác thực như dưới đây

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

Xác thực tùy chỉnh gọi Máy chủ

Sử dụng API ngModelControll$asyncValidators xử lý xác thực không đồng bộ, chẳng hạn như đưa ra $httpyêu cầu cho phụ trợ. Các hàm được thêm vào đối tượng phải trả về một lời hứa phải được giải quyết khi hợp lệ hoặc bị từ chối khi không hợp lệ. Xác thực không đồng bộ trong tiến trình được lưu trữ bằng khóa trong ngModelController.$pending. Để biết thêm thông tin, hãy xem Hướng dẫn dành cho nhà phát triển AngularJS - Biểu mẫu (Xác thực tùy chỉnh) .

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;
     });
};

Để biết thêm thông tin, xem


Sử dụng $validatorsAPI

Câu trả lời được chấp nhận sử dụng $parsersvà các $formattersđường ống để thêm trình xác nhận đồng bộ tùy chỉnh. AngularJS 1.3+ đã thêm $validatorsAPI để không cần đặt trình xác nhận vào $parsers$formattersđường ống dẫn:

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;
          });    
      }
   };
});

Để biết thêm thông tin, hãy xem Tài liệu tham khảo API của AngularJS ngModelContoder - $ xác thực .


3

Trong AngularJS, nơi tốt nhất để xác định Xác thực tùy chỉnh là chỉ thị Cutsom. AngularJS cung cấp một mô-đun ngMessages.

ngMessages là một lệnh được thiết kế để hiển thị và ẩn các thông báo dựa trên trạng thái của một đối tượng khóa / giá trị mà nó nghe. Lệnh này bổ sung cho báo cáo thông báo lỗi với đối tượng lỗi ngModel $ (lưu trữ trạng thái khóa / giá trị của lỗi xác thực).

Để xác thực mẫu tùy chỉnh Một người nên sử dụng Mô-đun ngMessages với chỉ thị tùy chỉnh. Tôi có một xác thực đơn giản để kiểm tra xem độ dài của số có nhỏ hơn không thì 6 hiển thị lỗi trên màn hình

 <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>

Dưới đây là cách tạo chỉ thị xác thực tùy chỉnh

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 là hàm sẵn có để đặt trạng thái mô hình thành hợp lệ / không hợp lệ


1

Tôi đã mở rộng câu trả lời của @Ben Lesh với khả năng xác định xem xác thực có phân biệt chữ hoa chữ thường hay không (mặc định)

sử dụng:

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

mã:

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

Một số ví dụ tuyệt vời và libs được trình bày trong chủ đề này, nhưng họ không hoàn toàn có những gì tôi đang tìm kiếm. Cách tiếp cận của tôi: tính hợp lệ góc - một lib xác thực dựa trên lời hứa cho xác thực không đồng bộ, với kiểu dáng Bootstrap tùy chọn được tích hợp sẵn.

Một giải pháp hợp lệ góc cho trường hợp sử dụng của OP có thể trông giống như thế này:

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

Đây là một Fiddle , nếu bạn muốn mang nó đi quay. Lib có sẵn trên GitHub , có tài liệu chi tiết và nhiều bản demo trực tiếp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.