web-dev-qa-db-fra.com

Comment changer la validation du message 'data-val-number' dans MVC pendant qu'il est généré par @Html helper

Supposons ce modèle:

Public Class Detail
    ...
    <DisplayName("Custom DisplayName")>
    <Required(ErrorMessage:="Custom ErrorMessage")>
    Public Property PercentChange As Integer
    ...
end class

et la vue:

@Html.TextBoxFor(Function(m) m.PercentChange)

procédera ce html:

   <input data-val="true" 
    data-val-number="The field 'Custom DisplayName' must be a number." 
    data-val-required="Custom ErrorMessage"     
    id="PercentChange" 
    name="PercentChange" type="text" value="0" />

Je souhaite personnaliser le message d'erreur data-val-number Qui, je suppose, a généré car PercentChange est un Integer. Je cherchais un tel attribut pour le changer, range ou tout ce qui ne fonctionne pas.
Je sais qu'il est possible de modifier le fichier js discret lui-même ou de le remplacer côté client. Je veux changer le message d'erreur de data-val-number Comme les autres côté serveur.

74
GtEx

Ce ne sera pas facile. Le message par défaut est stocké en tant que ressource intégrée dans le System.Web.Mvc L'assemblage et la méthode qui récupère est une méthode statique privée d'une classe interne scellée interne (System.Web.Mvc.ClientDataTypeModelValidatorProvider+NumericModelValidator.MakeErrorString). C'est comme si le gars du codage Microsoft cachait un secret :-)

Vous pouvez jeter un œil à ce qui suit article de blog qui décrit une solution possible. Vous devez essentiellement remplacer l'existant ClientDataTypeModelValidatorProvider par un personnalisé.

Si vous n'aimez pas le codage hardcore que vous devrez faire, vous pouvez également remplacer cette valeur entière dans votre modèle de vue par une chaîne et avoir un attribut de validation personnalisé qui ferait l'analyse et fournirait un message d'erreur personnalisé (qui pourrait même être localisé).

38
Darin Dimitrov

Vous pouvez remplacer le message en fournissant vous-même l'attribut data-val-number lors du rendu du champ. Cela remplace le message par défaut. Cela fonctionne au moins avec MVC 4.

@ Html.EditorFor (model => model.MyNumberField, new {data_val_number = "Fournissez un entier, mec!"})

N'oubliez pas que vous devez utiliser le soulignement dans le nom d'attribut pour que Razor accepte votre attribut.

73
HenningJ

Ce que vous devez faire, c'est:

Ajoutez le code suivant dans Application_Start() dans Global.asax:

 ClientDataTypeModelValidatorProvider.ResourceClassKey = "Messages";
 DefaultModelBinder.ResourceClassKey = "Messages";

Cliquez avec le bouton droit sur votre projet ASP.NET MVC dans VS. Sélectionnez Add => Add ASP.NET Folder => App_GlobalResources.

Ajouter un .resx fichier appelé Messages.resx dans ce dossier.

Ajoutez ces ressources de chaîne dans le .resx fichier:

FieldMustBeDate        The field {0} must be a date.
FieldMustBeNumeric     The field {0} must be a number.
PropertyValueInvalid   The value '{0}' is not valid for {1}.
PropertyValueRequired  A value is required.

Modifiez la valeur FieldMustBeNumeric comme vous le souhaitez ... :)

Vous avez terminé.


Consultez cet article pour plus de détails:

Localisation des messages d'erreur par défaut dans ASP.NET MVC et WebForms

50
Leniel Maccaferri

En guise d'alternative, j'ai appliqué un attribut RegularExpression pour intercepter l'entrée non valide et y placer mon message:

[RegularExpression(@"[0-9]*$", ErrorMessage = "Please enter a valid number ")]

C'est un peu un hack mais cela semble préférable à la complexité des autres solutions présentées, du moins dans ma situation particulière.

EDIT: Cela a bien fonctionné dans MVC3, mais il semble qu'il pourrait bien y avoir de meilleures solutions pour MVC4 +.

23
Matthew Nichols

