Reputation: 122
I am quite new to ASP.NET MVC, and I am working on a small quiz app project. However I am stuck with a rather annoying problem.
Right now I have a few models, with questions, choices and the quiz. The quiz is connected to a form. I use partial views in the forms to display each question, in the question I use another partial view to display the choices.
Whenever I try to get which answers were given from the form, I get 0 and null back. I have tried a lot of things, but none of them have worked.
Here are my classes
Choice
public class Choice
{
public int Id { get; set; }
public string Text { get; set; }
public bool IsAnswer { get; set; }
private Question question = new Question();
public bool IsSelected { get; set; }
public Question Question
{
get { return question; }
set { question = value; }
}
}
Question
public class Question
{
public int Id { get; set; }
private IList<Choice> choices = new List<Choice>();
public string Text { get; set; }
public int OrderNumber { get; set; }
public IList<Choice> Choices
{
get { return choices; }
set { choices = value; }
}
}
Quiz
public class Quiz
{
public int Id { get; set; }
public IList<Question> questions = new List<Question>();
public string Name { get; set; }
public IList<Question> Questions
{
get { return questions; }
set { questions = value; }
}
}
My controller. It does always set 'zzz' to null and 0's.
[HttpPost]
public ActionResult Grade(Quiz zzz)
{
var grade = quizService.Grade(zzz);
return View(grade);
}
The views. I used to not have the ViewDataDictionary, but that gave nulls too. I changed it to a ViewDataDictionary, but it still gives nulls back.
Note: I did add the comments right now, they are not in the actual code
Publish
@model QuizApp.Models.Quiz
@{ ViewBag.Title = "Publish";}
@Html.Hidden("Id", Model.Id)
@using (Html.BeginForm("Grade","Quiz", FormMethod.Post))
{
foreach (var question in Model.Questions){
@Html.Partial("_Question", question, new ViewDataDictionary(){
TemplateInfo = new TemplateInfo()
{ HtmlFieldPrefix = "Questions" }
});
}
<input type="submit" value="Vesturen" />
}
Question
@model QuizApp.Models.Question
<div class="question">
@Html.Hidden("Quiz.Questions[" + Model.OrderNumber + "].Id", Model.Id)
//Shows the question
<b>@Model.Text </b><br/>
//Adds choices to the question
@foreach (var choice in Model.Choices)
{
@Html.Partial("_Choice", choice, new ViewDataDictionary()
{
TemplateInfo = new TemplateInfo()
{ HtmlFieldPrefix = "Choices" }
});
}
</div>
And finally the choice Partial view
@model QuizApp.Models.Choice
@Html.RadioButton("Quiz.Questions[" + Model.Question.OrderNumber + "].Choices[0].Id", Model.Id)
@Model.Text
Does anyone see a solution to my problem, or maybe a workaround? Did I do something wrong, that I obviously do not know about? I don't understand why it keeps giving me nulls, since it should be working now to my knowledge.
Upvotes: 1
Views: 224
Reputation: 239260
The following will work:
for (var i = 0; i < Model.Questions.Count(); i++){
@Html.Partial("_Question", question, new ViewDataDictionary(){
TemplateInfo = new TemplateInfo()
{ HtmlFieldPrefix = "Questions[" + i.ToString() + "]" }
});
}
In other words, your field prefix needs to contain the index. Also, the index cannot be an arbitrary value, as you're attempting to do with Model.Question.OrderNumber
. It needs to be the actual index within the list.
Alternatively, if you create the view Views\Shared\EditorTemplates\Question.cshtml
along the lines of:
@model Namespace.To.Question
@Html.HiddenFor(m => m.Id)
...
Then, in your view, you can simple do:
@Html.EditorFor(m => m.Questions)
And Razor will render that editor template for each item in Questions
, all prefixed properly. Rinse and repeat with your other classes like Choice
, etc.
Upvotes: 2