J’ai les règles suivantes
le premier fonctionne avec une validation côté client discrète, le second ne fonctionne pas
des idées pourquoi?
RuleFor(x => x.StartDate) .LessThanOrEqualTo(x => x.EndDate.Value) .WithLocalizedMessage(() => CommonRes.Less_Than_Or_Equal_To, filters => CommonRes.Start_Date, filters => CommonRes.End_Date); RuleFor(x => x.StartDate) .GreaterThanOrEqualTo(x => x.AbsoluteStartDate) .LessThanOrEqualTo(x => x.AbsoluteEndDate) .WithLocalizedMessage(() => CommonRes.Between, filters => CommonRes.Start_Date, filters => filters.AbsoluteStartDate, filters => filters.AbsoluteEndDate);
Aucune des règles LessThanOrEqualTo
ou GreaterThanOrEqualTo
n’est prise en charge par la validation côté client, comme expliqué dans la documentation .
Cela signifie que si vous voulez les valider côté client, vous devrez écrire un FluentValidationPropertyValidator
personnalisé et implémenter la méthode GetClientValidationRules
qui vous permettra d’enregistrer un adaptateur personnalisé et d’implémenter la logique de validation côté client en javascript.
Si vous êtes intéressé par la façon dont cela pourrait être réalisé, faites un ping et je vous donnerai un exemple.
Mettre à jour
En tant que demande, je vais essayer de montrer un exemple de la façon dont on pourrait implémenter la validation côté client personnalisée pour la règle LessThanOrEqualTo
. Ce n’est qu’un cas particulier avec des dates non nullables. Il est bien sûr possible d’écrire un validateur côté client personnalisé pour tous les cas possibles, mais cela demandera beaucoup plus d’efforts.
Nous commençons donc avec un modèle de vue et un validateur correspondant:
[Validator(typeof(MyViewModelValidator))] public class MyViewModel { [Display(Name = "Start date")] [DisplayFormat(DataFormatSsortingng = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] public DateTime StartDate { get; set; } public DateTime DateToCompareAgainst { get; set; } } public class MyViewModelValidator : AbstractValidator { public MyViewModelValidator() { RuleFor(x => x.StartDate) .LessThanOrEqualTo(x => x.DateToCompareAgainst) .WithMessage("Invalid start date"); } }
Puis un contrôleur:
public class HomeController : Controller { public ActionResult Index() { var model = new MyViewModel { StartDate = DateTime.Now.AddDays(2), DateToCompareAgainst = DateTime.Now }; return View(model); } [HttpPost] public ActionResult Index(MyViewModel model) { return View(model); } }
et une vue:
@model MyViewModel @using (Html.BeginForm()) { @Html.Hidden("DateToCompareAgainst", Model.DateToCompareAgainst.ToSsortingng("yyyy-MM-dd")) @Html.LabelFor(x => x.StartDate) @Html.EditorFor(x => x.StartDate) @Html.ValidationMessageFor(x => x.StartDate) }
Tout cela est la norme jusqu’ici. Cela fonctionnera mais sans validation du client.
La première étape consiste à écrire le FluentValidationPropertyValidator
:
public class LessThanOrEqualToFluentValidationPropertyValidator : FluentValidationPropertyValidator { public LessThanOrEqualToFluentValidationPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator) : base(metadata, controllerContext, rule, validator) { } public override IEnumerable GetClientValidationRules() { if (!this.ShouldGenerateClientSideRules()) { yield break; } var validator = Validator as LessThanOrEqualValidator; var errorMessage = new MessageFormatter() .AppendPropertyName(this.Rule.GetDisplayName()) .BuildMessage(validator.ErrorMessageSource.GetSsortingng()); var rule = new ModelClientValidationRule { ErrorMessage = errorMessage, ValidationType = "lessthanorequaldate" }; rule.ValidationParameters["other"] = CompareAtsortingbute.FormatPropertyForClientValidation(validator.MemberToCompare.Name); yield return rule; } }
qui sera enregistré dans Application_Start
lors de la configuration de notre fournisseur FluentValidation:
FluentValidationModelValidatorProvider.Configure(x => { x.Add(typeof(LessThanOrEqualValidator), (metadata, context, rule, validator) => new LessThanOrEqualToFluentValidationPropertyValidator(metadata, context, rule, validator)); });
Et le dernier bit est l’adaptateur personnalisé sur le client. Nous ajoutons donc bien sûr les 2 scripts à notre page pour permettre une validation côté client discrète:
et l’adaptateur personnalisé:
(function ($) { $.validator.unobtrusive.adapters.add('lessthanorequaldate', ['other'], function (options) { var getModelPrefix = function (fieldName) { return fieldName.substr(0, fieldName.lastIndexOf(".") + 1); }; var appendModelPrefix = function (value, prefix) { if (value.indexOf("*.") === 0) { value = value.replace("*.", prefix); } return value; } var prefix = getModelPrefix(options.element.name), other = options.params.other, fullOtherName = appendModelPrefix(other, prefix), element = $(options.form).find(":input[name=" + fullOtherName + "]")[0]; options.rules['lessthanorequaldate'] = element; if (options.message != null) { options.messages['lessthanorequaldate'] = options.message; } }); $.validator.addMethod('lessthanorequaldate', function (value, element, params) { var parseDate = function (date) { var m = date.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/); return m ? new Date(parseInt(m[1]), parseInt(m[2]) - 1, parseInt(m[3])) : null; }; var date = parseDate(value); var dateToCompareAgainst = parseDate($(params).val()); if (isNaN(date.getTime()) || isNaN(dateToCompareAgainst.getTime())) { return false; } return date <= dateToCompareAgainst; }); })(jQuery);
L’exemple de Darin contient des éléments obsolètes, alors voici un exemple plus à jour que j’ai qui fait des comparaisons de numéros. Vous pouvez facilement le modifier pour les comparaisons de dates si:
Javascript:
(function ($) { $.validator.addMethod("lessthanorequal", function(value, element, param) { return this.optional(element) || parseFloat(value) <= parseFloat(param); }, "Must be less than"); $.validator.unobtrusive.adapters.add("lessthanorequal", ["field"], function (options) { options.rules["lessthanorequal"] = options.params.field; if (options.message) options.messages["lessthanorequal"] = options.message; }); })(jQuery);
C #
public class LessThanOrEqualPropertyValidator : FluentValidationPropertyValidator { public LessThanOrEqualPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator) : base(metadata, controllerContext, rule, validator) { } public override IEnumerable GetClientValidationRules() { if (!ShouldGenerateClientSideRules()) yield break; var formatter = new MessageFormatter().AppendPropertyName(Rule.PropertyName); ssortingng message = formatter.BuildMessage(Validator.ErrorMessageSource.GetSsortingng()); var rule = new ModelClientValidationRule { ValidationType = "lessthanorequal", ErrorMessage = message }; rule.ValidationParameters["field"] = ((LessThanOrEqualValidator)Validator).ValueToCompare; yield return rule; } }
Global.asax Application_Start:
FluentValidation.Mvc.FluentValidationModelValidatorProvider.Configure(x => { x.Add(typeof(LessThanOrEqualValidator), (metadata, context, description, validator) => new LessThanOrEqualPropertyValidator(metadata, context, description, validator)); });
Donc, maintenant, toute règle numérique utilisant LessThanOrEqual sera validée côté client.
LessThanOrEqualTo
et GreaterThanOrEqualTo
ne prennent pas en charge la validation client hors de la boîte.
Cependant, InclusiveBetween
est pris en charge. Donc, vous pouvez utiliser InclusiveBetween
.
Exemple
RuleFor(x => x.StartDate) .InclusiveBetween(x.AbsoluteStartDate, x.AbsoluteEndDate)
Voir la documentation pour plus d’informations sur les méthodes client supscopes .