简体   繁体   中英

MVC3 Validation with ComponentModel.DataAnnotations for UK date format (also using jquery ui datepicker)

I see there are some similar questions to this, but none solve my issue.

I am working on an MVC3 app with Entity Framework 4.3. I have a UK date field that i plan to allow the user to edit using the Jquery UI datepicker (which i got working thanks to this blog ).

Fortunately for me this blog includes instructions on making the datepicker using UK format, however, the EF validation is still telling me that i need to enter a valid date format. Wierdly it doesn't prevent me from submitting the date to the DB its just the unobtrusive validation kicking in and displaying the message.

At the moment I have the following data annotation:

[DataType(DataType.Date)]
public System.DateTime Module_Date { get; set; }

but i have also tried adding:

[DisplayFormat(DataFormatString="{0:dd/MM/yyyy}")]

which had no effect at all. I hope some one has a solution because i don't fancy turning off the unobtrusive validation to stop this error message.

Thanks

EDIT

following @Iridio answer, i looked into adding a Model Binding, and indeed from the few posts like this one that i read it seemed to be the right thing to do, but what i have come up with has no effect. here is what i have tried:

public class DateTimeBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        var date = value.ConvertTo(typeof(DateTime), CultureInfo.CurrentCulture);

        return date;
    }
}

with this in the Application_Start() method of the Global.asax.cs file:

ModelBinders.Binders.Add(typeof(DateTime), new DateTimeBinder());
ModelBinders.Binders.Add(typeof(DateTime?), new DateTimeBinder());

Right, the problem was with the jquery validate scripts insisting on using the US datefomat. I will restrain my self from going on a proper rant about the fact that the majority of the world uses dd/mm/yyyy though.

Anyway, eventually i found the answer to my woes in a comment to an answer of a similar question , the author of which kindly wrote a blog post about how he solved the issue.

Basically I have used the jquery globalize script and just set the culture to en-GB . I should mention that in his blog he doesn't mention where to put the bit where you specify the culture, so i just shoved in in script tags in the page under the references to the globalization scripts:

<script src="@Url.Content("~/Scripts/globalize.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/globalize.culture.en-GB.js")" type="text/javascript"></script>
<script type="text/javascript">
    Globalize.culture("en-GB");
    $.validator.methods.date = function (value, element) {
        return this.optional(element) || Globalize.parseDate(value);
    };
</script>

You have to write you own ModelBinder for the DateTime type.

This is a binder that I wrote for a similar problme but with Decimal type (maybe you will need it). you should grasp the idea and adapt it to your need

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
    {
      actualValue = Convert.ToDecimal(valueResult.AttemptedValue, CultureInfo.CurrentCulture);
    }
    catch (FormatException e)
    {
      modelState.Errors.Add(e);
    }

    bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
    return actualValue;
  }
}

Then in global.asax you register your binder and you're done

protected void Application_Start()
{
  AreaRegistration.RegisterAllAreas();
  RegisterGlobalFilters(GlobalFilters.Filters);
  RegisterRoutes(RouteTable.Routes);
  //Here you tell how to hendle the specific type 
  ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
}

UPDATE

After your clarification this answer should help

I believe there is a bug in the script version of the jquery ui datepicker that ships with the mvc3 framework (jquery-ui-1.8.11.js).

If you specify the date in the uk format (as indeed the blog states):

$(document).ready(function () {
    $('.date').datepicker({dateFormat: "dd/mm/yy"});
});

then jquery-ui-1.8.11.js seems to have an issue with validating the date and keeps asking for a valid uk date (but the validation appears random). If you change the date format to "mm/dd/yy" then this issue will go away but thats no good for uk dates.

The issue has been resolved in a later version of that library so download the latest version (I believe 1.8.18 at time of writing) or reference the cdn:

<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js" type="text/javascript"></script>

Actually I have found a better solution here.... by #fretje

Override jquery date

I have modified his/her code slightly though so that it can still take date formats like 30 May 2012 below.

$(function () {
    $.validator.addMethod(
        "date",
        function (value, element) {

            //Added to validate dates like 31 May 2012
            if (value.split('/').length === 1) 
                return this.optional(element) || !/Invalid|NaN/.test(new Date(value));

            var bits = value.match(/([0-9]+)/gi), str;
            if (!bits)
                return this.optional(element) || false;
            str = bits[1] + '/' + bits[0] + '/' + bits[2];
            return this.optional(element) || !/Invalid|NaN/.test(new Date(str));
        },
        "Please enter a date in the format dd/mm/yyyy"
    );

    $global.init();
});

I've had this problem just now, took me hours to track down the reason. I'm not saying this is your issue but after having spent hours switching globalisations on everything, etc. i thought I'd post the issue on here for any people struggling like me.

Anyway, the problem in my project was actually not what i thought it was. I had decorated the property with [DataAnnotationsExtentions.Date] which, it turns out, mucks up the client side validation in chrome when it comes to the localisation (ie if you want a day after the 12th in England) although it seems to work fine in other browsers. As soon as I removed that it worked

The problem is that by some reason if you put a class called "date" in your textbox, Chrome just get crazy as discribed here at this blog . I had the same problem and I just changed the class name to customDate and it was solved.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM