6

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());
Ben
  • 5,525
  • 8
  • 42
  • 66
  • I believe your referring to the System.ComponentModel.DataAnnotations rather than the EntityFramework data annotations? If you followed the blog through then do you specify the data format `{dateFormat: "dd/mm/yy"}` in your client side script? If so, what version of the jquery ui script are you using? – Dangerous Apr 13 '12 at 08:55
  • oooh you are quite correct i am using the ComponentModel ones. I got used to using the EF ones on last project. will update. I was using jquery ui 1.8.7 but i have updated to the latest as per your answer below to no avail – Ben Apr 13 '12 at 09:22
  • oh and yes i have specified `{dateFormat:"dd/mm/yyyy"}` – Ben Apr 13 '12 at 09:24
  • To clarify, it is the client side validation (not the server side validation) that is complaining that the date is not in the correct format? _validation is still telling me that i need to enter a valid date format_. The reason I am going down this route is that I had this problem this week from the exact same blog. – Dangerous Apr 13 '12 at 09:25
  • yeah thats right, i should have been more clear. it is the client side validation. The default value is set to todays date (13/4/2012 which is invalid for US) on the create page, and if you don't change it and just click save it will happily add it to the database – Ben Apr 13 '12 at 09:51

6 Answers6

4

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>
Community
  • 1
  • 1
Ben
  • 5,525
  • 8
  • 42
  • 66
  • It really shouldn't be necessary to go to all this trouble just to make UK date validate!! But thanks for the info I was stuck on this one. Just hope jQuery add a more elegant way of doing this soon. That script globalize.js (ironically spelt with a z :) ) file is pretty big. – Paul Johnson Apr 30 '12 at 10:24
  • @PaulJohnson I agree, I shouldn't have to do that, and infact its not a very good solution for alot of cases because it always forces UK format dates. – Ben May 01 '12 at 11:50
  • I've been searching for two days for a resolution to this problem, with the finger eventually pointing to JQuery for the reasons you mention. This fix has worked perfectly for me - although the easiest way to implement it was to use nuget to add the jquery-globalise package - and if you do that, then the script locations become /Scripts/globalize/globalize.js and /Scripts/globalize/culture/globalize.culture.en-GB.js – Alex White Oct 21 '14 at 00:14
1

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

Community
  • 1
  • 1
Iridio
  • 9,213
  • 4
  • 49
  • 71
1

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>
Dangerous
  • 4,818
  • 3
  • 33
  • 48
  • it looks like i am using a slightly older version (1.8.7) so swapped in the new one, and it made no difference. thanks though – Ben Apr 13 '12 at 09:19
1

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();
});
Community
  • 1
  • 1
Paul Johnson
  • 1,417
  • 1
  • 17
  • 26
0

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 (i.e 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

Manatherin
  • 4,169
  • 5
  • 36
  • 52
0

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.

Bruno Casarotti
  • 623
  • 8
  • 23