0

Ok All Weird one here ....

I have a view with a dropdown list containing 4 days prior and todays date...

When Index(Action) is lauched with a null for DateTime the DropDownList appears with the current date already selected... Great!

HTML SOURCE URL \Controller\Index

    <select class="form-control" id="Date" name="Date" onchange="Change_Date(this)"
    <option value="23/10/2017">23/10/2017</option>
    <option value="24/10/2017">24/10/2017</option>
    <option value="25/10/2017">25/10/2017</option>
    <option value="26/10/2017">26/10/2017</option>
    <option selected="selected" value="27/10/2017">27/10/2017</option>
    </select>

When Index(Action) is launched with a DateTime, even though it goes through the exact same process and I can physically see the Selected=True property in the ViewBag.DateList... the dropdown has no selected option and reverts to the first.

HTML SOURCE URL \Controller\Index?date=2017-10-26

    <select class="form-control" id="Date" name="Date" onchange="Change_Date(this)"
    <option value="23/10/2017">23/10/2017</option>
    <option value="24/10/2017">24/10/2017</option>
    <option value="25/10/2017">25/10/2017</option>
    <option value="26/10/2017">26/10/2017</option>
    <option value="27/10/2017">27/10/2017</option>
    </select>

I have tried bypassing the JS and putting the datetime directly in the URL but no luck so its not that...

I cannot understand why having ?date=date in the URL removes the selected property from the options elements...

Just to be Clear in both instances the Selected = True Property is present within the ViewBag.DateList, but it doesn't render as expected when a parameter is passed into the action.

View

@Html.DropDownList("Date", (IEnumerable<SelectListItem>)ViewBag.DateList, 
    new { @class = "form-control", @onchange="Change_Date(this)" })

Method

  public ActionResult Index(DateTime? date)
    {
        if (date.HasValue == false)
        {
            date = DateTime.Now.Date;
        }
        List<SelectListItem> Dates = new List<SelectListItem>();
        for (int i = -4; i < 1; i++)
        {
            string date_display = DateTime.Now.Date.AddDays(i).ToShortDateString();
            Dates.Add(new SelectListItem { Text = date_display, Value =date_display});
        }

        foreach (SelectListItem item in Dates)
        {
            if (item.Value == date.ToShortDateString())
                item.Selected = true;
        }
        ViewBag.DateList = Dates;
     }

JS

function Change_Date(val)
{
    var value = $('#Date').val();
    value = value.split("/").reverse().join("-");
    var url = "/Controller/Index?date=" + value;
    window.location.href = url;
}
L Riley
  • 337
  • 4
  • 15

1 Answers1

1

?date=date in your url adds a value for date to ModelState because you have a parameter named date in your method. The HtmlHelper methods that generate form controls use the value from ModelState for binding if it exists (then from ViewData and finally from the actual model property). Refer the 2nd part of this answer for an explanation of the behavior.

Internally the DropDownList() (and DropDownListFor()) method builds a new IEnumerable<SelectListItem> and sets the value of the Selected property based on the property your binding to (in your case Date) if its not null.

When you redirect using ../Controller/Index?date=2017-10-26, the value of the date parameter (and the ModelState value) becomes 26/10/2017 12:00:00 AM. When the DropDownList() method builds its IEnumerable<SelectListItem> by looping through ViewBag.DateList, it compares the .ToString() property of your SelectListItem values with the value of date in ModelState and does not find any match (the string "26/10/2017 12:00:00 AM" is not equal to "26/10/2017") so no options are set as selected.

Some options to have the correct option selected include

  1. Adding ModelState.Clear() in the controller method before you return the view.
  2. Changing either the name of the parameter in the method, or the name in the dropdownlist so they do not match, for example @Html.DropDownList("SelectedDate", ...)
  • Very Nice... Thanks for the very clear explanation on top of the answer. I didn't know ModelState took from the URL's – L Riley Oct 30 '17 at 09:11