1

I am building an MVC4 app and in my model I have these fields:

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

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

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

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

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

I am trying to set datepickers in a view. Here's what I have done so far:

<div class="float-left">
    <p>Date Created:</p>
    <p>Date of last modification:</p>
    <p>Date Last Displayed:</p>
    <p>Date of promotion's start:</p>
    <p>Date of promotion's end:</p>
</div>
<div class="float-right">
    <p>
        @Html.TextBoxFor(_item => _item.mCardOfTheDay.mDateCreated, new
            {
                @value = Model.mCardOfTheDay.mDateCreated,
                @selectedDate = Model.mCardOfTheDay.mDateCreated,
                @class = "datePick",
                @type = "date",
                @id = "dateCreated"
            })
    </p>
    <p>
        @(Model.mCardOfTheDay.mDateModified != null ? Html.DisplayFor(_item => _item.mCardOfTheDay.mDateModified) : Html.Label(ValueDomain.FIELD_UNAVAILABLE))
    </p>
    <p>@(Model.mCardOfTheDay.mDateLastDisplayed != null ? Html.DisplayFor(_item => _item.mCardOfTheDay.mDateLastDisplayed) : Html.Label(ValueDomain.FIELD_UNAVAILABLE))</p>
    <p>
        @*@Html.EditorFor(_item => _item.mCardOfTheDay.mStartDate, new { @class = "datePick", @type="date" })*@
        @*@Html.TextBoxFor(_item => _item.mCardOfTheDay.mStartDate, new {@id = "dateStart"})*@
      @*  @Html.TextBoxFor(_item => _item.mCardOfTheDay.mStartDate, new
            {
                @value = (DateTime?) Model.mCardOfTheDay.mStartDate,
                @selectedDate = (DateTime?) Model.mCardOfTheDay.mStartDate,
                @class = "datePick",
                @type = "date",
                @id = "dateStart"
            })*@
    </p>
    <p>
        @Html.TextBoxFor(_item => _item.mCardOfTheDay.mEndDate, new
            {
                @value = Model.mCardOfTheDay.mEndDate,
                @selectedDate = Model.mCardOfTheDay.mEndDate,
                @class = "datePick",
                @type = "date",
                @id = "dateEnd"
            })
    </p>
</div>
<div class="clear"></div>

And CSS to show what I'm doing with the classes:

$('.datePick').datepicker({
    dateFormat: "dd/ww/yy",
});

$('.datePick').each(function () {
    var a = $(this).datepicker({
        dateFormat: "dd/ww/yy",
        defaultDate: new Date($(this).val())
    });
});

This shows the various problems I have. First:

  1. Using Html.TexborFor helpers with @value, @selectedDate and so on does displays a datepicker, but this datepicker's default shown value is aaaa-mm-dd instead of the value binded to the model and when I pass the model to the controller none of the data is kept (meaning that the mEndDate is always null);
  2. Trying only to set a datepicker ends up with the same results;
  3. Here's a sample of Html code behind to show you the "results" I have: <input class="input-validation-error datePick" data-val="true" data-val-date="The field mDateCreated must be a date." data-val-required="The mDateCreated field is required." id="dateCreated" name="mCardOfTheDay.mDateCreated" selectedDate="11/21/2013 00:00:00" type="date" value="" />
  4. And if I use the EditorFor, all I have is a date in string format, no datepicker.

What I want is a datepicker with the proper date selected that passed the selected date to the controller method in post. Can anyone help me figure out why this does not work?

hsim
  • 2,000
  • 6
  • 33
  • 69

2 Answers2

4

You shouldn't be overriding the value of the date input with the same date in a different format, there is no reason to and it will only cause headaches. From my experience you're better off leaving it as is.

@Html.TextBoxFor(_item => _item.mCardOfTheDay.mDateCreated, new
{
    @selectedDate = Model.mCardOfTheDay.mDateCreated,
    @class = "datePick",
    @type = "date",
    @id = "dateCreated"
})

