views:

28

answers:

1

I've got a model which contains a List of QuestionEditModel for which I want to use an EditorFor.

Normally, I would just call EditorFor on the collection and MVC will do the rest. However, I need the individual QuestionEditModel to use different EditorTemplates depending on the value of a field within the object.

I would've thought that the method for doing this would be something like

<%: Html.EditorFor(model=>model.Questions), [fieldname from individual question] %>

but I cannot figure out how to tell it to look at the Question which is currently selected and use the EntryType field from the question to determine which EditorTemplate to use.

So I tried this

            <% foreach (Reviewer.Models.QuestionEditModel qem in Model.Questions)
           {
               Html.EditorFor(q=>qem, qem.EntryType, null);
           } %>

but this doesn't render anything on to the page. The odd thing is that if I set a breakpoint and run over the code, this does call the correct EditorTemplate, the correct model data is passed in and there are no exceptions, but it just doesn't render anything.

Is there some additional work I need to do in this scenario to get the rendered EditorTemplate back in to my page?

EDIT:

Full code of the Edit View.

<% using (Html.BeginForm()) {%>
    <%: Html.ValidationSummary(true) %>

    <%: Html.HiddenFor(model=>model.AcadPeriod) %>
    <%: Html.HiddenFor(model=>model.ReviewID) %>
    <%: Html.HiddenFor(model=>model.ReviewName) %>
    <%: Html.HiddenFor(model=>model.CategoryID) %>
    <%: Html.HiddenFor(model=>model.CategoryName) %>
    <%-- Categories not getting returned in model for some reason. Use EditorFor or DisplayFor instead of loop? --%>
    <%: Html.HiddenFor(model=>model.Categories) %>
    <%: Html.HiddenFor(model=>model.ClassificationID) %>
    <%: Html.HiddenFor(model=>model.ClassificationName) %>

    <div style="width:100%">

    <div style="float:left">
        <ul style="list-style-type:none">
            <% for (int i = 0; i < Model.Categories.Count(); i++)
               { %>
            <li style="background-color:Gray; border: 1px solid black; padding: 3px 3px 3px 3px; margin-bottom: 2px">
            <%: Html.ActionLink(Model.Categories[i].name, "Edit", new { AcadPeriod = Model.AcadPeriod, ClassificationID=Model.ClassificationID, ReviewID=Model.ReviewID, CategoryID=Model.Categories[i].category_id })%>
            </li>
            <% }%>
        </ul>
    </div>

    </div>
                <% foreach (Reviewer.Models.QuestionEditModel qem in Model.Questions) { %> 
                     <%: Html.EditorFor(q=>qem, qem.EntryType,null); %> 
                <% } %> 

        <p>
            <input type="submit" value="Save" />
        </p>

<% } %>

EDIT 2:

Complete View, Controller, and Template code as requested.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Reviewer.Models.ReviewEditModel>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Edit
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h1><%: Model.AcadPeriod %> &gt; <%: Model.ClassificationName %> &gt; <%: Model.ReviewName %></h1>

<% using (Html.BeginForm()) {%>
    <%: Html.ValidationSummary(true) %>

    <%: Html.HiddenFor(model=>model.AcadPeriod) %>
    <%: Html.HiddenFor(model=>model.ReviewID) %>
    <%: Html.HiddenFor(model=>model.ReviewName) %>
    <%: Html.HiddenFor(model=>model.CategoryID) %>
    <%: Html.HiddenFor(model=>model.CategoryName) %>
    <%-- Categories not getting returned in model for some reason. Use EditorFor or DisplayFor instead of loop? --%>
    <%: Html.HiddenFor(model=>model.Categories) %>
    <%: Html.HiddenFor(model=>model.Questions) %>
    <%: Html.HiddenFor(model=>model.ClassificationID) %>
    <%: Html.HiddenFor(model=>model.ClassificationName) %>

    <div style="width:100%">

    <div style="float:left;width: 15%">
        <ul style="list-style-type:none">
            <% for (int i = 0; i < Model.Categories.Count(); i++)
               { %>
            <li style="background-color:Gray; border: 1px solid black; padding: 3px 3px 3px 3px; margin-bottom: 2px">
            <%: Html.ActionLink(Model.Categories[i].name, "Edit", new { AcadPeriod = Model.AcadPeriod, ClassificationID=Model.ClassificationID, ReviewID=Model.ReviewID, CategoryID=Model.Categories[i].category_id })%>
            </li>
            <% }%>
        </ul>
    </div>

    <div style="float:left; width: 80%; margin-left: 5px">

<% foreach (Reviewer.Models.QuestionEditModel qem in Model.Questions) { %> 
 <%: Html.EditorFor(q=>qem, qem.EntryType,null) %> 
<% } %> 

    </div>
    </div>
    <div style="clear:both" />
        <p>
            <input type="submit" value="Save" />
        </p>

<% } %>

