Je suis un débutant angulaire et je tombe sur quelque chose dans la façon dont les directives de validation de formulaire d'angular fonctionnent.
Je sais que je peux assez facilement ajouter des directives à des champs individuels , mais j'essaie d'ajouter une validation qui comparera deux champs de formulaire (qui sont tous deux des éléments d'un modèle).
Voici un squelette de formulaire:
<form name="edit_form" >
<input name="min" type="number" ng-model="field.min"/>
<input name="max" type="number" ng-model="field.max"/>
</form>
<div class="error" ng-show="edit_form.min.$dirty || edit_form.max.$dirty">
<small class="error" ng-show="(what goes here?)">
Min cannot exceed max
</small>
</div>
En bref, je veux écrire une directive et l'utiliser pour afficher/cacher ce small.error
si min
et max
ont tous les deux des valeurs mais min > max
. Comment puis-je accéder aux deux champs d'une même directive? Une directive est-elle le bon outil pour ce travail?
Много способов снять шкуру с кошки.
app.directive('lowerThan', [
function() {
var link = function($scope, $element, $attrs, ctrl) {
var validate = function(viewValue) {
var comparisonModel = $attrs.lowerThan;
if(!viewValue || !comparisonModel){
// It's valid because we have nothing to compare against
ctrl.$setValidity('lowerThan', true);
}
// It's valid if model is lower than the model we're comparing against
ctrl.$setValidity('lowerThan', parseInt(viewValue, 10) < parseInt(comparisonModel, 10) );
return viewValue;
};
ctrl.$parsers.unshift(validate);
ctrl.$formatters.Push(validate);
$attrs.$observe('lowerThan', function(comparisonModel){
// Whenever the comparison model changes we'll re-validate
return validate(ctrl.$viewValue);
});
};
return {
require: 'ngModel',
link: link
};
}
]);
Использование:
<input name="min" type="number" ng-model="field.min" lower-than="{{field.max}}" />
<span class="error" ng-show="form.min.$error.lowerThan">
Min cannot exceed max.
</span>
Vous n'avez besoin d'aucune directive. Attribuez simplement la valeur "min" de max à min-value. Comme:
<input name="min" type="number" ng-model="field.min"/>
<input name="max" type="number" ng-model="field.max" min=" {{ field.min }}"/>
Et vous n'avez besoin d'aucune personnalisation.
Plus: vous pouvez faire min=" {{ field.min + 1}}"
Une simple comparaison vous conviendrait-elle?
<small class="error" ng-show="field.min > field.max">
Je pense qu'une directive serait exagérée si votre cas n'est que cela. Si vous ne vous sentez pas à l'aise avec la vue contenant la logique d'application, vous pouvez l'exporter dans une fonction du contrôleur:
$scope.isMinMaxInalid = function() {
return $scope.field.min > $scope.field.max;
};
Et le modèle:
<small class="error" ng-show="isMinMaxInalid()">
Pour moi, au-delà d'un message de retour, j'avais besoin de définir le champ comme invalide, empêchant l'envoi. J'ai donc rassemblé quelques approches, comme l'approche @thestewie, avec une configuration de vue pour réunir une solution de comparaison de dates. J'espère pouvoir agréger les solutions qui ont été présentées.
Le code est dans _ PLUNKER
angular.module('MyApp')
.directive('thisEarlierThan', function () {
return {
require: 'ngModel',
restrict: 'A',
link: function (scope, elem, attrs, ctrl) {
var startDate,
endDate;
scope.$watch(attrs.ngModel, function (newVal, oldVal, scope) {
startDate = newVal;
check();
});
scope.$watch(attrs.thisEarlierThan, function (newVal, oldVal, scope) {
endDate = newVal;
check();
});
var check = function () {
if (typeof startDate === 'undefined' || typeof endDate === 'undefined') {
return;
}
if (!validate(startDate)) {
startDate = new Date(startDate);
if (!validate(startDate)) {
return;
}
}
if (!validate(endDate)) {
endDate = new Date(endDate);
if (!validate(endDate)) {
return;
}
}
if (startDate < endDate) {
ctrl.$setValidity('thisEarlierThan', true);
}
else {
ctrl.$setValidity('thisEarlierThan', false);
}
return;
};
var validate = function (date) {
if (Object.prototype.toString.call(date) === '[object Date]') {
if (isNaN(date.getTime())) {
return false;
}
else {
return true;
}
}
else {
return false;
}
};
}
};
})
;
Ma version de la directive:
module.directive('greaterThan', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attributes, ngModelController) {
var otherValue;
scope.$watch(attributes.greaterThan, function (value) {
otherValue = value;
ngModelController.$validate();
});
ngModelController.$parsers.unshift(function (viewValue) {
ngModelController.$setValidity('greaterThan', !viewValue || !otherValue || viewValue > otherValue);
return viewValue;
});
}
};
});
Vous pouvez consulter https://github.com/nelsonomuto/angular-ui-form-validation
Ceci fournit une directive préconfigurée avec une API qui expose l'étendue et ses modèles à votre fonction de validation.
Voici un exemple de votre cas d'utilisation spécifique: http://plnkr.co/edit/S0rBlS?p=preview
La syntaxe des validateurs de directives est celle indiquée dans l'exemple ci-dessous:
{
errorMessage: 'Cannot contain the number one',
validator: function (errorMessageElement, val, attr, element, model, modelCtrl){
/**
* The model and modelCtrl(scope) are exposed in the validator function
* */
return /1/.test(val) !== true;
}
}