What you need to do however is configure the datepicker properly so that it knows how to interpret the date coming from your database. If you want to show a different format to the user than the one posted back to the server, you can make use of the altField (source) and altFormat (source) option.

That will allow you to use dateFormat to display the date in whichever format you like in the input to the user, while keeping the posted value in the right format.

You won't need this anymore :

$('.datePick').each(function () {
    var a = $(this).datepicker({
        dateFormat: "dd/ww/yy",
        defaultDate: new Date($(this).val())
    });
});

You'll also need to get rid of ApplyFormatInEditMode = true on your model property attributes. Let the framework handle dates based on current culture, don't try working against it by applying formats all over the place.

Just leave the textbox value be whatever your database sends, and use the datapicker's functionality to do what you need on the client side.

The only time I would advise overriding the value is if you're worried about the input showing the time part when you only want the date. In that case, you should do it like so :

@Html.TextBoxFor(_item => _item.mCardOfTheDay.mDateCreated, new
{
    @selectedDate = Model.mCardOfTheDay.mDateCreated,
    @class = "datePick",
    @type = "date",
    @id = "dateCreated",
    @Value = Model.mCardOfTheDay.mDateCreated.ToString("mm/d/yyyy")
})

Notice @Value with a capital v, that is actually important and not a typo. You then pass a date format to the ToString method, but it needs to be the same format as your database.


Edit:

I went ahead and built a small test-case to try and replicate your issue. Here's what I have :

Controller :

public ActionResult Test()
{
    return View(new TestViewModel()
    {
        DateCreated = DateTime.Now.AddDays(10)
    });
}

[HttpPost]
public ActionResult Test(TestViewModel model)
{
    return RedirectToAction("Test");
}

ViewModel :

public class TestViewModel
{
    public DateTime DateCreated { get; set; }
}

View :

@using (Html.BeginForm())
{
    @Html.TextBoxFor(m => m.DateCreated, new {
        @type = "date",
        @Value = Model.DateCreated.ToString("d")
    })
    <input type="submit">
}

// This is the rendered input
<input Value="12/1/2013" data-val="true" data-val-date="The field DateCreated must be a date." id="DateCreated" name="DateCreated" type="date" value="12/1/2013 4:03:19 PM" />

JS:

$('input[type="date"]').datepicker();

This all works as expected; datepicker has the date in the input's value selected by default, value of model.DateCreated is set to a DateTime object on post. Notice I haven't messed with formats anywhere but in the display value where I replaced the full date with the standard short date pattern.

Can you try simplifying your code to match what I have and let me know what happens?

dom
  • 6,702
  • 3
  • 30
  • 35
  • Interesting, really, I've understood a bit more about it. What frustrates me is that I have tried what you suggest, and to no avail. :| – hsim Nov 21 '13 at 20:22
  • @HerveS what does a "raw" date look like in your database and what culture is your application using? – dom Nov 21 '13 at 20:38
  • Culture: en-US, so english, I suppose. And a raw date is a DateTime value. – hsim Nov 21 '13 at 20:44
  • @HerveS See my edit, let me know if that works. I know it's not complete as it's not exactly what you have, but try and get it working first and we'll worry about display formats later. – dom Nov 21 '13 at 21:09
  • Well everything is similar, even the output, it is the binding effect that does not work somehow. – hsim Nov 21 '13 at 21:29
  • Do other fields get binded properly and only the dates end up null? – dom Nov 21 '13 at 21:31
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/41666/discussion-between-herve-s-and-dombenoit) – hsim Nov 21 '13 at 21:32
3

Well, after so many years you would definitely have sorted out this issue but still wanted to answer for all those who are new to this problem:

The datepicker should take the format YYYY-MM-DD as its value. Single digit days and months should be padded with a 0. January is 01. You can simply modify your date format as

 @Value = Model.DateCreated.ToString("yyyy-MM-dd") 
Adeel Asghar
  • 217
  • 2
  • 5