web-dev-qa-db-fra.com

La validation MVC/JQuery n'accepte pas les virgules comme séparateur décimal

Mise à jour du 07.01.2018

Même s'il a été suggéré qu'il s'agit plutôt d'un problème jQuery que d'un problème MVC, je pense que c'est un problème MVC. J'ai créé l'application entière dans asp.net core 2.0 MVC et l'erreur persiste. Pour moi, le lien avec MVC est le fait que je peux résoudre le problème de validation de la date en ajoutant la ligne [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")] au modèle. MVC a donc une influence sur la validation. Je suppose donc qu’il existe un moyen dans MVC de résoudre ce problème (voir ceci post ). S'il vous plaît poster des réponses pour asp.net core 2.0.

Message original

Dans une page MVC5, je rends une propriété Double dans une zone de texte. Lorsque la page est chargée, la valeur est indiquée avec un "," comme séparateur décimal, ce qui est correct, car la page est exécutée sur un système allemand. Si je veux enregistrer le formulaire, j'obtiens une erreur de validation. Comment cela peut-il être résolu? Je sais qu'il y a des questions sur le sujet, mais pour autant que je sache, la plupart d'entre elles sont obsolètes ... J'ai encore du mal à comprendre qu'il n'existe aucun paramètre ou élément intégré permettant aux utilisateurs de différents pays de travailler avec les applications MVC.

Modèle:

[DisplayFormat(DataFormatString = "{0:n2}", ApplyFormatInEditMode = true)]
public Double Gewicht
{
    get { return gewicht; }
    set { gewicht = value; OnPropertyChanged(new PropertyChangedEventArgs("Gewicht")); }
}

CSHTML:

<div class="form-group">
    @Html.LabelFor(model => model.Gewicht, htmlAttributes: new { @class = "control-label col-md-3" })
    <div class="col-md-8">
        @Html.EditorFor(model => model.Gewicht, new { htmlAttributes = new { @class = "form-control col-md-1" } })
        @Html.ValidationMessageFor(model => model.Gewicht, "", new { @class = "text-danger" })
    </div>
</div>

Web.config

<globalization uiCulture="de-DE" culture="de-DE" />

Zone après son chargement -> Valeur chargée avec une virgule comme séparateur décimal  enter image description here

La case après avoir cliqué sur le bouton d'envoi -> Erreur de validation pour la même valeur

 enter image description here

La case après que la virgule soit changée en point -> Aucune erreur de validation  enter image description here

Mise à jour 05.01.2018

J'ai essayé la solution montrée ici qui, malheureusement, ne fonctionne pas pour moi. Cependant, j’ai aussi découvert que les valeurs non seulement ne sont pas acceptées, mais sont également remplacées par des nombres dans lesquels le séparateur de groupe et le séparateur décimal sont mélangés (voir la photo). Qu'est-ce qui se passe, c'est que la valeur de 22 est modifiée à 22,5 et stockée dans la base de données. Il en résulte qu'une valeur de 2 250,00 est stockée dans la base de données. 

 enter image description here

Mise à jour du 07.01.2018

Ce qui est également intéressant, c’est le fait que les champs de date acceptent parfaitement le format allemand.

Propriété

private DateTime? inbetriebnahmedatum;

[DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")]
public DateTime? Inbetriebnahmedatum
{
    get { return inbetriebnahmedatum; }
    set { inbetriebnahmedatum = value; OnPropertyChanged(new PropertyChangedEventArgs("Inbetriebnahmedatum")); }
}

La valeur indiquée ci-dessous est acceptée et traitée sans erreur.  enter image description here

Mise à jour 07.01.2018 - 2

Si je change la ligne dans edit.cshtml de 

<input asp-for="Gewicht" class="form-control" />

à

<input name="Gewicht" id="Gewicht" type="number" class="form-control" value="@Model.Gewicht"/>

Le formulaire peut être soumis avec la valeur "23,7" sans erreur de validation. Dans le contrôleur, la propriété du modèle lié affiche la valeur "237", tandis que la variable IFormCollection indique la valeur "23,7". Cela suggérerait un problème avec le classeur.

14
Mister 832

Même s'il a été suggéré qu'il s'agit plutôt d'un problème jQuery que d'un problème MVC, je pense que c'est un problème MVC.

Non, ce n'est pas correct. Vous voyez une erreur de validation côté client parce que, par défaut, jquery.validate.js (un plug-in tiers indépendant non associé à Microsoft, utilisé par MVC pour la validation côté client) valide les nombres en fonction du séparateur décimal qui est un . (point), pas un , ( virgule).

MVC est le code côté serveur et ne s'exécute pas dans le navigateur. Pour effectuer la validation côté client, les méthodes HtmlHelper de MVC qui génèrent des contrôles de formulaire rendent un ensemble d'attributs data-val-* dans le code HTML utilisé pour décrire la validation à exécuter, qui sont à leur tour analysés par le plug-in jquery.validate.unobtrusive.js lorsque le DOM est chargé, et les utilise ajouter des règles au $.validator.

Dans le cas de votre propriété double, il ajoutera un attribut data-val-number (en plus de l'attribut data-val-required), ce qui ajoutera la règle number qui est définie comme suit:

// http://docs.jquery.com/Plugins/Validation/Methods/number
number: function( value, element ) {
    return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value);
},

où le séparateur décimal est un point et le séparateur de milliers est une virgule (vraisemblablement parce que le plugin a été développé aux États-Unis et utilise donc un format américain).

Vous devez écraser le comportement par défaut que vous pouvez utiliser en utilisant des plugins tels que jquery.globalize , ou en incluant le script suivant (notez que l'expression régulière échange simplement le point et la virgule)

$.validator.methods.number = function (value, element) {
    return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:\.\d{3})+)?(?:,\d+)?$/.test(value);
}

Notez que le script ci-dessus doit être après le script jquery.validate.js mais pas enveloppé dans $(document).ready()

Pour moi, le lien avec MVC est le fait que je peux résoudre le problème de validation de la date en ajoutant la ligne [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")] au modèle.

C'est en fait votre attribut [DataType(DataType.Date)] en conjonction avec l'attribut [DisplayFormat] qui influence le code HTML généré. L'attribut [DataType] génère <input type="date" ... /> qui restitue HTML-5 datepicker si le navigateur le prend en charge. Conformément aux spécifications, le format doit être yyyy-MM-dd (format ISO), d'où la nécessité de l'attribut [DisplayFormat].

Le datepicker HTML-5 rend la date dans la culture des navigateurs. L'image que vous avez montrée avec l'entrée 26.1.2018 est due au fait que la culture de votre navigateur est de-DE, mais si je naviguais sur votre site, je verrais 26/1/2018 dans l'entrée car ma culture est en-AU (Australien), et si un utilisateur des États-Unis accédait à votre site, ils verraient 1/26/2018.

La raison pour laquelle la validation côté client fonctionne pour la propriété date est que le plug-in jquery.validate.js inclut des règles de date pour le format américain (MM/dd/yyyy) et le format ISO (yyyy-MM-dd). 

Et si vous utilisiez @Html.TextBoxFor(m => m.Inbetriebnahmedatum) (qui ignore vos attributs [DataType] et [DisplayFormat]) et si vous saisiez 26.1.2018 dans l'entrée, une erreur de validation côté client s'afficherait.

21
user3559349

Je pense que le problème est jquery validator J’utilise donc pour résoudre l’erreur virgule/virgule

$.validator.methods.number = function (value, element) {
    return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:[\s\.,]\d{3})+)(?:[\.,]\d+)?$/.test(value);
}

juste essayer de jouer avec

1
Dans

Une solution plus robuste pourrait consister à intégrer les méthodes du validateur dans votre propre fonction, qui convertit votre nombre séparé par des virgules en un nombre séparé par des virgules.

Une astuce consiste à utiliser .call pour appeler la fonction de validateur d’origine comme si "ceci" était celui que les développeurs pensaient (par exemple, ils utilisent une fonction "this.optional" pour leur validation d’étape).

var originalNumber = $.validator.methods.number;
var wrappedNumber = function (value, element) {
    var fixedValue = parseFloat(value.toString().replace(",", "."));
    return originalNumber.call($.validator.prototype, fixedValue, element);     // Call function as if "this" is the original caller
};
$.validator.methods.number = wrappedNumber;

Vous pouvez faire fonctionner ce travail pour n’importe quel validateur, par exemple. la validation de l'étape:

var originalStep = $.validator.methods.step;
var wrappedStep = function (value, element, param) {
    var fixedValue = parseFloat(value.toString().replace(",", "."));
    return originalStep.call($.validator.prototype, fixedValue, element, param);
};
$.validator.methods.step = wrappedStep;
1
Peheje