BILL
BILL

Reputation: 4869

Get data from Form in MVC3?

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

Answers (2)

DMulligan
DMulligan

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

Erik Funkenbusch
Erik Funkenbusch

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

Related Questions