<div>
    <%: Html.ActionLink("Back to List", "Index") %>
</div>

</asp:Content>

Editor Template:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Reviewer.Models.QuestionEditModel>" %>

<div style="width:100%; border: 1px solid black">
 <div style="width: 100%; border: 1px solid black"><h2><%: Model.QuestionName %></h2></div>
<div style="width:25%; display:inline; border: 1px solid black; float:left">
    <%: Model.QuestionText %>
</div>
<div style="width:70%; border: 1px solid black; float:left">
    <%: Html.TextAreaFor(model=>model.Answer) %>
    <%:Html.ValidationMessageFor(model=>model.Answer) %>
</div>

 <div style="clear:both" />
</div>

    <fieldset>
        <legend>TEXT</legend>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.QuestionID) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.QuestionID) %>
            <%: Html.ValidationMessageFor(model => model.QuestionID) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.QuestionName) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.QuestionName) %>
            <%: Html.ValidationMessageFor(model => model.QuestionName) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.QuestionText) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.QuestionText) %>
            <%: Html.ValidationMessageFor(model => model.QuestionText) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.DefaultText) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.DefaultText) %>
            <%: Html.ValidationMessageFor(model => model.DefaultText) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.EntryType) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.EntryType) %>
            <%: Html.ValidationMessageFor(model => model.EntryType) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.HelpText) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.HelpText) %>
            <%: Html.ValidationMessageFor(model => model.HelpText) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Answer) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Answer) %>
            <%: Html.ValidationMessageFor(model => model.Answer) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.OptionValue) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.OptionValue) %>
            <%: Html.ValidationMessageFor(model => model.OptionValue) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.completedBy) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.completedBy) %>
            <%: Html.ValidationMessageFor(model => model.completedBy) %>
        </div>

        Option Required: <%:Html.TextBoxFor(model=>model.OptionRequired) %>
        Answer Required: <%: Html.TextBoxFor(model=>Model.AnswerRequired) %>

    </fieldset>

Edit(GET) Action:

        public ActionResult Edit(string AcadPeriod, string ClassificationID, string ReviewID, int CategoryID)
    {
        Reviewer.Models.ReviewEditModel dset1 = rr.GetReviewEditModel(AcadPeriod, ReviewID, CategoryID.ToString(), ClassificationID);
        return View(dset1);
    }

Edit(POST) Action:

        [HttpPost]
    public ActionResult Edit(Reviewer.Models.ReviewEditModel model)
    {
        try
        {
            foreach (Reviewer.Models.QuestionEditModel qem in model.Questions)
            {
                if (qem.Answer == null || qem.OptionValue == null) { qem.completedBy = this.HttpContext.User.Identity.Name; }
            }

            if (ModelState.IsValid)
            {
                rr.SaveReviewEditModel(model);

                return RedirectToAction("Index");
            }
            else { return View(model); }
            }
        catch
        {
            return View(model);
        }
    }
+1  A: 

You have to tell it what to actually render (<%: %>):

<% foreach (Reviewer.Models.QuestionEditModel qem in Model.Questions) { %>
     <%: Html.EditorFor(q=>qem, qem.EntryType, null) %>
<% } %>
Necros
What a fool, I thought I'd be clever and try to put it all in one code block and completely forgot about the :. However, when running your code I get a CS1026: ) expected, however I can't see any missing parantheses.I have added the full Edit View code to my original post.
hermiod
The error is appearing on the Html.EditorFor line.
hermiod
It was just the ; on the end of the line throwing it off. That has done the job perfectly, thanks Necros. Can't believe I was so close! :)
hermiod
Spoke too soon. When the form is submitted, the Questions collection is empty. Any ideas?
hermiod
If you post the view model and the action method you are posting to and the template you are using for questions, I can have a look. But basically you map to array view model properties like that: http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
Necros
I checked your code. I would use this approach if I were u: http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
Necros
Hi Necros. I have tried the method you suggested, however the collection is still coming back empty. The only difference I can see is that Steven Sanderson's scenario has the view strongly typed to the ienumerable where as in my scenario the list is a child of the view type.The correct behavior is being exhibited by Steven's method but it just doesn't seem to be working.
hermiod
I've done some further research and have found that MVC is trying to convert my Category collection to a string. I tried the method suggested at (http://dotfresh.blogspot.com/2010/04/using-editorfor-method-in-mvc2-to.html) to get around that, but to no avail. Surely I can't be the only one having this much trouble with child collections in my models?
hermiod