Search code examples
asp.netasp.net-mvc-4c#-4.0razor

Razor post collection


I am having an issue for posting collection. I just start learing MVC and razor. I am writing a small questionnaire application all what I am doing populate a list of question and let the user answer the question and post the answer.

I have two class in the model Questionaire and QuestionRepository the controller have two method one for fetch the question other one to get the post data, the problem i am struggling when I populate the form with textbox I am struggling to post back the collection.

Basically what i want to achive pull the list of question, population on the UI with a text box, send the the list of question with the answer to the controller for processing some logic.

I Would really appreciate if someone can help me.

public class Questionnaire
{
    public string Title {
        get;
        set;
    }
    public IList<string> Questions {
        get;
        set;
    }
    public string Answer {
        get;
        set;
    }
}

public Questionnaire GetQuestionnaire() {
    return new Questionnaire {
    Title = "Geography Questions",
      Questions = new List<string>  
       {
          "What is the capital of Cuba?",
          "What is the capital of France?",
          "What is the capital of Poland?",
          "What is the capital of Germany?"
         }
        };
    }

    public int GetCustomerAnswer() {
        return 0;
    }
}

Controller

public ActionResult Index()
{
  var q = new QuestionRepository().GetQuestionnaire();  
  return View(q);
}

[HttpPost]
public ActionResult GetAnswer(QuestionRepository q) {
   return View();
}

View

@model Question.Models.Questionnaire
<h2>Question List</h2>
@using(Html.BeginForm("GetAnswer","Home"))
{
  for(int i=0;i< Model.Questions.Count;i++)
  {
    @Html.Label("Question")
    <text>@Model.Questions[i]</text>
    @Html.TextBox(Q => Model.Questions[i])
    <br /> 
  }
  <input type="submit" name="submit" />
}

Solution

  • Firstly you model is wrong and does not define any relationship between questions and associated answers (you only have the ability to add one answer to all the questions). Secondly your view binds a text box to each question, allowing the user to only edit the question and not add a answer. A simple example might look like

    View models

    public class QuestionVM
    {
      public int ID { get; set; }
      public string Text { get; set; }
    }
    
    public class AnswerVM 
    {
      public QuestionVM Question { get; set; }
      public int ID { get; set; }
      public string Text { get; set; }     
    }
    
    public class QuestionnaireVM
    {
      public int ID { get; set; }
      public string Title { get; set; }
      public List<AnswerVM> Answers { get; set; }
    }
    

    Controller

    public ActionResult Create(int ID)
    {
      QuestionnaireVM model = new QuestionnaireVM();
      // populate the model from the database, but a hard coded example might be
      model.ID = 1;
      model.Title = "Questionaire 1";
      model.Answers = new List<AnswerVM>()
      {
        new AnswerVM()
        {
          Question = new QuestionVM() { ID = 1, Text = "Question 1" }
        },
        new AnswerVM()
        {
          Question = new QuestionVM() { ID = 2, Text = "Question 2" }
        }
      };
      return View(model);
    }
    
    [HttpPost]
    public ActionResult Create(QuestionnaireVM model)
    {
      // save you data and redirect
    }
    

    View

    @model QuestionnaireVM
    @using(Html.BeginForm())
    {
      @Html.DisplayFor(m => m.Title)
      for(int i = 0; i < Model.Answers.Count; i++)
      {
        @Html.HiddenFor(m => m.Answers[i].Question.ID)
        @Html.DisplayFor(m => m.Answers[i].Question.Text)
        @Html.TextBoxFor(m => m.Answers[i].Text)
      }
      <input type="submit" />
    }
    

    This will generate a view display each question with and associated textbox to add the answer.When you post back the model will contain the ID of the questionnaire, and a collection containing the ID of each question and its associated answer.

    A couple of other examples of similar issues here and here