1

I have a problem (or I don't understand how forms work) with passing a model to a controller from a form. I have a model called EmptySurveyViewModel, that has a list consisting of EmptyQuestionViewModel. This question model has a property Answer that is empty, and is to be filled by the form. However, one survey has many questions, and at the end i want to pass a model to the controller that is a EmptySurveyViewModel, containing a list of EmptyQuestionViewModel, that each has the Answer property. That property can be filled in different ways, depending on the type of the question. My problem is that if I don't have the if statement (see below), all questions are displayed as radio style questions, and the model passed to the controller has only questions that have the Answer property filled. However, when i add the if (i intend to add other ifs, to catch all possible types), only some questions are listed, and when i submit the form, the model is completely empty (it's not null, but its property Questions is null. I think the first situation (without the if) can be dealt with by other logic later on, but returning an empty list can't. Why is that happening?

The Models:

public class EmptySurveyViewModel {
    //Something else here
    public List<EmptyQuestionViewModel> Questions { get; set; }
}

public class EmptyQuestionViewModel {
    //Something else here
    public string Answer { get; set; }
}

The View:

@model cq.Models.EmptySurveyViewModel

@using (Html.BeginForm("New", "Client", FormMethod.Post, new { role = "form" })) {
    for (int i = 0; i < Model.Count(); i++) {
        if (Model.Questions[i].Type == "Single choice") {
            @Html.RadioButtonFor(m => m.Questions[i].Answer, "foo")
            @Html.RadioButtonFor(m => m.Questions[i].Answer, "bar")
        }
        <br />
    }

    <input type="submit" value="submit" />
}

And the Action in the controller:

[HttpPost]
public ActionResult New(EmptySurveyViewModel survey) {
    //Do something with the survey here
}
Emberfire
  • 89
  • 7
  • please check with FormCollection add in Action parameter like eg, [HttpPost] public ActionResult New(EmptySurveyViewModel survey,FormCollection fc) { //Do something with the survey here } if a value occurs in form? – jishan siddique Aug 06 '19 at 14:37
  • @jishansiddique As it turns out it was a problem of the model binder not understanding the model, as Andrei suggested. Thank you for the suggestion though :) – Emberfire Aug 07 '19 at 07:38

1 Answers1

1

I believe this happens because you are skipping some of the indices. So when the data is posted back, you maybe post objects with indices 0, 1, 3, while 2 is missing because it happened to be filtered out by if. That breaks the continuity of the collection, something model binding cannot deal with. More details can be found in this Haacked post.

There are few possible solutions:

  1. Add other if's to cover all question types. That will make sure there are no skips.
  2. As Phil suggests in the post, add a hidden Index field to each question (also see this post). Note that this will cause only rendered questions to be posted back.
  3. Render filtered out questions as hidden inputs entirely, again avoiding skipping any of them.
Andrei
  • 55,890
  • 9
  • 87
  • 108
  • Thank you, I was able to get the model to bind when I added the other types of questions. I had a problem with the model not binding if the line of answered questions was broken(a question was left unanswered), but i fixed it by adding a hidden input for a hidden value called "Token" in the model. That fixed my issue, thank you again :) P.S. MVC model binder is dumb, I feel there can be a more intuitive way to do this in my opinion – Emberfire Aug 07 '19 at 07:35