How to model a ViewModel, when Views need different ViewModels based on a condition?
I am building a questionnarie. It displays two questions at a time. The questions can be of different types. For instance, Multiple Choice questions, and "Matrix" questions, where there are many rows and columns that need to be answered.
I am currently not using ViewModels, just the entity models (i know i shouldnt do this)..
The code to retrieve a list of questions:
public ActionResult QuestionList(int categoryId, int page)
{
var questions = new PagedData<Question>();
questions.Data = db.Question.Where(c => c.category_id == categoryId).OrderBy(p => p.question_number).Skip(PageSize * (page - 1)).Take(PageSize).ToList();
questions.NumberOfPages = Convert.ToInt32(Math.Ceiling((double)db.Question.Where(cc => cc.category_id == categoryId).Count() / PageSize));
questions.CurrentPage = page;
questions.CategoryID = categoryId;
return PartialView("QuestionList", questions);
}
The View looks like this:
@model MvcApplication3.Helpers.Paging.PagedData<MvcApplication3.Models.Question>
@if (Mo开发者_运维百科del.Data.Count() == 0)
{
<h2>Denne kategori har ingen spørgsmål</h2>
}
else
{
<h2>@Model.Data.First().Category.category_name</h2>
<br />
<div>
Tryk for at komme videre til side:
@for (int i = 1; i <= Model.NumberOfPages; i++)
{
if (i == Model.CurrentPage)
{
@i
}
else
{
<a class="page-number" href="javascript:void();">@i</a>
}
}
</div>
<br />
foreach (var item in Model.Data)
{
if (item.visible == true)
{
String isAnswered = null;
if (item.Tabelform_Answers.Count() >= 1)
{
isAnswered = "answered";
}
else if(item.MCQ_Answers.Count() >= 1)
{
isAnswered = "answered";
}
else
{
isAnswered = "unanswered";
}
<div id=@isAnswered>
@if (User.IsInRole("Administrator"))
{
@Html.ActionLink("[Rediger]", "Edit", "AdminQuestion", new { id = item.question_id }, null)
}
@Html.LabelFor(y => item.question_wording, item.question_wording, new { @class = "tooltip", title = @item.help_text })
@if (item.Question_Type.type_description == "Multiple Choice")
{
<br />
@Html.Partial("MCQDisplay", item)
}
else if (item.Question_Type.type_description == "Tabelform")
{
<br /><br />
@Html.Partial("GridDisplay", item)
}
</div>
<br />
}
}
}
@Html.HiddenFor(m => m.NumberOfPages)
@Html.HiddenFor(m => m.CategoryID)
@Html.HiddenFor(m => m.CurrentPage)
Instead of sending the whole Question entity to the partial views MCQDisplay and GridDisplay, i would like to send only the data neccecary.
How should this ViewModel look like?
My idea was to have a list for each type of question, in a main ViewModel, like this:
List<MultipleChoiceViewModel> mcqlist;
List<GridQuestionViewModel> gridlist;
If there are no questions of type Multiple Choice in the Category, the list would be null and not be used. Is this good practise?
Something you could try is this. I'm not 100% sure it would work, since i don't know if the MVC framework will only look for the model type, or it's real type.
Pass a base clas as your model type, then derive your different viewmodels from the base class type. Then you define editor templates for each question type and just use DisplayFor or EditorFor for that type and let it render itself.
As I said, this will depend on whether or not MVC uses it's ultimate type, or just the base type.
EDIT:
You create base class, called QuestionViewModel
, it doesn't need to have any properties or methods but if there are common methods or properties you could put them here.
Then derive MultipleChoiceViewModel
and GridQuestionViewModel
from QuestionViewModel
.
In your View:
@model IEnumerable<QuestionViewModel>
@Html.EditorForModel()
Then you create a folder called EditorTemplates in your Views/Whatever folder, in your Views/Shared folder for each type, then define your html for each type.
MVC should automatically know that a question is a GridQuestionViewModel and use it's editor template when you pass your list of them.
精彩评论