Issue with Decimals, Commas and Client-Side Validation

前端 未结 2 623
栀梦
栀梦 2021-01-13 18:27

I\'m trying to achieve client-side validation for a nullable whose decimal separator can be a comma (e.g.: 123,45).

In my View:



        
2条回答
  •  甜味超标
    2021-01-13 19:26

    I've struggled quite a bit with this.

    The best approach for me is to define a custom binder for decimals:

    public class DecimalModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext,
            ModelBindingContext bindingContext)
        {
            ValueProviderResult valueResult = bindingContext.ValueProvider
                .GetValue(bindingContext.ModelName);
            ModelState modelState = new ModelState { Value = valueResult };
            object actualValue = null;
            try
            {
                //Check if this is a nullable decimal and a null or empty string has been passed
                var isNullableAndNull = (bindingContext.ModelMetadata.IsNullableValueType &&
                                         string.IsNullOrEmpty(valueResult.AttemptedValue));
    
                //If not nullable and null then we should try and parse the decimal
                if (!isNullableAndNull)
                {
                    actualValue = Convert.ToDecimal(valueResult.AttemptedValue, CultureInfo.CurrentCulture);
                }
            }
            catch (FormatException e)
            {
                modelState.Errors.Add(e);
            }
    
            bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
            return actualValue;
        }
    }
    

    and bind it in the Application_Start in Global.asax:

    ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
    ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());
    

    I also use the globalize script (with cultures) which can be found here or downloaded from nuget here.

    Your bundle should look something like this:

    bundles.Add(ScriptBundle("~/bundles/jquery").Include(
        "~/Scripts/jquery-{version}.js",
        "~/Scripts/globalize.js",
        "~/Scripts/cultures/globalize.culture.en-GB.js",
        "~/Scripts/cultures/globalize.culture.it-IT.js"
        ));
    

    Of course you can add more culures if you want to support different localizations.

    Now, when your DOM is ready (javascript) you can define your culture:

    Globalize.culture('en-GB');
    
    $.validator.methods.number = function (value, element) {
        return this.optional(element) || jQuery.isNumeric(Globalize.parseFloat(value));
    }
    
    //Fix the range to use globalized methods
    jQuery.extend(jQuery.validator.methods, {
        range: function (value, element, param) {
        var val = Globalize.parseFloat(value);
        return this.optional(element) || (val >= param[0] && val <= param[1]);
        }
    });
    
    $.validator.methods.date = function (value, element) {
        return (this.optional(element) || Globalize.parseDate(value));
    }
    

    and customize your validations (I've added the date as well). You've done that in your jQueryFixes.

    You can find a working example here (MvcAppForDecimals) where you can change languages using a toolbar and cookies so that the culture can change on the server as well.

    In the example I read the cookie in Application_BeginRequest or use the default culture define in the web.config:

    
    

    I've also defined a ActionFilter (LanguageFilterAttribute) which injects the current culture in a base viewmodel so the client uses the current set on the server side.

    An extended explanation can be found here.

    Some more info about the globalize script and culture settings here.

提交回复
热议问题