Как добавить пользовательскую проверку в форму AngularJS?
у меня есть форма с полями ввода и настройкой проверки, добавив required
атрибуты и тому подобное. Но для некоторых полей мне нужно сделать дополнительную проверку. Как бы я "подключиться" к проверке, что FormController
контроля?
пользовательская проверка может быть чем-то вроде "если эти 3 поля заполнены, то это поле требуется и должно быть отформатировано определенным образом".
есть метод в FormController.$setValidity
но это не похоже на публичный API, поэтому я скорее не использовать его. Создание пользовательской директивы и использование NgModelController
выглядит как другой вариант, но в основном потребует от меня создать директиву для каждого пользовательского правила проверки, которое я не хочу.
фактически, маркировка поля от контроллера как недопустимая (а также сохранение FormController
в синхронизировать) может быть то, что мне нужно в простейшем случае, чтобы получить работу, но я не знаю как это сделать.
12 ответов
Edit: добавлена информация о ngMessages (>= 1.3.Х) ниже.
сообщения проверки стандартной формы (1.0.X и выше)
поскольку это один из лучших результатов, если Вы Google "проверка угловой формы", в настоящее время я хочу добавить еще один ответ на это для тех, кто приходит оттуда.
в FormController есть метод.$setValidity, но это не похоже на публичный API, поэтому я не использую его.
это "общественность", не беспокойтесь. Использовать его. Вот что это за. Если бы он не предназначался для использования, угловые разработчики приватизировали бы его в закрытии.
чтобы выполнить пользовательскую проверку, если вы не хотите использовать Angular-UI в качестве другого ответа, вы можете просто свернуть свою собственную директиву проверки.
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;
});
}
};
});
и вот пример использования:
<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>
Примечание: в 1.2.X вероятно, предпочтительнее заменить ng-if
для ng-show
выше
вот обязательный plunker link
кроме того, я написал несколько записей в блоге только об этом предмете, который идет немного более подробно:
Пользовательские Директивы Проверки
Edit: использование ngMessages в 1.3.X
теперь вы можете использовать модуль ngMessages вместо ngShow, чтобы показать свою ошибку сообщения. Он будет работать с чем угодно, это не должно быть сообщение об ошибке, но вот основы:
- включить
<script src="angular-messages.js"></script>
-
ссылка
ngMessages
в объявлении модуля:var app = angular.module('myApp', ['ngMessages']);
-
добавить соответствующую разметку:
<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>
В приведенной выше разметке, ng-message="personForm.email.$error"
в основном определяет контекст для ng-message
директив ребенка. Тогда ng-message="required"
и ng-message="email"
указать свойства в этом контексте для просмотра. самое главное, они также указывают порядок их проверки в. Первый, который он находит в списке, который является "правдивым", выигрывает, и он покажет это сообщение, и никто другой.
проект Angular-UI включает директиву UI-validate, которая, вероятно, поможет вам в этом. Это позволит вам указать функцию для вызова, чтобы выполнить проверку.
взгляните на демонстрационную страницу:http://angular-ui.github.com/, поиск вниз к заголовку проверки.
С демо-страницы:
<input ng-model="email" ui-validate='{blacklist : notBlackListed}'>
<span ng-show='form.email.$error.blacklist'>This e-mail is black-listed!</span>
затем в вашем контроллере:
function ValidateCtrl($scope) {
$scope.blackList = ['bad@domain.com','verybad@domain.com'];
$scope.notBlackListed = function(value) {
return $scope.blackList.indexOf(value) === -1;
};
}
вы можете использовать ng-required для вашего сценария проверки ("если эти 3 поля заполнены, то это поле обязательно":
<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>
можно использовать Угловое-Оценщику.
пример: использование функции для проверки поля
<input type = "text"
name = "firstName"
ng-model = "person.firstName"
validator = "myCustomValidationFunction(form.firstName)">
тогда в вашем контроллере у вас будет что-то вроде
$scope.myCustomValidationFunction = function(firstName){
if ( firstName === "John") {
return true;
}
вы также можете сделать что-то вроде этого:
<input type = "text"
name = "firstName"
ng-model = "person.firstName"
validator = "'!(field1 && field2 && field3)'"
invalid-message = "'This field is required'">
(где field1 field2 и field3-переменные области. Вы также можете проверить, не равны ли поля пустой строке)
если поле не проходит the validator
затем поле будет помечено как недопустимое, и пользователь не сможет отправить форму.
дополнительные примеры использования см. В разделе:https://github.com/turinggroup/angular-validator
отказ от ответственности: я являюсь автором Angular-Validator
вот классный способ сделать пользовательские проверки выражений подстановочных знаков в форме (от:Расширенная проверка формы с AngularJS и фильтрами):
<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 (поддерживает именование выражений и несколько выражений)
Это похоже на ui-validate
, но вам не нужна конкретная функция проверки области (это работает в целом) и, конечно, вам не нужно пользовательский интерфейс.utils этот путь.
недавно я создал директиву, позволяющую аннулировать входные данные угловой формы на основе выражения. Можно использовать любое допустимое угловое выражение, и оно поддерживает пользовательские ключи проверки с использованием нотации объекта. Испытано с угловым v1.3.8
.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);
});
}
}
};
}]);
вы можете использовать его как это:
<input ng-model="foo" invalid-if="{fooIsGreaterThanBar: 'foo > bar',
fooEqualsSomeFuncResult: 'foo == someFuncResult()'}/>
или просто передав выражение (ему будет присвоен validationKey по умолчанию "invalidIf")
<input ng-model="foo" invalid-if="foo > bar"/>
@synergetic я думаю, что @blesh предположим, чтобы поставить функцию validate, как показано ниже
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);
обновление:
улучшенная и упрощенная версия предыдущей директивы (одна вместо двух) с той же функциональностью:
.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();
});
});
}
}
};
}])
пример использования:
<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 />
результат: взаимозависимые тестовые выражения, в которых валидаторы выполняются при изменении чужой модели директивы и текущей модели.
тестовое выражение имеет локальный $model
переменная, которую вы должны использовать для сравнения с другими переменная.
ранее:
Я попытался улучшить код @Plantface, добавив дополнительную директиву. Эта дополнительная директива очень полезна, если наше выражение должно выполняться при внесении изменений в несколько переменных 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();
});
});
}
};
}])
пример использования для создания перекрестных проверенных полей:
<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
выполняется для проверки модели, когда ng-model
или какой-либо из ensure-watch
переменные изменяются.
в AngularJS лучшим местом для определения пользовательской проверки является директива Cutsom. AngularJS обеспечивает модуль ngMessages.
ngMessages-это директива, предназначенная для отображения и скрытия сообщений на основе состояния объекта key / value, который он прослушивает. Этот сама директива дополняет отчеты об ошибках с помощью ngModel $error object (который хранит состояние ключа / значения ошибок проверки).
для проверки пользовательской формы следует используйте модули ngMessages с пользовательской директивой.Здесь у меня есть простая проверка, которая проверит, если длина номера меньше, чем 6 отображает ошибку на экране
<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>
вот как создать пользовательскую директиву проверки
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
встроенная функция для установки состояния модели в valid / invalid
я расширил ответ @Ben Lesh с возможностью указать, является ли проверка чувствительной к регистру или нет (по умолчанию)
использовать:
<input type="text" name="fruitName" ng-model="data.fruitName" blacklist="Coconuts,Bananas,Pears" caseSensitive="true" required/>
код:
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;
});
}
};
}
]);
пользовательские проверки, которые вызывают сервер
использовать ngModelController $asyncValidators
API который обрабатывает асинхронную проверку, такую как создание $http
запрос к backend. Функции, добавленные к объекту, должны возвращать обещание, которое должно быть разрешено при допустимом или отклонено при недопустимом. Выполняемые асинхронные проверки сохраняются ключом в ngModelController.$pending
. Дополнительные сведения см. В разделе AngularJS Руководство Разработчика-Формы (Пользовательские Проверка).
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;
});
};
для получения дополнительной информации см. раздел
некоторые отличные примеры и библиотеки, представленные в этой теме, но у них не было того, что я искал. Мой подход: угловое-действительность -- lib проверки обещания основанный для асинхронной проверки, с опционным стилем Bootstrap испеченным-внутри.
решение угловой валидности для варианта использования OP может выглядеть примерно так:
<input type="text" name="field4" ng-model="field4"
validity="eval"
validity-eval="!(field1 && field2 && field3 && !field4)"
validity-message-eval="This field is required">
здесь Скрипка, Если вы хотите взять его на спину. Lib доступен на GitHub, имеет подробную документацию и множество живых демонстраций.