0

I'm using MVC, Have the following Model

public class Questionnaire 
     {
     public string Name { get; set; }
     public List<Question> Questions { get; set; }
 }

and Question class is :

public class Question 
 {
     public int QuestionNumber { get; set; }
     public string Body { get; set; }
     public IList<Option> Options { get; set; }
     //public IEnumerable<CreativeFactory.Option> OptionsTemp { get; set; }
     public Guid? QuestionnaireId { get; set; }
     public Guid? SelectedOption { get; set; }
     public int? SelectedEmployeeId { get; set; }

  } 

In my View I do foreach, and partially render a view

    % Html.BeginForm("Submit", "Questionnaire", FormMethod.Post); %>
    <%

    foreach (var q in Model.Questions)
    {
    Html.RenderPartial("Question", q);
    }
    %>
    <input type="submit" name="submit" value="submit" />
    <% Html.EndForm(); %>

My problem is the passed model to my action is always null

[AcceptVerbs(HttpVerbs.Post)]
         public ActionResult Submit(Questionnaire m)
         {
}

EDIT 1: Well, My Partial View Code is :

<%
 foreach (var option in Model.Options)
 {%>
   <p/>
 <%= Html.RadioButtonFor(x => x.SelectedOptionId, option.QuestionId, new { id = "test" +    option.ID })%>
<%
}     
%>

Even in the debugging Mode, I can't find my collection in the Form instance so even Custom Binding dosn't solve the problem, because the collection is not exist

any idea please?

  • Please check the element ID's rendered by your partial view. Are these in form that is supported by default model binder to list? Refer to Phil Haack's post related to "model binding to list" – byte Aug 22 '11 at 12:26

3 Answers3

3

I think you have to make Questionnaire implement ICollection<Question> and then follow these detailed instructions in Phil Haack's post. If you don't want Questionnaire to implement ICollection<Question>, I think you need to implement a custom model binder of the Questionnaire type.

Buu
  • 49,745
  • 5
  • 67
  • 85
  • I Implemented ICollection, and checked the above link , But still have the same problem, Do you think the problem with Html.RenderPartial("Question", q); ? – Sameh Aboelnil Aug 22 '11 at 10:58
  • Hard to tell unless you post code for RenderPartial. In general, if generated HTML conforms to the rules specified in that post, it should be okay. – Buu Aug 22 '11 at 12:34
  • 1
    The inputs in your partial view should have a name like "Questions[i].QuestionNumber" where i is the index (zero based) of the question. You should pass the index to the partial (or use QuestionNumber as index but be sure that it's zero for the first one) and check that you're generating the right names for the inputs so the model binder can do it's work. – Eduardo Campañó Aug 22 '11 at 13:04
  • Eduardo Campano, would you please clarify your solution based on the code above – Sameh Aboelnil Aug 22 '11 at 13:23
  • @Aboelnil: Eduardo Campano is right, as well as Buu Nguyen answer. Please refer to this [question and answer](http://stackoverflow.com/questions/616559/default-model-binder-and-complex-types-that-include-a-list) for further details on it. – Lorenzo Aug 22 '11 at 13:31
1

This is the code for your partial, not tested. I assumed a zero based QuestionNumber:

<input type="hidden" name="Questions[<%= Model.QuestionNumber %>].QuestionNumber" value="<%= Model.QuestionNumber %>" />
<% foreach (var option in Model.Options) { %>
  <input type="radio" name="Questions[<%= Model.QuestionNumber %>].SelectedOptionId" value="<%= option.ID %>" /><%= option.Text %>
<% } %>
Eduardo Campañó
  • 6,778
  • 4
  • 27
  • 24
  • Eduardo, I just have one question please According to http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx , we don't use hidden fields, why we use it in your example – Sameh Aboelnil Aug 23 '11 at 01:03
  • 2
    The key is to associate the question with the answer. I added it so in the Questionnaire that you receive in the action you get that property loaded, otherwise it will be zero or a default value. If you check that you will see that in the Questionary every Question will have null in the Body and also in the Options property, that is because the model binder didn't find information about those properties in the post values. If you remove the hidden you still will get the Questionnaire but you have to use the order of the questions to know to which question the answer corresponds. – Eduardo Campañó Aug 24 '11 at 04:44
0

Complete answer: MVC post a list of complex objects which contains Phil Haack's solution and another one too:

@for (var itemCnt = 0; itemCnt < Model.Questions.Count(); itemCnt++)
{
    @Html.TextBoxFor(m => Model.Questions[itemCnt].Body)
    ....
    @Html.HiddenFor(m => Model.Questions[itemCnt].QuestionNumber )
}
Community
  • 1
  • 1
OzBob
  • 4,227
  • 1
  • 39
  • 48