MVC3 Unobtrusive Date Validation on a custom formatted date
Asked Answered
P

10

9

I have a date field (i'm using the jquery ui datepicker) in a form that I've formatted, like so:

ViewModel

[DisplayFormat(DataFormatString = "{0:dd-MMM-yyyy}", ApplyFormatInEditMode = true)]
public DateTime FooDate { get; set; }

View

@Html.EditorFor(m => m.FooDate)

This correctly shows the date the way I want it to, e.g. 09-Nov-2011

The problem I'm getting, occurs when I press submit. It keeps telling me the date is not valid.... It IS valid, you stupid thing!

Is there any way, i can get jquery/unobtrusive javascript to ignore this field or allow this format to pass? So far, the only way I can get the form to work, is if i don't format the date, or use {0:d} as a date format for it.

Edit: I've created a totally separate layout+view+controller+model for testing this stupid thing. Still doesn't work in IE/Safari. I have the latest jquery.validate/unobtrusive files from nuget.

My layout is empty. It just loads the following files:

"jquery-1.7.min.js"
"jquery-ui-1.8.16.min.js"
"jquery.validate.min.js"
"jquery.validate.unobtrusive.min.js"

My TestViewModel is simple:

public class TestViewModel
{
    [Display(Name = "Test Date:")]
    [DisplayFormat(DataFormatString = "{0:dd/MMM/yyyy}", ApplyFormatInEditMode = true)]
    public DateTime? TestDate { get; set; }
}

My TestController goes as follows:

public class TestController : Controller
{
    public ActionResult Index()
    {
        var m = new TestViewModel();
        m.TestDate = DateTime.Now;
        return View(m);
    }
}

My View:

@using (Html.BeginForm())
{
    ViewContext.FormContext.ValidationSummaryId = "valSumId";
    @Html.ValidationSummary(false, "The following errors were found:");
    @Html.AntiForgeryToken()

    @Html.LabelFor(m => m.TestDate)
    <input type="date" id="TestDate" value="@Model.TestDate.Value.ToString("dd/MMM/yyyy")" />
    <input type="submit" />
}

No worky.

You know what the annoying thing is? If i change TestDate to a string, it still fails.

Pebbly answered 9/11, 2011 at 0:46 Comment(3)
did you set the same date format when you declare the datepicker? $('#date').datepicker({ constrainInput: true, dateFormat: 'D, dd M yy'... something like thisDrone
Yes i did. I load a default date from the view when the page loads, and it still doesn't like itPebbly
For my case, i dint format the date in the model, i do it directly in view using string.format, and validation passed. Perhaps you can have a try :)Drone
P
3

So it looks like jquery.validate.unobtrusive has a problem with input type="date". This must be a bug that only occurs in IE and Safari.

When i removed the unobtrusive js file, it submitted the form fine. When i added the unobtrusive js file back in and changed the input type to text, it worked.

Annoying bug. Needs to be fixed.

Pebbly answered 11/11, 2011 at 2:54 Comment(3)
While I agree with the facts expressed in this answer, I would not want to remove the unobtrusive js.. there is this fix which helps my MSIE and Chrome browsers to be happier, involves adding a 'date' method to the validator objectCrank
This is another tweak to deal with an iOS issue also involves a tweak to the validator's date method If you paste in this snippet after the snippet linked to in my prior comment, this one will effectively combined the prior logic with it's ownCrank
I posted my first comment a little hastily.. while it deals somewhat with your issue, it is also trying to get a jquery UI datepicker to play nice with date fields. The concept there is still applicable.. and to be clear, I guess what we're dealing with is overriding (not 'adding') the 'date' method of the validator object that is set forth in the unobtrusive js file.Crank
R
4

I think there is a problem with hyphen ("-") in your format string:

[DisplayFormat(DataFormatString = "{0:dd-MMM-yyyy}", ApplyFormatInEditMode = true)]

It seems that unobtrusive validation does not accept hyphen for date formatting by default.

In my case I had to add custom client-side method:

$.validator.methods.date = function (value, element) {
    var s = value;
    s = value.replace(/\-/g, '/');

    return this.optional(element) || !/Invalid|NaN/.test(new Date(s));
};

as implemented here

Remains answered 21/11, 2012 at 11:42 Comment(0)
P
3

So it looks like jquery.validate.unobtrusive has a problem with input type="date". This must be a bug that only occurs in IE and Safari.

When i removed the unobtrusive js file, it submitted the form fine. When i added the unobtrusive js file back in and changed the input type to text, it worked.

Annoying bug. Needs to be fixed.

Pebbly answered 11/11, 2011 at 2:54 Comment(3)
While I agree with the facts expressed in this answer, I would not want to remove the unobtrusive js.. there is this fix which helps my MSIE and Chrome browsers to be happier, involves adding a 'date' method to the validator objectCrank
This is another tweak to deal with an iOS issue also involves a tweak to the validator's date method If you paste in this snippet after the snippet linked to in my prior comment, this one will effectively combined the prior logic with it's ownCrank
I posted my first comment a little hastily.. while it deals somewhat with your issue, it is also trying to get a jquery UI datepicker to play nice with date fields. The concept there is still applicable.. and to be clear, I guess what we're dealing with is overriding (not 'adding') the 'date' method of the validator object that is set forth in the unobtrusive js file.Crank
G
2

There are really two things here:

  1. Client side validation
  2. Server side validation

Both should use the same format for this to work. Let's first deal with the server side validation. You could write a custom model binder for the DateTime fields which will use the format specified for displaying when binding them back. Here's an example of such model binder.

Next we must deal with client side validation. For this you could write a custom rule which will be attached to the given elements:

<script type="text/javascript">
    $.validator.addMethod(
        'myDateFormat', function (value, element) {
            // TODO: put your validation logic here that will parse the string
            // and validate it
            return false;
        },
        'Please enter a date in the format dd-MMM-yyyy'
    );

    $(function () {
        // we attach the custom validation rule to the given input element
        $('#FooDate').rules('add', 'myDateFormat');
    });
</script>

You could also use adapters with a custom attribute.

Gabrielson answered 9/11, 2011 at 7:37 Comment(0)
D
1

For my case, I use the text field for the date, so it didnt cause problem for jquery validation:

 <div class="editor-field">
    @Html.TextBox("ExpiryDate", String.Format("{0:ddd, dd MMM yyyy}", DateTime.Now), new { id = "expirydate" })
    @Html.ValidationMessageFor(model => model.ExpiryDate)
</div>

So why not you try format your date like this instead of using the input type=date?

Hope this help :)

Drone answered 11/11, 2011 at 4:3 Comment(0)
C
1

Actually it is not bug in browser, client validation issues can occur because of MVC bug (even in MVC 5) in jquery.validate.unobtrusive.min.js which does not accept date/datetime format in any way. Unfortunately you have to solve it manually.

My finally working solution:

You have to include before:

@Scripts.Render("~/Scripts/jquery-3.1.1.js")
@Scripts.Render("~/Scripts/jquery.validate.min.js")
@Scripts.Render("~/Scripts/jquery.validate.unobtrusive.min.js")
@Scripts.Render("~/Scripts/moment.js")

You can install moment.js using:

Install-Package Moment.js

And then you can finally add fix for date format parser:

$(function () {
    $.validator.methods.date = function (value, element) {
        return this.optional(element) || moment(value, "DD.MM.YYYY", true).isValid();
    }
});
Chambliss answered 8/3, 2017 at 16:2 Comment(0)
C
1

As lukyer posted, there can be issues relating to the jquery.validate*.min.js files, especially if you have added your own validation in to those files. The simple answer I found that worked for me when the final release system failed to validate dates in IE (Chrome worked without issue) was to simply remove the pre-packaged minified validation files altogether and let the beast handle it's own minification from the "master" files. Only shame was that I didn't connect lukyer's reply to the solution earlier...

(I'd probably post this as a comment but apparently I've not yet gained quite enough rep: must try harder!)

Concertmaster answered 9/6, 2017 at 17:12 Comment(0)
U
0

Have you tried simply changing the type to:

@Html.TextBoxFor(model => model.startDate, new { @class = "date" })

I was having the same issue with EditorFor... so I changed it to this and then applied my jquery datepicker to the 'date' class added to the textbox.

Unshroud answered 11/11, 2011 at 1:41 Comment(0)
T
0

Just wanted to make a little comment on this line if someone else has trouble with this later:

<input type="date" id="TestDate" value="@Model.TestDate.Value.ToString("dd/MMM/yyyy")" />

In some cases (at least my case earlier) this would translate into this format: "01.01.2012", because with some cultures you can't specify slashes like that to actually get it formatted like that, it will just turn them into dots, so I had to write:

@Model.TestDate.Value.ToString("dd\/MMM\/yyyy");

Which gave me "01/01/2012".

Tenebrous answered 30/7, 2012 at 14:16 Comment(0)
S
0

Quite old this thread. Just landed here having similar issues. In another thread I read that there could be an issue with Version incompatibility by all these *.js libraries involfed somehow in the Validation. Perhaps the following link can help other Readers landig here: https://stackoverflow.com/a/16551039

Hope this helps

Soni answered 16/1, 2014 at 11:45 Comment(0)
D
-1

I was having the same issue, it was driving me bananas! Basically, mvc validation will always render DateTime objects to require a value on the textbox. Why? Because it is directly associated with a DateTime object. If you declare your ViewModel with a ? symbol, you will make it nullable. This way it won't bother you requiring validation:

public class MyViewModel
{
    DateTime? StartDate { get; set; }
}

Hope this helps

Dannie answered 24/3, 2012 at 5:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.