De ce livre sur MVC 3 que j'ai. Tout ce que vous avez à faire est le suivant:

public class ClientNumberValidatorProvider : ClientDataTypeModelValidatorProvider 
{ 
   public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, 
                                                          ControllerContext context) 
   { 
       bool isNumericField = base.GetValidators(metadata, context).Any(); 
       if (isNumericField) 
           yield return new ClientSideNumberValidator(metadata, context); 
   } 
} 

public class ClientSideNumberValidator : ModelValidator 
{ 
  public ClientSideNumberValidator(ModelMetadata metadata,  
      ControllerContext controllerContext) : base(metadata, controllerContext) { } 

  public override IEnumerable<ModelValidationResult> Validate(object container) 
  { 
     yield break; // Do nothing for server-side validation 
  } 

  public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() 
  { 
     yield return new ModelClientValidationRule { 
        ValidationType = "number", 
        ErrorMessage = string.Format(CultureInfo.CurrentCulture,  
                                     ValidationMessages.MustBeNumber,  
                                     Metadata.GetDisplayName()) 
        }; 
  } 
} 

protected void Application_Start() 
{ 
    // Leave the rest of this method unchanged 

    var existingProvider = ModelValidatorProviders.Providers 
        .Single(x => x is ClientDataTypeModelValidatorProvider); 
    ModelValidatorProviders.Providers.Remove(existingProvider); 
    ModelValidatorProviders.Providers.Add(new ClientNumberValidatorProvider()); 
} 

Remarquez comment le ErrorMessage est généré, vous spécifiez la culture actuelle et le message localisé est extrait du fichier de ressources ValidationMessages (ici les spécificités de la culture) .resx. Si vous n'en avez pas besoin, remplacez-le simplement par votre propre message.

11
Denis Valeev

Voici une autre solution qui modifie le côté client du message sans changer la source MVC3. Tous les détails dans cet article de blog:

https://greenicicle.wordpress.com/2011/02/28/fixing-non-localizable-validation-messages-with-javascript/

En bref, ce que vous devez faire est d'inclure le script suivant après le chargement de la validation jQuery plus le fichier de localisation approprié .

(function ($) {
    // Walk through the adapters that connect unobstrusive validation to jQuery.validate.
    // Look for all adapters that perform number validation
    $.each($.validator.unobtrusive.adapters, function () {
        if (this.name === "number") {
            // Get the method called by the adapter, and replace it with one 
            // that changes the message to the jQuery.validate default message
            // that can be globalized. If that string contains a {0} placeholder, 
            // it is replaced by the field name.
            var baseAdapt = this.adapt;
            this.adapt = function (options) {
                var fieldName = new RegExp("The field (.+) must be a number").exec(options.message)[1];
                options.message = $.validator.format($.validator.messages.number, fieldName);
                baseAdapt(options);
            };
        }
    });
} (jQuery));
7
Phil Hale

Vous pouvez définir ResourceKey de la classe ClientDataTypeModelValidatorProvider sur le nom d'une ressource globale qui contient la clé FieldMustBeNumeric pour remplacer le message d'erreur de validation mvc de nombre par votre message personnalisé. FieldMustBeDate est également un message d'erreur de validation de la date.

ClientDataTypeModelValidatorProvider.ResourceKey="MyResources"; // MyResource is my global resource
4
reza taroosheh

Voici une autre solution en pure js qui fonctionne si vous souhaitez spécifier des messages globalement et non des messages personnalisés pour chaque élément.

La clé est que les messages de validation sont définis à l'aide de jquery.validation.unobtrusive.js en utilisant le data-val-xxx attribut sur chaque élément, donc tout ce que vous avez à faire est de remplacer ces messages avant que la bibliothèque ne les utilise, c'est un peu sale mais je voulais juste que le travail soit fait et rapide, alors voici pour la validation du type de nombre:

    $('[data-val-number]').each(function () {
    var el = $(this);
    var orig = el.data('val-number');

    var fieldName = orig.replace('The field ', '');
    fieldName = fieldName.replace(' must be a number.', '');

    el.attr('data-val-number', fieldName + ' باید عددی باشد')
});

