问题
Ok, I hope someone out there can help me out on this one (Thanks in advance!). I'm using MVC4.
My ContractsModel contains (among other things) a list of ContractModel(s). In my partial view, I loop though the list creating a form for each. So far so good. The issue is on postback. The 1st form always posts back fine. But the others (2, 3, 4, etc) always return null.
I've checked with debugging tools and confirmed that the rendered controls are appropriately named.
<select name="Contracts[0].OrganizationId" id="Contracts_0__OrganizationId">
<select name="Contracts[1].OrganizationId" id="Contracts_1__OrganizationId">
<select name="Contracts[2].OrganizationId" id="Contracts_2__OrganizationId">
I've also confirmed that client is indeed returning data to the server, but for some reason it does not seem to be getting attached back into the model that my ActionResult is expecting. Any ideas?
I've minimized my code for brevity.
Here are my models:
public class ContractsModel
{
public ContractsModel()
{
this.Contracts = new List<ContractModel>();
this.OrganizationList = new List<SelectListItem>();
this.ContractNumList = new List<SelectListItem>();
}
public string ParentProjectId { get; set; }
// etc, etc .....
public List<ContractModel> Contracts { get; set; }
public List<SelectListItem> OrganizationList { get; set; }
public List<SelectListItem> ContractNumList { get; set; }
}
public class ContractModel
{
public string OrganizationId { get; set; }
public string Organization { get; set; }
public string ContractNumId { get; set; }
public string ContractNum { get; set; }
}
Here is my Controller Action
[HttpPost]
public ActionResult _ContractsEdit(ContractsModel model)
{
if (ModelState.IsValid) {
//blah, blah, blah....
}
return PartialView("Index", ProjectModel);
}
Here is my Partial View
@model Manager.Models.ContractsModel
@for (int i = 0; i < Model.Contracts.Count(); i++)
{
var divId = "divContractsModelItem_" + (i + 1);
var saveButtonId = "btnContractsEditSave_" + (i + 1);
<div id = "@divId">
@using (Html.BeginForm("_ContractsEdit", "Projects", FormMethod.Post))
{
<fieldset>
<legend>General:</legend>
<div>
<label>Contracting Organization:</label>
@Html.DropDownListFor(model => model.Contracts[i].OrganizationId, new SelectList(Model.OrganizationList, "value", "text", Model.Contracts[i].OrganizationId))
</div>
<div>
<label>Contract Number:</label>
@Html.DropDownListFor(model => model.Contracts[i].ContractNumId, new SelectList(Model.ContractNumList, "value", "text", Model.Contracts[i].ContractNumId))
</div>
<div>
<button id="@saveButtonId" type="submit">Save</button>
</div>
</fieldset>
}
</div>
}
回答1:
Since my comments helped you, I figured I would flesh them out as a full answer.
The problem with the model binding is that it does not allow you to skip array indexes - once one is skipped, it stops binding. Your page has multiple forms, one for each Contract. So the second and subsequent forms do not start at index 0 - they start at index 1 and then index 2 and so on. Thus, the model binding fails immediately and you get a null object passed into your controller.
The simple solution is to move to a single form so that the model binding has access to all the indexes of the Contract objects, and then use extra code in the controller to determine which submit button was pressed.
I'm not certain that is the best solution, though, as having multiple forms and submit buttons is better from an HTTP point of view, since it reduces the amount of unnecessary data that is being posted to the server. However, best is the enemy of good, and if a single form works...
回答2:
At first glance, it looks like a disconnect between what each form represents and what the post controller method is expecting. It looks like each form instance represents a single Contract, while your controller post method is expecting a full Contracts model. Perhaps try changing your controller method to only take a Contract.
来源:https://stackoverflow.com/questions/16613519/mvc-multiple-forms-in-partialview-returns-null-on-postback-for-except-the-1st-on