locked
Decimal Validation in ASP.NET MVC (jQuery) RRS feed

  • Question

  • User-1326558348 posted

    I am struggeling with the (german) decimal seperator ',' at Validation of my ASP.NET MVC (NOT Core) Application. I read a lot posts like

    and tried to solve my problem with this solutions. I spend hours trying to make globalize.js work but I struggled with many diffrent errors.

    Then I tried to simply ovveride the validation method of the validator, like it is described in this post accepted answer:

    The Model

     public class AnnualProject 
        {
           ...
    
            [Display(ResourceType = typeof(Ressources.lang.Projects), Name = "Budget")]
            [DisplayFormat(DataFormatString = "{0:N}", ApplyFormatInEditMode = true)]
            public float Budget { get; set; }
    
          ...
    
        }
    

    The View

    @model DOOR2020.Models.ViewModels.AnnualProjectViewModel
    
    <script type="text/javascript" src="~/Scripts/jquery.validate.js"></script>
    <script type="text/javascript">
    
        $.validator.methods.number = function (value, element) {
            console.log('validate');
            return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:\.\d{3})+)?(?:,\d+)?$/.test(value);
        }
    </script>
    
    ...
    
    <div class="form-group">
        @Html.LabelFor(model => model.Project.Budget, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Project.Budget, new { htmlAttributes = new { @class = "form-control" } }) 
            @Html.ValidationMessageFor(model => model.Project.Budget, "", new { @class = "text-danger" })
        </div>
    </div>
    

    I also tried to add the references via Bundles - But that didn't work as well

    By adding the console.log('validate'); I found out, that this line isn't called.

    Can someone tell me what I did wrong and how to solve my Issue?

    Monday, September 7, 2020 1:41 PM

Answers

  • User1686398519 posted

    Hi schnickalodeon,

    1. By adding the console.log('validate'); I found out, that this line isn't called.
      • Two files are needed to implement MVC client side validation: jquery.validate.min.js and jquery.validate.unobtrusive.min.js. You seem to only use jquery.validate.js.
      • In addition, the two files mentioned above must be quoted after the jquery file.
    2. According to your needs, I made an example for you to refer to.
      1. For the Index view in the example:
        • I used the _Layout view, and the _Layout view has already referenced the jquery file. In addition, there is @RenderSection("scripts", required: false) on the _Layout view, so in my example, I put the js code and the referenced js file inside "@section scripts{}".
        • If you have not referenced the _Layout view, you may need to reference the jquery file on the Index view.
      2. About the comma decimal separator:

    Model

        public class AnnualProjectViewModel
        {
            public AnnualProject Project { get; set; }
        }
        public class AnnualProject
        {
            [DisplayFormat(DataFormatString = "{0:N}", ApplyFormatInEditMode = true)]
            public float Budget { get; set; }
        }

    BudgetController

        public class BudgetController : Controller
        {
            public ActionResult Index()
            {
                return View();
            }
            [HttpPost]
            public ActionResult test(AnnualProjectViewModel test)
            {
                if (ModelState.IsValid)
                {
                }
                return View(test);
            }
        }

    Index

    @model DailyMVCDemo.Models.AnnualProjectViewModel
    @using (Html.BeginForm("test", "Budget", FormMethod.Post))
    {
        <div class="form-group">
            @Html.LabelFor(model => model.Project.Budget, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Project.Budget, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Project.Budget, "", new { @class = "text-danger" })
            </div>
        </div>
        <button type="submit">submit</button>
    
    }
    @section scripts{
        <script src="~/Scripts/jquery.validate.min.js"></script>
        <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
        <script type="text/javascript">
            $.validator.methods.number = function (value, element) {
                console.log('validate');
                return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:\.\d{3})+)?(?:,\d+)?$/.test(value);
            }
        </script>
    }

    test

    @model DailyMVCDemo.Models.AnnualProjectViewModel
    @Html.TextBoxFor(model => model.Project.Budget,new { @class = "form-control"  })

    web.config

      <system.web>
        <compilation debug="true" targetFramework="4.7.2" />
        <httpRuntime targetFramework="4.7.2" />
        <globalization uiCulture="de" culture="de-DE" />
      </system.web>

    FloatModelBinder

        public class FloatModelBinder : DefaultModelBinder
        {
            public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
            {
                var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
                return valueProviderResult == null ? base.BindModel(controllerContext, bindingContext) :float.Parse(valueProviderResult.AttemptedValue, new CultureInfo("de-DE"));
            }
        }

    Global.asax

            protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
                FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles); 
                ModelBinders.Binders.Add(typeof(float), new FloatModelBinder());
                ModelBinders.Binders.Add(typeof(float?), new FloatModelBinder());
            }

    Here is the result.

    Best Regards,

    YihuiSun

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, September 8, 2020 4:01 AM

