Reputation: 4869
I have this this View for rendering form
@using ExpertApplication.ViewModels
@model IEnumerable<QuestionViewModel>
@{
ViewBag.Title = "GetQuestions";
}
@using(Html.BeginForm("ProcessAnswers", "Home", FormMethod.Post))
{
foreach(QuestionViewModel questionViewModel in Model)
{
Html.RenderPartial("QuestionPartialView", questionViewModel);
}
<input type="submit" value="Send data"/>
}
}
<h2>GetQuestions</h2>
And partial view
@using ExpertApplication.ViewModels
@model QuestionViewModel
<div id="question">
@Model.Text
<br />
<div id="answer">
@foreach(var answer in Model.AnswerViewModels)
{
@(Model.IsMultiSelected
? Html.CheckBoxFor(a => answer.Checked)
: Html.RadioButtonFor(a => answer.Checked, false))
@Html.LabelFor(a => answer.Text)
<br />
}
</div>
</div>
I want get data from From
[HttpPost]
public ActionResult ProcessAnswers(IEnumerable<QuestionViewModel> answerForQuesiton)
{
//answerForQuestion always is null
}
but parameter answerForQuesiton is null. How to fix this problem ?
Upvotes: 1
Views: 635
Reputation: 9073
MVC binds lists by using zero indexed names. Unfortunately, for this reason, while foreach
loops will create inputs that contain the correct values, they will not create input names that use the correct names. Therefore, you cannot bind lists using foreach
For example:
for (int i = 0; i< Model.Foo.Count(); i++)
{
for (int j = 0; j < Model.Foo[i].Bar.Count(); j++)
{
@Html.TextBoxFor(m => m.Foo[i].Bar[j].myValue)
}
}
Will create textboxes with names like "Foo[1].Bar[2].myValue" and correctly bind. However,
foreach (var foo in Model.Foo)
{
foreach (var bar in foo.Bar)
{
@Html.TextBoxFor(m => bar.myVal);
}
}
will create text boxes with the exact same values as the prior loop, but all of them will have "name="bar.myVal" so none of them can bind.
So to fix your issue:
1) You could replace your foreach loops with for loops. Note: this requires using IList
or List
instead of IEnumerable
2) You could use EditorTemplates which automatically apply the correct names for you.
Upvotes: 1
Reputation: 93434
You are using the wrong mechanism. You should be using EditorTemplates rather than partial views. Editor Templates know how to deal with collections and creating properly formatted name attributes so they can be bound on post-back.
http://coding-in.net/asp-net-mvc-3-how-to-use-editortemplates/
Upvotes: 1