@Display, ViewModels, & Templates, Oh my!

Topics: Customizing Orchard, Writing modules
Jan 8, 2014 at 4:03 AM
Okay. I've been muddling my way through Shapes & Templates, and am trying to reuse HTML code. I came across this (http://www.szmyd.com.pl/blog/using-shapes-as-html-helpers-in-orchard), and thought I was getting my head around it, but am running into an issue.

I have the following Template:
@using Zoetic.Website.ViewModels

@model CourseDefinitionViewModel
<@Page validateRequest="false" %>

@{
    Style.Require("Hillside.CommonForm");

    Script.Require("jQuery");
    Script.Require("OrchardTinyMce");
}

   <article class="form">
        <fieldset>
            <ul>
                <li>
                    <div class="field-label">
                        @Html.LabelFor(m => m.CourseName)
                    </div>
                    <div class="field-editor">
                        @Html.EditorFor(m => m.CourseName)
                        @*@Html.ValidationMessageFor(model => model.StateCode)*@
                    </div>
                </li>

                <li>
                    <div class="field-label">
                        @Html.LabelFor(m => m.CategoryName, T("Category"))
                    </div>
@*                    <div class="field-editor">
                        @Html.DropDownListFor(m => m.CategoryCode,
                                          Model.Model.Categories.Select(
                                                s => new SelectListItem {
                                                Selected = s.Code == Model.Model.CategoryCode,
                                                Text = s.Name,
                                                Value = s.Code
                                          }),
                                          "Choose a category...")
                    </div>*@
                </li>

                <li>
                    <div class="field-label">
                        @Html.LabelFor(m => m.CourseDetails, T("Course Details"))
                    </div>
                    <div class="field-editor">
                        @Html.TextArea("CourseDetails", (string)Model.CourseDetails, 25, 80,
                                   new Dictionary<string, object> {
                                       {"class", "html tinymce"},
                                       //{"data-mediapicker-uploadpath", Model.AddMediaPath},
                                       {"data-mediapicker-title",T("Insert/Update Media")}
                                       //{"style", "width:50%"}
                                   })
                    </div>
                </li>

                <li>
                    <div class="field-label">
                        @Html.LabelFor(m => m.NumberOfDays, T("# of Days"))
                    </div>
                    <div class="field-editor">
                        @Html.EditorFor(m => m.NumberOfDays)
                        @*@Html.ValidationMessageFor(model => model.StateCode)*@
                    </div>
                </li>
            </ul>
        </fieldset>

        <fieldset>
            <ul>
                <li>
                    <div class="field-label">
                        @Html.LabelFor(m => m.Tuition, T("Tuition"))
                    </div>
                    <div class="field-editor">
                        @Html.EditorFor(m => m.Tuition)
                        @*@Html.ValidationMessageFor(model => model.StateCode)*@
                    </div>
                </li>

                <li>
                    <div class="field-label">
                        @Html.LabelFor(m => m.ReviewerTuition, T("Reviewer"))
                    </div>
                    <div class="field-editor">
                        @Html.EditorFor(m => m.ReviewerTuition)
                        @*@Html.ValidationMessageFor(model => model.StateCode)*@
                    </div>
                </li>
                <li>
                    <div class="field-label">
                        @Html.LabelFor(m => m.DiscountTuition, T("Discount"))
                    </div>
                    <div class="field-editor">
                        @Html.EditorFor(m => m.DiscountTuition)
                        @*@Html.ValidationMessageFor(model => model.StateCode)*@
                    </div>
                </li>
            </ul>
        </fieldset>

        <fieldset>
            <ul>
                <li>
                    <div class="field-label">@Html.LabelFor(m => m.Prerequisites, T("Prerequisites"))</div>
                    <div class="field-editor">@Html.EditorFor(m => m.Prerequisites)</div>
                </li>
                <li>
                    <div class="field-label">@Html.LabelFor(m => m.IsActive, T("Active"))</div>
                    <div class="field-editor">@Html.EditorFor(m => m.IsActive)</div>
                </li>
            </ul>
        </fieldset>
        <fieldset class="save-button">
            @{
    var returnUrl = ViewBag.ReturnUrl;
            }

            @if (!String.IsNullOrWhiteSpace(returnUrl)) {
                <a id="button-cancel" href="@Url.Action(returnUrl)" class="button" style="float: left">@T("Cancel")</a>
            }

            <button style="float: right;" class="primaryAction" type="submit" name="submit.Save" value="submit.Save">@T("Submit")</button>
        </fieldset>
        @*      <footer class="commands">
            <ul>
                <li class="align left"><a href="@Url.Action("ListCourseDefinitions")">@T("Cancel")</a></li>
                <li class="align right">
                    <button type="submit">@T("Submit")</button></li>
            </ul>
        </footer>*@
    </article>
