Sam
Sam

Reputation: 4484

Unable to bind selectlistitem to model property

I have a couple of classes like below -

public class P
{
    public int Id { get; set; }
    public virtual ICollection<PDetail> PDetails { get; set; }
}

public class PDetail
{
    public int Id { get; set; }
    public int Type { get; set; }
    public double Price { get; set; }
}

Now, in my View, I am displaying it as -

@foreach (var detail in Model.PDetails)
{
    <div class="row">
        <div class="col-sm-6">
           @Html.DropDownListFor(m => detail.Type, (IEnumerable<SelectListItem>)ViewData["Types"], "--Type--", htmlAttributes: new { @class = "form-control" })
        </div>
        <div class="col-sm-6">
            @Html.TextBoxFor(m => detail.Price, "", htmlAttributes: new { @class = "form-control", placeholder = "Price" })
        </div>
    </div>
}

Here, I am able to display detail.Price for each detail object, but detail.Type is not getting selected from ViewData["Types"] dropdownlist.

PS: ViewData["Types"] is just a dictionary of typeIds = {1,2,3...}

Info1

I also tried changing the View to -

@for (int i = 0; i < Model.PDetails.Count(); i++)
{
    <div class="row">
        <div class="col-sm-6">
           @Html.DropDownListFor(m => m.PDetails.ElementAt(i).Type, (IEnumerable<SelectListItem>)ViewData["Types"], "--Type--", htmlAttributes: new { @class = "form-control" })
        </div>
    </div>
}

But it is still not working. How can I go about fixing it?

Upvotes: 0

Views: 127

Answers (1)

JLRishe
JLRishe

Reputation: 101728

Thanks for sticking through my barrage of questions. I was able to reproduce your issue, and after a whole lot of attempts to get it to work, it seems that this may just be a bug in the MVC framework that hasn't been fixed in over 4 years.

This answer provides two workarounds: https://stackoverflow.com/a/3529347/1945651

One involves using a somewhat verbose bit of code to manually add the value to the ModelState.

The other requires your list of items to be indexable with square brackets (e.g. an array or IList/IList<T>), and then involves adding the current value as a default value in the SelectList passed to the HTML helper:

@for (int i = 0; i < Model.PDetails.Count(); i++)
{
    <div class="row">
        <div class="col-sm-6">
           @Html.DropDownListFor(m => m.PDetails[i].Type, 
                                 new SelectList(ViewData["Types"] as IEnumerable, 
                                            "Value", "Text", Model.PDetails[i].Text), 
                                 "--Type--", 
                                 htmlAttributes: new { @class = "form-control" })
        </div>
    </div>
}

Could you give that a try?

Upvotes: 1

Related Questions