I am trying to develop a small Questionbank application using MVC3 razor and EF4. Here is my Questionbank razor page:
@using System.Linq
@model MvcApplication1.ViewModels.QuestionBankViewModel
@{
ViewBag.Title = " Question Bank";
}
@Html.ValidationSummary(true)
<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
<script src="../../Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
@using (Ajax.BeginForm(new AjaxOptions()
{
UpdateTargetId = "divToAddQuestion",
InsertionMode = InsertionMode.InsertAfter,
}))
{
<div class="div_question">
<table class="table_question">
<tr>
<td rowspan="3">
</td>
<td>
<span>Question Bank Title</span>
</td>
<td>@Html.EditorFor(model => model.QuestionBank.QuestionBankName) @*Question*@
</td>
<td>
</td>
</tr>
<tr>
<td>
</td>
<td>
</td>
<td>
</td>
</tr>
</table>
<div class="div_answer">
<table class="table_answer">
<tr>
<td>
<span>Questions()</span>
</td>
<td>
</td>
<td>
<input type="submit" id="btnAddQuestion" name="ButtonCommand" value="Add Question" class="cancel" />
</td>
<td></td>
</tr>
</table>
</div>
<div id="divToAddQuestion">
</div>
<div id="divToAddAnswer">
</div>
</div>
<div>
<input type="submit" id="btnSaveQuestionBank" name="ButtonCommand" value="Save" />
</div>
}
When I click on btnAddQuestion ,I am calling my PartialView _Question
Each time I clcik btnAddQuestion it will load my partialView page _Question
Here is my partial view _Question
@using System.Linq
@model MvcApplication1.Models.Question
@{
ViewBag.Title = " Question";
}
@Html.ValidationSummary(true)
<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
<div class="div_question">
<table class="table_question">
<tr>
<td>
<span>Question Number:</span>
</td>
<td >
@Html.TextBoxFor(model => model.QuestionIndex, new { @class = "tinytextbox" })
</td>
<td></td>
</tr>
<tr>
<td>
<span>Question</span>
</td>
<td>@Html.EditorFor(model => model.strQuestion) @*Question*@
</td>
<td>
@Html.ActionLink("Delete this", "Delete", new { id = Model.QuestionIndex }, new { @class = "deletebutton2", title = "Click to delete this Question and its Answers" })
</td>
</tr>
</table>
<div class="div_answer">
<table class="table_answer">
<tr>
<td>
<span>Answers()</span>
</td>
<td>
</td>
<td>
<input type="submit" id="btnAddAnswer" name="ButtonCommand" value="Add Answer" class="cancel" />
</td>
</tr>
</table>
</div>
</div>
Here are my model classes
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcApplication1.Models
{
public class QuestionBank
{
public virtual int QuestionBankId { get; set; }
public virtual string QuestionBankName { get; set; }
public virtual List<Question> Questions { get; set; }
public virtual List<Answer> Answers { get; set; }
public virtual int SubjectTypeId { get; set; }
}
public class Question
{
public int QuestionId { get; set; }
public int QuestionIndex { get; set; }
public string strQuestion { get; set; }
}
public class Answer
{
public int AnswerId { get; set; }
public int QuestionId { get; set; }
public string strAnswer { get; set; }
public int AnswerIndex { get; set; }
}
}
Here is my ViewModel
using System.Collections.Generic;
using MvcApplication1.Models;
namespace MvcApplication1.ViewModels
{
public class QuestionBankViewModel
{
public QuestionBank QuestionBank { get; set; }
public IEnumerable<Question> Questions { get; set; }
public IEnumerable<Answer> Answers { get; set; }
public string ButtonCommand { get; set; }
public int QuestionIndex { get; set; }
public int AnswerIndex { get; set; }
}
}
When I click on btnAnswer, I need to load my partialView _Answer.
@using System.Linq
@model MvcApplication1.Models.Answer
@{
ViewBag.Title = " Answer";
}
@Html.ValidationSummary(true)
<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
<div class="div_answer">
<table class="table_answer">
<tr>
<td>
<span>Answer Number:</span>
</td>
<td>
@Html.TextBoxFor(model => model.AnswerIndex, new { @class = "tinytextbox" })
</td>
<td>
</td>
</tr>
<tr>
<td>
<span>Answer</span>
</td>
<td>@Html.EditorFor(model => model.strAnswer) @*Question*@
</td>
<td>
</td>
</tr>
</table>
</div>
Here I am able to add an answer. Each time I click Add ans it will load new choice of answer.
And when the user finished adding questions and their corresponding answers, the user can click and save the entire question bank using EF4 context.
My issue here is when I click my Save button, I am not able find questions and answers that I typed.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplication1.ViewModels;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
Question qmodel = new Question();
Answer amodel = new Answer();
[HttpGet]
public ActionResult QuestionBank()
{
return View();
}
[HttpPost]
public ActionResult QuestionBank(QuestionBankViewModel model)
{
switch (model.ButtonCommand)
{
case "Add Question":
model.QuestionIndex++;
qmodel.QuestionIndex = model.QuestionIndex ;
return PartialView("_Question", qmodel);
break;
case "Add Answer":
model.AnswerIndex++;
amodel.AnswerIndex = model.AnswerIndex;
return PartialView("_Answer", amodel);
break;
case "Save":
this.SaveQuestionBank(model);
break;
}
return View(model);
}
public ActionResult Question()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public void SaveQuestionBank(QuestionBankViewModel model)
{
QBContext context = new QBContext();
foreach (Question question in model.Questions)
{
context.Question.Add(question);
}
foreach (Answer answer in model.QuestionBank.Answers)
{
context.Answer.Add(answer);
}
context.QuestionBank.Add(model.QuestionBank);
}
public ActionResult About()
{
return View();
}
}
}
My users should be able to add and delete as many questions and answer choices as they want,and finally they should be able to Save everything with the click of Save button.
When I click the save button, I am expecting IEnumerable<Question> Questions and IEnumerable<Answer> Answers within my controller but I am always getting them as null. Why, and how can I fix this?
Or do you think if there is anything wrong with my approach ?
Here is my complete source here as it is ,but not able to get Questions and answers to my controller . Appreciate your comments and suggestions .
I couldn’t able to try the code you have posted because I don’t think all the pieces are there to give a shot but I think I can throw some light to find the issue.
When you are binding collections through model binding you have to make sure the
nameproperty of input elements that are generated should follow the rules 🙂As an example..
Domain model
ViewModel
The Post action
A form through which I can add 5 movies
The important thing to notice here is the way I’m generating the input elements to add 5 movies. If you see the view source, the name of the input elements should goes as Movies[0].x, Movies[1].x.. (Notice
Moviesis the property name of theAddMoviesModel)Please review the view source and make sure the names of the input elements follows thess rules to happen the model binding for collections.
UPDATE:
I looked into the code.. hmm..
The problem is you already have a parent form and you are adding new child forms every time you click the Add Question button. When you try to submit the main form the questions in the child forms are not getting posted to the server and hence no binding 🙁
Why you need each question-answers pair wrapped in HTML form?
The fact is you don’t need HTML forms just to make AJAX calls.
You should change the Add Question and Add Answer to normal buttons(instead of submit) and you have to hook some JavaScript to the click events of those buttons to make the server calls to get the partial views or you could even replace those buttons with Ajax.ActionLinks. You have to change the way things are implemented right now.