0

I have a ViewModel with an enumerable property that will be set with multiple dropdown controls on a page.

My ViewModel has a collection AvailableItems for the possible options, SelectedItems for the return values, and PreSelectedItems for the default values.

public class ViewModel
{
    public ViewModel()
    {
        AvailableItems = new[]
        {
                new KeyValuePair<string, string>("", "unselected"),
                new KeyValuePair<string, string>("key1", "value1"),
                new KeyValuePair<string, string>("key2", "value2"),
                new KeyValuePair<string, string>("key3", "value3"),
                new KeyValuePair<string, string>("key4", "value4"),
            };
    }
    public IEnumerable<KeyValuePair<string, string>> AvailableItems { get; set; }
    public string[] SelectedItems { get; set; }
    public string[] PreSelectedItems { get; set; }
}

The Controller has two actions, one is a GET and the other a POST. They set two different sets of PreSelectedItems.

    public ActionResult Index()
    {
        var viewModel = new ViewModel
        {
            PreSelectedItems = new[] { null, "key4", null }
        };

        return View(viewModel);
    }

    [HttpPost]
    public ActionResult Index(ViewModel viewModel)
    {
        var oldViewModel = new ViewModel
        {
            PreSelectedItems = new[] { "key3", null, null },
            SelectedItems = new[] { null, null, "key1" }
        };

        return View(oldViewModel);
    }

Finally, the View displays the dropdownlists (the number of which will vary based on other parameters).

for (var i = 0; i < 3; i++)
{
    <p>
        @Html.DropDownListFor(model => model.SelectedItems,
            new SelectList(
                Model.AvailableItems,
                "Key",
                "Value",
                Model.PreSelectedItems[i]))
    </p>
}

The GET action works absolutely fine, with the middle dropdown showing 'value4'.

The POST action's viewModel parameter is populated correctly, but the resulting View displays the dropdowns with no preset/default values. It doesn't matter if the original ViewModel or a newly created one are returned (as long as PreSelectedItems is populated), no default values are set.

I have no idea why it works on a GET but not a POST for an identical ViewModel.

pete the pagan-gerbil
  • 3,136
  • 2
  • 28
  • 49
  • you mean when you send data to HttpPost and return model old selected items are not changed? – Usman Mar 14 '17 at 17:21
  • That's right, even with the correct properties set on the ViewModel (and confirmed when debugging) the View doesn't set the default values on Post the same as it does on a Get – pete the pagan-gerbil Mar 14 '17 at 18:36
  • Despite what you may think, your GET is not really binding correctly either (because a ` –  Mar 15 '17 at 01:04
  • And for a bit more info on binding dropwdownlists in a loop, refer [this answer](http://stackoverflow.com/questions/37407811/mvc5-razor-html-dropdownlistfor-set-selected-when-value-is-in-array/37411482#37411482) –  Mar 15 '17 at 01:05
  • I know the GET is not binding to display from that property, but when posted, SelectedItems contains an array of each of the different dropdown lists selections. (the original ViewModel code should be `string[] SelectedItems`, not `IEnumerable`). – pete the pagan-gerbil Mar 15 '17 at 07:45
  • `string[]` is `IEnumerable`! But its clear your not getting this at all. –  Mar 15 '17 at 12:18
  • No, I'm not, sorry about that. This code, and this answer, do what I need it to do. Not sure I've explained myself properly though. – pete the pagan-gerbil Mar 15 '17 at 12:35
  • Writing a bad hack in the POST method to solve bad code in the GET method is not the way to write code :) –  Mar 15 '17 at 22:36
  • Could you post an answer showing a better way to do this then please? – pete the pagan-gerbil Mar 16 '17 at 08:18

1 Answers1

1

when ever you change the Model or any value in Model after a request you have to clear ModelState because when you return to the view it checks ModelSate before Model so you should do something like this

  [HttpPost]
  public ActionResult Index(ViewModel viewModel)
    {
            var oldViewModel = new ViewModel
            {
                PreSelectedItems = new[] { "key3", null, null }
            }

            ModelState.Clear();  
            return View(oldViewModel);
     }
Usman
  • 4,615
  • 2
  • 17
  • 33