⬆️ ⬇️

Form Validation in AngularJS

Validation is one of the automagical capabilities of AngularJS . Although the magic here, of course, nothing. Just such standard html tags like form , input , select , textarea are also directives . And when they are combined with ngModel , required, ngPattern, etc., validation begins to work.





ngModel



A directive without which validation will not work. This directive is responsible for:



Virtually all of these responsibilities are realized through NgModelController .



The simplest example of email validation ( demo ).

')

  <input type="email" ng-model="myEmail"> 




Forms



The state of a form depends on all controls registered for it and nested forms. The form will be valid if all controls and forms included in it are valid. You can create form hierarchies using the ngForm directive to more conveniently process the state of individual parts of one large form. If a name is specified for a form using the name attribute, the controller of this form will be published in the appropriate scope with that name. Examples of using the properties of a form and its named controls ( demo ):



Information about validation and errors is also reflected in the classes of forms and controls. For example: ng-invalid-required , ng-dirty , ng-valid , ng-valid-email .



Creating a validator directive



When creating a validator directive, you need to implement handlers for two cases:



An example of a validator that verifies password settings is at least 6 characters, at least 1 digit, and at least one non-digital character ( demo ):

  mod.directive('strongPassRequired', function () { var isValid = function(s) { return s && s.length > 5 && /\D/.test(s) && /\d/.test(s); }; return { require:'ngModel', link:function (scope, elm, attrs, ngModelCtrl) { ngModelCtrl.$parsers.unshift(function (viewValue) { ngModelCtrl.$setValidity('strongPass', isValid(viewValue)); return viewValue; }); ngModelCtrl.$formatters.unshift(function (modelValue) { ngModelCtrl.$setValidity('strongPass', isValid(modelValue)); return modelValue; }); } }; }); 


In the $setValidity method, the first parameter is the string that will be used:





Visual directive with support for validators



For example, we implement our checkbox with an icon from Font Awesome, for which you can use, for example, the required validator (the demo is for the second checkbox, and the required validator is used).

Source directive:

 .directive('uiCheckbox', function () { return { restrict: 'EA', replace: true, transclude: true, template: '<div class="checkbox-control" ng-click="toggle()">' + '<span ng-class="{\'icon-check-empty\': !value, \'icon-check\': value}"></span>' + '<span class="checkbox-label" ng-transclude></span>' + '</div>', require: 'ngModel', scope: true, link: function (scope, element, attrs, ngModelCtrl) { scope.value = false; ngModelCtrl.$render = function () { scope.value = ngModelCtrl.$viewValue; }; scope.toggle = function () { scope.value = !scope.value; ngModelCtrl.$setViewValue(scope.value); }; } }; }); 


The key points here are:





Validation and directives with isolated scope



Suppose you have a block with several interface elements, messages on the results of validation, etc. And you need to use it on several pages. For example, a block for setting a password with confirmation, checks for the quality of a password, identity, etc. and you want to use this block again in the user registration and profile editing pages. For such a case, it is quite possible to create a directive with an isolated scope. And the validation results will be perfectly transmitted for parent forms, since parent form lookup is based on the DOM hierarchy, not the scope hierarchy.



Insulated form



Suppose there is such a task: there is a form for creating some object. To create it, you must fill in the name and do not necessarily fill out the description and list of sites with links. The Create Object button will be inactive while the creation form is invalid. At the same time, to add a new site to the list, it is necessary to fill in the Name and Url fields. And until they are filled in, the button must be inactive. Thus, to fill the list of sites will use its own nested form. But the state of its validity should not affect the parent form.



For this task, I have a workable, but not very beautiful solution. Perhaps it is useful to someone. Or someone will offer a better solution. Demo .

Source directive code:

 mod.directive('isolatedForm', function(){ return { require: 'form', link: function(scope, formElement, attrs, formController) { var parentFormCtrl = formElement.parent().controller('form'); var core$setValidity = formController.$setValidity; formController.$setValidity = function(validationToken, isValid, control) { core$setValidity(validationToken, isValid, control); if (!isValid && parentFormCtrl) { parentFormCtrl.$setValidity(validationToken, true, formController); } } } }; }); 


The basic idea is that every time a form wants to inform upstairs that something is invalid in it, instead report it is valid.

Source: https://habr.com/ru/post/167793/



All Articles