简体   繁体   中英

DropDown List from a loop in a razor view

I am trying to use a drop-down list within a for loop in a razor view. The drop-down list display correctly on the initial page load, however the model binding is not working on the post. The items selected in the drop-down list are not available on the post. The tableColumns property is empty. Any help would be much appreciated.

Model

  public class DataMappingViewModel
        {          

public string TableName { get; set; }
        public List<XmlElement> XmlElements { get; set; }

    }
    public class XmlElement
    {
        public string ElementName { get; set; }
        public List<SP_GET_DBASE_COLUMNS_Result> tableColumns { get; set; }
    }

      public partial class SP_GET_DBASE_COLUMNS_Result
    {
        public string TABLE_CATALOG { get; set; }
        public string TABLE_SCHEMA { get; set; }
        public string TABLE_NAME { get; set; }
        public string COLUMN_NAME { get; set; }
        public Nullable<int> ORDINAL_POSITION { get; set; }
        public string COLUMN_DEFAULT { get; set; }
        public string IS_NULLABLE { get; set; }
        public string DATA_TYPE { get; set; }
        public Nullable<int> CHARACTER_MAXIMUM_LENGTH { get; set; }
        public Nullable<int> CHARACTER_OCTET_LENGTH { get; set; }
        public Nullable<byte> NUMERIC_PRECISION { get; set; }
        public Nullable<short> NUMERIC_PRECISION_RADIX { get; set; }
        public Nullable<int> NUMERIC_SCALE { get; set; }
        public Nullable<short> DATETIME_PRECISION { get; set; }
        public string CHARACTER_SET_CATALOG { get; set; }
        public string CHARACTER_SET_SCHEMA { get; set; }
        public string CHARACTER_SET_NAME { get; set; }
        public string COLLATION_CATALOG { get; set; }
        public string COLLATION_SCHEMA { get; set; }
        public string COLLATION_NAME { get; set; }
        public string DOMAIN_CATALOG { get; set; }
        public string DOMAIN_SCHEMA { get; set; }
        public string DOMAIN_NAME { get; set; }
    }

Controller

public ActionResult Index()
        {

            List<XmlElement> elements = new List<XmlElement>();

            XmlElement element1 = new XmlElement();
            element1.ElementName = "element1";
            element1.tableColumns = data.GetTableColumns("TABLENAME");

           elements.Add(element1);

            DataMappingViewModel viewitem = new DataMappingViewModel();

            viewitem.XmlElements = elements;
            viewitem.TableName = "TABLENAME";


            return View(viewitem);
        }


        [HttpPost]
        public ActionResult MapData(DataMappingViewModel  model)
        {
            return View("Index",model);
        }

View

@model ExcelImportAPI.Models.DataMappingViewModel
@using System.Web.Mvc;
@{
    ViewBag.Title = "title";
    Layout = "~/Views/Shared/_Layout.cshtml";
}


@using (Html.BeginForm("MapData", "DataMapping", FormMethod.Post))
{

    <h2>Data Mapping</h2>

for (var i = 0; i < Model.XmlElements.Count; i++)
 {

     @Html.HiddenFor(m => Model.XmlElements[i].ElementName)
     @Model.XmlElements[i].ElementName

        <td>
            @Html.DropDownList("tableColumns", new SelectList(@Model.XmlElements[i].tableColumns, "COLUMN_NAME", "COLUMN_NAME"), "--Select a Value--")


        </td>
    }

    <div class="modal-footer">
        <input type="submit" name="btnSaveAndExit" value="Save and Exit" class="btn btn-default">
        <input type="submit" name="btnSaveAndContinue" value="Save and Continue" class="btn btn-primary modal-btn">
    </div>

}

You should render tableColumns in a collection of hidden elements, the dropdown value should be bound to a property SelectedColumn of DataMappingViewModel :

        @Html.DropDownList("SelectedColumn", new SelectList(Model.XmlElements[i].tableColumns, "COLUMN_NAME", "COLUMN_NAME"), "--Select a Value--")
        @for(var j = 0; j < Model.XmlElements[i].tableColumns.Count; j ++)
        {
            @Html.Hidden(string.Format("XmlElements[{0}].tableColumns[{1}].COLUMN_NAME", i, j), Model.XmlElements[i].tableColumns[j].COLUMN_NAME)
        }

tableColumns is a complex object and you cannot bind a <select> element to a complex object (it only posts back a simple value - the value of the selected option which in your case is the value of the COLUMN_NAME property).

Your view model needs a property to bind to, and ideally a simplified collection property to bind to

public class DataMappingViewModel
{          
    public string TableName { get; set; }
    public List<XmlElementViewModel> XmlElements { get; set; }
    public IEnumerable<string> ColumnList { get; set; } // for generating the SelectLists
}
public class XmlElementViewModel
{
    public string ElementName { get; set; }
    public string SelectedColumn { get; set; } // to bind the selected value to
}

and you GET method will then be

public ActionResult Index()
{
    DataMappingViewModel model= new DataMappingViewModel()
    {
        TableName = "TABLENAME",
        ColumnList = data.GetTableColumns("TABLENAME").Select(x => x.COLUMN_NAME),
        XmlElements = new List<XmlElement>()
        {
            new XmlElement()
            {
                ElementName = "element1",
                SelectedColumn = "...." // if you want to preselect an option
            }
        }
    }
    return View(model);
}

Then in the view

model ExcelImportAPI.Models.DataMappingViewModel
....
@using (Html.BeginForm("MapData", "DataMapping", FormMethod.Post))
{
    ....
    for (var i = 0; i < Model.XmlElements.Count; i++)
    {
        @Html.HiddenFor(m => Model.XmlElements[i].ElementName)
        @Model.XmlElements[i].ElementName
        <div>
            @Html.DropDownListFor(m => m.XmlElements[i].SelectedColumn, new SelectList(Model.ColumnList), "--Select a Value--")
        </div>
    }
    ....
}

Side notes:

  • Your view shows <td> elements but no enclosing <tr> and <table> elements, but it does not seem you need a table here anyway.
  • You do not need @using System.Web.Mvc; in the view
  • Normally your SelectList should be generated in the controller, but since you using creating a dropdownlist in a loop, you need to generate a new SelectList in each iteration, or use an EditorTemplate and pass the SelectList using additionalViewData as described in this answer
  • The 3rd parameter of DropDownListFor() is generating a null option. I assume that you will want users to select a value, so you should add a [Required] attribute to SelectedColumn and include @Html.ValidationMessageFor(m => m.XmlElements[i].SelectedColumn) in the view.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM