ASP.NET MVC SelectList items with Model Binder

I have a controller which accepts a complex object parameter, which itself has a complex type collection property. The model-binding doesn't work for my damages property after the form is posted (it's always null). How do I build the drop downs for my damages property so the model will be populated with the selected values when the html form is posted to the controller?

Note-I am new to ASP.NET MVC and this is pre-written code I have been asked to debug.

View Model 1:

public class EditInspectionViewModel
    {
        public long? InsRefreshSeq { get; set; }
        public string Inspector { get; set; }
        public string VIN { get; set; }
        public string Manufacturer { get; set; }
        public string Plant { get; set; }
        public string Model { get; set; }
        public IEnumerable<DamageViewModel> Damages { get; set; }

        public IEnumerable<GETAREAResult> AreaFilterOptions { get; set; }
        public IEnumerable<GETDMGTYPEResult> DamageTypeFilterOptions { get; set; }
        public IEnumerable<GETSEVERITYResult> SeverityFilterOptions { get; set; }
        public IEnumerable<GETGRIDResult> GridFilterOptions { get; set; }     
    }

View Model 2:

 public class DamageViewModel
{
    public long DamageId { get; set; }
    public string Area { get; set; }
    public string AreaCode { get; set; }
    public string TypeCode { get; set; }
    public string SeverityCode { get; set; }
    public string GridCode { get; set; }
    public string Type { get; set; }
    public string Severity { get; set; }
    public string Grid { get; set; }
    public bool HasError { get; set; }
    public bool HasAreaError { get; set; }
    public bool HasDamageTypeError { get; set; }
    public bool HasSeverityError { get; set; }
    public bool HasImages { get; set; }        
}

Controller Edit Methods:

[HttpGet]
    public virtual ActionResult Edit(long id)
    {

            EditInspectionViewModel viewModel = _getInspectionForEditingQuery.Execute(CurrentUserId, id);
            viewModel.InsRefreshSeq = 0;
            viewModel.AreaFilterOptions = _refService.GetAreas().OrderBy(x => x.ARECODE);
            viewModel.DamageTypeFilterOptions = _refService.GetDamageTypes().OrderBy(x => x.DTPCODE);
            viewModel.SeverityFilterOptions = _refService.GetSeverities().OrderBy(x => x.SEVCODE);
            viewModel.GridFilterOptions = _refService.GetQuadrants().OrderBy(x => x.QUDCODE);

         return View(viewModel);
     }


[HttpPost]
    public virtual ActionResult Edit( long id, EditInspectionViewModel editedInspection)
    {
        if (ModelState.IsValid)
        {
            _updateErrorInspectionCommand.Execute(editedInspection);

            return View(editedInspection);
        }

        return View(editedInspection);
    }

Here is a partial razor view that displays inspection damages (both this view and the outer view are typed to the EditInspectionViewModel):

        @model AIM.NewCars.Model.Inspections.EditInspectionViewModel

    @{

    }

<div class="panel panel-info">
    <div class="panel-heading clearfix">


    </div>
    <table class="table table-condensed">
        <thead>
            <tr>
                <th>Area</th>
                <th>Type</th>
                <th>Severity</th>
                <th>Grid</th>
                <th>Images</th>
                <th>Remove</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var damage in Model.Damages)
            {
                if (damage.HasError)
                {
                    IEnumerable<SelectListItem> areas = Model.AreaFilterOptions.Select(x => new SelectListItem() { Value = x.ARECODE, Text = x.ARECODE + "-" + x.AREDESC, Selected = damage.AreaCode == x.ARECODE });
                    IEnumerable<SelectListItem> damageTypes = Model.DamageTypeFilterOptions.Select(x => new SelectListItem() { Value = x.DTPCODE, Text = x.DTPCODE + "-" + x.DTPDESC, Selected = damage.TypeCode == x.DTPCODE });
                    IEnumerable<SelectListItem> severities = Model.SeverityFilterOptions.Select(x => new SelectListItem() { Value = x.SEVCODE, Text = x.SEVCODE + "-" + x.SEVDESC, Selected = damage.SeverityCode == x.SEVCODE });
                    IEnumerable<SelectListItem> grids = Model.GridFilterOptions.Select(x => new SelectListItem() { Value = x.QUDCODE, Text = x.QUDCODE + "-" + x.QUDDESC, Selected = damage.GridCode == x.QUDCODE });

                    <tr class="damage-container">
                        <td>
                            <input type="hidden" name="@("InspectionDamages[" + Model.Index + "].Index")" value="@Model.Index" />

                            @Html.DropDownList("InspectionDamages[" + damage.DamageId + "].AreaCode", areas, string.Empty, new { @class = "form-control js-damage-field" })
                        </td>
                        <td>

                            @Html.DropDownList("Damages[" + damage.DamageId + "].DamageTypeCode", damageTypes, string.Empty, new { @class = "form-control js-damage-field" })
                        </td>
                        <td>

                            @Html.DropDownList("InspectionDamages[" + damage.DamageId + "].SeverityCode", severities, string.Empty, new { @class = "form-control js-damage-field" })
                        </td>
                        <td>

                            @Html.DropDownList("InspectionDamages[" + damage.DamageId + "].GridCode", grids, string.Empty, new { @class = "form-control js-damage-field" })
                        </td>
                  }
        </tbody>
        </table>
       </div>

After the http get, the drop down menus get populated and selected according to their values just fine, but when I post the form the damages property is null when it reaches the post action method.

Answers


Your model binding doesn't work because your are using your model in wrong way. Use for loop instead of foreach and use DropDownListFor for appropriate DamageViewModel inside of for loop. Then you will get all you need form model binding. Keep in mind that never try mimicking model binding by you own code because it is error prone and hard to make later changes, as always there is a possibility for that.


Need Your Help

How to get console output data into command prompt?

c++ visual-studio-2010 visual-c++ mfc console

I have a Windows based application. I made it to work in for both GUI Mode and Console Mode. In GUI mode or Console mode I am attaching a Console by using AttachConsole() to bring up output print

AngularJS ng-disabled not working with list items

javascript angularjs list disabled-control

I am facing a problem with disabling a item in the list.