All replies

  • User1686398519 posted

    Hi schnickalodeon,

    1. By adding the console.log('validate'); I found out, that this line isn't called.
      • Two files are needed to implement MVC client side validation: jquery.validate.min.js and jquery.validate.unobtrusive.min.js. You seem to only use jquery.validate.js.
      • In addition, the two files mentioned above must be quoted after the jquery file.
    2. According to your needs, I made an example for you to refer to.
      1. For the Index view in the example:
        • I used the _Layout view, and the _Layout view has already referenced the jquery file. In addition, there is @RenderSection("scripts", required: false) on the _Layout view, so in my example, I put the js code and the referenced js file inside "@section scripts{}".
        • If you have not referenced the _Layout view, you may need to reference the jquery file on the Index view.
      2. About the comma decimal separator:

    Model

        public class AnnualProjectViewModel
        {
            public AnnualProject Project { get; set; }
        }
        public class AnnualProject
        {
            [DisplayFormat(DataFormatString = "{0:N}", ApplyFormatInEditMode = true)]
            public float Budget { get; set; }
        }

    BudgetController

        public class BudgetController : Controller
        {
            public ActionResult Index()
            {
                return View();
            }
            [HttpPost]
            public ActionResult test(AnnualProjectViewModel test)
            {
                if (ModelState.IsValid)
                {
                }
                return View(test);
            }
        }

    Index

    @model DailyMVCDemo.Models.AnnualProjectViewModel
    @using (Html.BeginForm("test", "Budget", FormMethod.Post))
    {
        <div class="form-group">
            @Html.LabelFor(model => model.Project.Budget, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Project.Budget, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Project.Budget, "", new { @class = "text-danger" })
            </div>
        </div>
        <button type="submit">submit</button>
    
    }
    @section scripts{
        <script src="~/Scripts/jquery.validate.min.js"></script>
        <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
        <script type="text/javascript">
            $.validator.methods.number = function (value, element) {
                console.log('validate');
                return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:\.\d{3})+)?(?:,\d+)?$/.test(value);
            }
        </script>
    }

    test

    @model DailyMVCDemo.Models.AnnualProjectViewModel
    @Html.TextBoxFor(model => model.Project.Budget,new { @class = "form-control"  })

    web.config

      <system.web>
        <compilation debug="true" targetFramework="4.7.2" />
        <httpRuntime targetFramework="4.7.2" />
        <globalization uiCulture="de" culture="de-DE" />
      </system.web>

    FloatModelBinder

        public class FloatModelBinder : DefaultModelBinder
        {
            public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
            {
                var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
                return valueProviderResult == null ? base.BindModel(controllerContext, bindingContext) :float.Parse(valueProviderResult.AttemptedValue, new CultureInfo("de-DE"));
            }
        }

    Global.asax

            protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
                FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles); 
                ModelBinders.Binders.Add(typeof(float), new FloatModelBinder());
                ModelBinders.Binders.Add(typeof(float?), new FloatModelBinder());
            }

    Here is the result.

    Best Regards,

    YihuiSun

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, September 8, 2020 4:01 AM
  • User-1326558348 posted

    Thank you very much!!!! After so many hours of research I can now continue. 

    Thank you :) 

    Tuesday, September 8, 2020 9:39 AM