la bonne chose est qu'il ne nécessite pas de compilation et que vous pouvez l'étendre facilement plus tard, pas robuste mais rapide.

3
mohas

Vérifiez aussi ceci:

Le guide complet de validation dans ASP.NET MVC 3 - Partie 2

Les principales parties de l'article suivent (copier-coller).

La création d'un validateur personnalisé entièrement fonctionnel qui fonctionne à la fois sur le client et le serveur comporte quatre parties distinctes. D'abord, nous sous-classons ValidationAttribute et ajoutons notre logique de validation côté serveur. Ensuite, nous implémentons IClientValidatable sur notre attribut pour autoriser HTML5 data-* attributs à transmettre au client. Troisièmement, nous écrivons une fonction JavaScript personnalisée qui effectue la validation sur le client. Enfin, nous créons un adaptateur pour transformer les attributs HTML5 en un format que notre fonction personnalisée peut comprendre. Bien que cela ressemble à beaucoup de travail, une fois que vous aurez commencé, vous le trouverez relativement simple.

Sous-classement ValidationAttribute

Dans cet exemple, nous allons écrire un validateur NotEqualTo qui vérifie simplement que la valeur d'une propriété n'est pas égale à la valeur d'une autre.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class NotEqualToAttribute : ValidationAttribute
{
    private const string DefaultErrorMessage = "{0} cannot be the same as {1}.";

    public string OtherProperty { get; private set; }

    public NotEqualToAttribute(string otherProperty)
        : base(DefaultErrorMessage)
    {
        if (string.IsNullOrEmpty(otherProperty))
        {
            throw new ArgumentNullException("otherProperty");
        }

        OtherProperty = otherProperty;
    }

    public override string FormatErrorMessage(string name)
    {
        return string.Format(ErrorMessageString, name, OtherProperty);
    }

    protected override ValidationResult IsValid(object value, 
        ValidationContext validationContext)
    {
        if (value != null)
        {
            var otherProperty = validationContext.ObjectInstance.GetType()
                .GetProperty(OtherProperty);

            var otherPropertyValue = otherProperty
                .GetValue(validationContext.ObjectInstance, null);

            if (value.Equals(otherPropertyValue))
            {
                return new ValidationResult(
                    FormatErrorMessage(validationContext.DisplayName));
            }
        }
    return ValidationResult.Success;
    }        
}

Ajoutez le nouvel attribut à la propriété de mot de passe de RegisterModel et exécutez l'application.

[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
[NotEqualTo("UserName")]
public string Password { get; set; }
...

Implémentation de IClientValidatable

ASP.NET MVC 2 avait un mécanisme pour ajouter une validation côté client mais ce n'était pas très joli. Heureusement dans MVC 3, les choses se sont améliorées et le processus est maintenant assez trivial et heureusement ne le fait pas implique de changer le Global.asax comme dans la version précédente.

La première étape consiste pour votre attribut de validation personnalisé à implémenter IClientValidatable. Il s'agit d'une interface simple à une méthode:

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
    ModelMetadata metadata,
    ControllerContext context)
{
    var clientValidationRule = new ModelClientValidationRule()
    {
        ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
        ValidationType = "notequalto"
    };

    clientValidationRule.ValidationParameters.Add("otherproperty", OtherProperty);

    return new[] { clientValidationRule };
}

Si vous exécutez l'application maintenant et affichez la source, vous verrez que l'entrée de mot de passe html contient maintenant vos attributs de données notequalto:

<div class="editor-field">
    <input data-val="true" data-val-notequalto="Password cannot be the same as UserName." 
    data-val-notequalto-otherproperty="UserName" 
    data-val-regex="Weak password detected." 
    data-val-regex-pattern="^(?!password$)(?!12345$).*" 
    data-val-required="The Password field is required." 
    id="Password" name="Password" type="password" />
    <span class="hint">Enter your password here</span>
    <span class="field-validation-valid" data-valmsg-for="Password" 
    data-valmsg-replace="true"></span>
</div>

Création d'une fonction de validation jQuery personnalisée

