tags:

views:

396

answers:

4

I'm building a questionnaire mvc webapp, and i cant figure out how to pass an unknown number of arguments to the controller from the form.

My form is something like:

<% using (Html.BeginForm())
   { %>
<div id="Content">
    <% foreach (var group in ViewData.Model.QuestionGroups)
       { %>
    <div class="Group">
        <%=group.Description %>
        <% foreach (var question in group.Questions)
           {%>
        <div class="Question">
            <div class="QuestionTitle">
                <%=question.Title %>
            </div>
                <%=Html.Hidden("Id", question.ID) %>
            <div class="QuestionText">
                <%switch (question.TypeAsEnum)
                  {
                      case QuestionTypeEnum.Text:%>
                <%=Html.TextBox("somename") %>
                <% break;
                      case QuestionTypeEnum.Number:%>
                <%=Html.TextBox("somename") %>
                <% break;
                      case QuestionTypeEnum.PhoneNumber:%>
                <%=Html.TextBox("somename")%>
                <% break;
                      case QuestionTypeEnum.Email:%>
                <%=Html.TextBox("somename")%>
                <% break;
                      case QuestionTypeEnum.Date:%>
                <%=Html.TextBox("somename")%>
                <% break;
                      case QuestionTypeEnum.YesNo:%>
                <%=Html.RadioButton("somename", true)%>
                <%=Html.RadioButton("somename", false)%>
                <% break;
                      case QuestionTypeEnum.Alternative:%>
                <%=Html.DropDownList("somename", question.Answers)%>
                <% break;
                  }%>
            </div>
        </div>
        <% } %>
    </div>
    <% } %>
</div>
<div id="submittButton">
    <%=Html.SubmitButton()%></div>
<% } %>

Now what i need in my controller is List< ResponseAnswer >, where ResponseAnswer has the properties:

string questionID, string AnswerText, bool AnswerBool, number AnswerNumber, ...

So how can i pass an unknown number of items containing questionID, AnswerType and Answer to the controller. In webforms i solved this by rendering the form with repeaters instead of foreach, and then iterating through the question repeater checking the control id, each repeater item containing a hidden questionid element and a input with id=AnswerType. But this will seriously break Separation of concern in mvc?

So is there any way of getting my controller to accept List< ResultAnswer > and somehow build this list without breaking soc, and if not, how do i pass the entire formresult back to the controller so i can do the iteration of the form data there instead of in the view.

+3  A: 

You can add an argument to your action like

public ActionResult MyAction(FormCollection form)

Then the form parameter will contain all the data from the posted form. From that you can do what you want.

You could probably implement a binder that could map to ResponseAnswers but I have no experience of doing that so I'll leave that to someone else.

Garry Shutler
A: 

To clarify gary's answer, you can then easily walk through all fields of the form like this

foreach (string s in Request.Form.Keys)
{
    if (s.Contains("number"))
        number = int.Parse ((Request.Form[s]));

    //do something
}
Morph
A: 

Thanks for the tip, puts me a step in the right direction at least, problem with the FormCollection though is that its a NameValueCollection with duplicates, so i end up with Id{1,2,3,6,4,8..} Text{"my answer", "your answer", " our answer"..} Number{"21","23","4"...} etc. I have no way of mapping the correct Ids to the correct Answers(Text[i],Number[i] etc..).

This was not a problem in WebForms since Repeater was wrapping its Items in namingcontainers so i could access the individual controls pr. repeat.

I took a quick look into the binder functionality you mention but couldn't find anything i can figure out how to apply to this context.

Bernt
What about doing something like Html.TextBox("somename" + question.Id) so you can group bits together or something?
Garry Shutler
+1  A: 

Garry's answer will work (and hence, up voted). However, you can model bind directly to a list, and I think it's a bit more elegant. There are instructions in this blog post.

Craig Stuntz
Hurrah, someone spelt my name right!
Garry Shutler
Upvote for link too, knew I'd seen something somewhere
Garry Shutler