This is being called from:
@model Zoetic.Website.ViewModels.CourseDefinitionViewModel
@*@{
    Style.Require("Hillside.CommonForm");

    Script.Require("jQuery");
    Script.Require("OrchardTinyMce");
}*@

<h2>@T("New CourseType")</h2>
<p>@T("Please fill out the form below")</p>

@Html.ValidationSummary()
@using (Html.BeginFormAntiForgeryPost(Url.Action("CreateNewCourseDefinition", "CourseAdmin", new { area = "Zoetic.Website" }))) {    
    @Display(New.CourseDefinition(CourseDefinitionViewModel: Model))
}
I am getting all kinds of different errors, depending on the various permutations that I have tried. This particular manifestation generates the following error:
The model item passed into the dictionary is of type 'Orchard.DisplayManagement.Shapes.Shape', but this dictionary requires a model item of type 'Zoetic.Website.ViewModels.CourseDefinitionViewModel'.
However, if I change the model around to this:
                    <div class="field-label">
                        @Html.LabelFor(Model.CourseName)
                    </div>
I get the following error:
The type arguments for method 'System.Web.Mvc.Html.LabelExtensions.LabelFor<TModel,TValue>(System.Web.Mvc.HtmlHelper<TModel>, System.Linq.Expressions.Expression<System.Func<TModel,TValue>>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
I've tried all different types of combinations/permutations, and nothing works. I feel like I'm almost there, but keep coming up short.

Can someone give me any pointers on how to get this to work? I'd really appreciate it, as developing a solid understanding of how to implement Shapes and Templates is a big deal for me.
Coordinator
Jan 8, 2014 at 7:24 AM
That's a lot of code. Can you simplify the question?
Jan 8, 2014 at 9:57 AM
Html.LabelFor needs a function as argument. Since you are using a template for a shape, as fas as I know, you can't make a @model declaration. So what you can do is to lose the @model type declaration in the template, instead have a code block something like:

@{
CourseDefinitionViewModel vm = Model.CourseDefinitionViewModel; // Model is CourseDefinition shape here
}

after @using statement, and replace Html.LabelFor (and other Html....For calls) to this:

@Html.LabelFor(model => vm.CourseName, T("Course Name))

This should solve this problem. However you would probably need to tweek so that form post will be successful, since form input tags will probably be named differently as opposed to the case you use a @model declaration and model => model.CourseName function to Html.EditorFor calls.


Jan 8, 2014 at 5:06 PM
@BertrandLeRoy - Yes, it's a lot. Sorry. It was late and I was thinking it might be too much, but was too tired to worry about it.

@kassobasi - Thanks! I'm almost there. The form shows up perfectly now. But I'm running into the issue with posting it back properly. How does it need to be formatted so that the data is posted back to the controller properly? I'm not getting the data, and when I look at the raw source, the input Names and Ids are now prefixed with 'vm_' or 'vm.'.

I'm also curious, besides getting a specific answer to this question, what resources I may be able to look at that can give me a better understanding of what is happening and how to resolve these kinds of issues. I really want to develop a competency at this stuff, and digging into resources (like Bertrand's blog posts on the origins of Clay, for instance!) that help me lay a solid foundation will be a great help.

Thanks for the assist on this. I was close before, but hadn't quite put the pieces together the way you explain it above.
Jan 9, 2014 at 4:05 PM

This is about ASP.NET MVC model binding, how the form elements and request parameterse are matched to parameters of an action method of a controller, it's not Orchard specific. I don't know enough about it to explain, but there are lots of resources online explaining how it works.


8 Oca 2014 19:07 tarihinde "GregoryHill" <[email removed]> yazdı:

From: GregoryHill

@BertrandLeRoy - Yes, it's a lot. Sorry. It was late and I was thinking it might be too much, but was too tired to worry about it.

@kassobasi - Thanks! I'm almost there. The form shows up perfectly now. But I'm running into the issue with posting it back properly. How does it need to be formatted so that the data is posted back to the controller properly? I'm not getting the data, and when I look at the raw source, the input Names and Ids are now prefixed with 'vm_' or 'vm.'.

I'm also curious, besides getting a specific answer to this question, what resources I may be able to look at that can give me a better understanding of what is happening and how to resolve these kinds of issues. I really want to develop a competency at this stuff, and digging into resources (like Bertrand's blog posts on the origins of Clay, for instance!) that help me lay a solid foundation will be a great help.

Thanks for the assist on this. I was close before, but hadn't quite put the pieces together the way you explain it above.

Read the full discussion online.

To add a post to this discussion, reply to this email ([email removed])

To start a new discussion for this project, email [email removed]

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com