Il est préférable de placer tout ce code dans un fichier JavaScript distinct.

(function ($) {
    $.validator.addMethod("notequalto", function (value, element, params) {
        if (!this.optional(element)) {
            var otherProp = $('#' + params);
            return (otherProp.val() != 
        }
    return true;
});

$.validator.unobtrusive.adapters.addSingleVal("notequalto", "otherproperty");

}(jQuery));

En fonction de vos exigences de validation, vous pouvez constater que la bibliothèque jquery.validate possède déjà le code dont vous avez besoin pour la validation elle-même. Il y a beaucoup de validateurs dans jquery.validate qui n'ont pas été implémentés ou mappés sur des annotations de données, donc si ceux-ci répondent à vos besoins, alors tout ce dont vous avez besoin pour écrire en javascript est un adaptateur ou même un appel à un adaptateur intégré qui peut être aussi petit qu'une seule ligne. Jetez un œil à l'intérieur jquery.validate.js pour découvrir ce qui est disponible.

Utilisation d'un adaptateur jquery.validate.unobtrusive existant

Le travail de l'adaptateur est de lire le HTML5 data-* attributs sur votre élément de formulaire et convertissez ces données en un formulaire compréhensible par jquery.validate et votre fonction de validation personnalisée. Vous n'êtes pas obligé de faire tout le travail vous-même et dans de nombreux cas, vous pouvez appeler un adaptateur intégré. jquery.validate.unobtrusive déclare trois adaptateurs intégrés qui peuvent être utilisés dans la majorité des situations. Ceux-ci sont:

jQuery.validator.unobtrusive.adapters.addBool - used when your validator does not need any additional data.
jQuery.validator.unobtrusive.adapters.addSingleVal - used when your validator takes in one piece of additional data.
jQuery.validator.unobtrusive.adapters.addMinMax - used when your validator deals with minimum and maximum values such as range or string length.

Si votre validateur ne rentre pas dans l'une de ces catégories, vous devez écrire votre propre adaptateur en utilisant le jQuery.validator.unobtrusive.adapters.add méthode. Ce n'est pas aussi difficile qu'il y paraît et nous verrons un exemple plus loin dans l'article.

Nous utilisons la méthode addSingleVal, en transmettant le nom de l'adaptateur et le nom de la valeur unique que nous voulons transmettre. Si le nom de la fonction de validation diffère de l'adaptateur, vous pouvez passer un troisième paramètre (ruleName):

jQuery.validator.unobtrusive.adapters.addSingleVal("notequalto", "otherproperty", "mynotequaltofunction");

À ce stade, notre validateur personnalisé est terminé.

Pour une meilleure compréhension, reportez-vous à article lui-même qui présente plus de description et un exemple plus complexe.

HTH.

2
Kamran

Je viens de le faire et j'ai ensuite utilisé une expression régulière:

$(document).ready(function () {
    $.validator.methods.number = function (e) {
        return true;
    };
});


[RegularExpression(@"^[0-9\.]*$", ErrorMessage = "Invalid Amount")]
public decimal? Amount { get; set; }
1
Rob

Ou vous pouvez simplement le faire.

@Html.ValidationMessageFor(m => m.PercentChange, "Custom Message: Input value must be a number"), new { @style = "display:none" })

J'espère que cela t'aides.

1
Edward Disi

J'ai ce problème dans KendoGrid, j'utilise un script à la FIN de la vue pour remplacer data-val-number:

@(Html.Kendo().Grid<Test.ViewModel>(Model)
  .Name("listado")
  ...
  .Columns(columns =>
    {
        columns.Bound("idElementColumn").Filterable(false);
    ...
    }

Et au moins, à la fin de View, je mets:

<script type="text/javascript">
        $("#listado").on("click", function (e) {
            $(".k-grid #idElementColumn").attr('data-val-number', 'Ingrese un número.');
        });    
</script>
0

Je fais cela en mettant cela à mon avis

@Html.DropDownListFor(m => m.BenefNamePos, Model.Options, new { onchange = "changePosition(this);", @class="form-control", data_val_number = "This is my custom message" })
0
Fernando Campos