I have a view, whose Model is a ViewModel, which is used to display some data. For each line displayed this way, the user can choose a value from a DropDownList, then click a button to save their choice into the database. More than one "choice" can be processed this way per button click.
In order to do so, I use an Html.BeginForm method, like so (named altered):
@using (Html.BeginForm("DatabaseSave", "Save", new { attr = Model.attributedList }, FormMethod.Post))
And my method in the controller is:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult DatabaseSave(AttributionViewModel attr)
{
// Data processing.
}
But when I use this, attr is null. I can still get my data by using Request.Form and the correct index, but that is not the solution I'd rather use. I have a model that is ready to do this and used a ViewModel specifically so I didn't have to ask Request.Form. But I just can't see what I'm missing. Can anybody help me?
In order for an answer to be found quickly, you will find the pseudocode of all relevant classes and views below.
Class that contains the data:
public class Attribution
{
public Attribution()
{
listToAttribute = new List<SelectListItem>();
}
public string Title { get; set; }
public int ID { get; set; }
public string Description { get; set; }
public int? Number { get; set; }
public IEnumerable<SelectListItem> listToAttribute { get; set; }
public int AttributedNumber { get; set; } // Mostly used internally to properly send dropdownlist data.
// Other methods that are not relevant.
}
The ViewModel used in the View:
public class AttributionViewModel : Attribution
{
public AttributionViewModel()
{
}
public IPagedList<Attribution> attributedList { get; set; }
}
The relevant parts of the view:
@model Project.ViewModels.AttributionViewModel
@using PagedList.Mvc
@using PagedList
// Some code later...
@using (Html.BeginForm("DatabaseSave ", "Save", new { attr = Model.attributedList }, FormMethod.Post))
{
@Html.ValidationSummary(false, "", new { @class = "text-danger" })
@Html.AntiForgeryToken()
<table class="contentTable contentTable-evo fixedTableHeader">
<thead>
// Headers are not relevant.
</thead>
<tbody id="processingTable">
@{
int i = 0;
}
@foreach (var item in Model.attributedList)
{
<tr>
<text>@Html.EditorFor(modelItem => Model.attributedList[i].ID, new { htmlAttributes = new { @class = "form-control", @hidden = "hidden", @style = "width:0px display:none", @type = "hidden" } })</text>
<td class="noWrap width1percent tri">@item.Title</td>
<td class="noWrap width1percent tri">@item.ID</td>
<td class="noWrap width1percent tri">@item.Description</td>
<td class="noWrap width1percent tri">@item.Number</td>
<td class="noWrap width1percent tri">
<text>@Html.DropDownListFor(modelItem => Model.attributedList[i].AttributedNumber, Model.attributedList[i].listToAttribute , "" , new { htmlAttributes = new { @class = "form-control", @style = "width:90px" } })</text>
</td>
</tr>
i++;
}
</tbody>
</table>
<br />
<center>
<input value="Processing" class="add" type="submit" onclick="javascript:return ShowConfirm();" >
</center>
Page @(Model.attributedList.PageCount < Model.attributedList.PageNumber ? 0 : Model.attributedList.PageNumber) out of @Model.attributedList.PageCount | @Model.attributedList.TotalItemCount <br />
<text>@Resources.Views.PaginationResource.GoToPage </text>@Html.DropDownList("PageChanger", new SelectList(Enumerable.Range(1, Model.attributedArticles.PageCount), "", ""), new { onchange = "PageChangedFromDropDown()" })
@Html.PagedListPager(Model.attributedList, page => Url.Action("Attribute", new { page, searchString = Session["Search"], currentFilter = ViewBag.CurrentFilter, sortColumn = ViewBag.sortAttr }), new PagedListRenderOptions { LiElementClasses = new[] { "needsLoading" }, DisplayEllipsesWhenNotShowingAllPageNumbers = false })