11

I have been following the guidance given in Katarina's blog post about using ViewModels in DD4T. However, in spite of the fact that she only uses @Html.Render(cp) in her examples, I was tempted to use other helper methods. In this example you can see that I tried to use RenderComponentPresentationsByView()

@model DD4T.Indi.Models.GeneralPageViewModel

@{
    ViewBag.Title = Model.Title;
}

<header class="header">

    @Html.RenderComponentPresentationsByView("Hero Message CT")
</header>

<div id="main" class="main-content" role="main">
    <div id="region-Main">
        @foreach (var cp in Model.ComponentPresentations.Where(c => c.RenderData.View == "ContentBlock"))
        {

            @Html.Render(cp)
        }

    </div>
</div>

Having gone off-piste like this, I rapidly ended up in trouble, with NullReferenceExceptions coming from an 'unknown module'. On more detailed examination, I realised that the code I was executing was in DD4T.Mvc.Html.TridionHelper, which is marked as [Obsolete("Consider changing to ViewModels and rendering them with the RenderHelper")]. As my ViewModel class did not implement IPage, this broke the expectations of the framework code.

So - it's now clear to me that when using ViewModels, I can and should use @Html.Render(cp), and that using RenderComponentPresentationsByView() is a bad idea - although presumably a good idea if you are using the old-skool approach.

I would like to know what strategy can I employ to determine which methods belong with which technique, and how I can avoid making similar mistakes (which are very time-consuming to analyse).

Further - what guidelines might represent good practice for this kind of work? For example, do people typically expose pre-filtered lists of component presentations from their model? I have succeeded in filtering in the razor view using a lambda expression, but what's the best way of doing this, and are there any known anti-patterns?

8

Dominic, it's indeed correct that, when you use the DD4T2 ViewModel approach, you should use the Html.Render helper function, and if you use the older models, you should use the Html.RenderComponentPresentationBy...() helper.

Regarding your question on "Do people typically expose pre-filtered lists of component presentations from their model", I have to say I do like the fact that in DD4T 2 I can create a page model with properties for different regions of component presentations.

For this, I extensively use the attributes PresentationsByView and PresentationsByRegion.

This allows me to create a page model like this

[PageViewModel(TemplateTitle = "MyPage")]
public class MyPage: ViewModelBase
{
    [PageTitle]
    public string PageTitle { get; set; }

    [PresentationsByRegion(Region = "Header")]
    public List<IRenderableViewModel> HeaderItems { get; set; }

    [PresentationsByRegion(Region = "Sidebar")]
    public List<IRenderableViewModel> SidebarItems{ get; set; }

    [PresentationsByRegion(Region = "Main")]
    public List<IRenderableViewModel> MainItems{ get; set; }

}

And this allows you to create a razor view where you don't need much logic

<header class="header">
        @foreach (var cp in Model.HeaderItems)
        {
            @Html.Render(cp)
        }
</header>

<div id="main" class="main-content" role="main">
    <div id="region-Main">
        @foreach (var cp in Model.MainItems)
        {
            @Html.Render(cp)
        }
    </div>
    <div id="side-bar">
        @foreach (var cp in Model.SidebarItems)
        {
            @Html.Render(cp)
        }
    </div>
</div>

I prefer this way of working instead of having one list with all component presentations in my page model, and having to add the filter logic in my razor view

  • Awesome example Harald. – Pankaj Gaur Jun 8 '16 at 4:52
  • Thanks Harald. Great answer. Since writing the question I'd also followed up on the PresentationsBy... attributes and it definitely looks like the way to go. – Dominic Cronin Jun 8 '16 at 6:39
5

My understanding of the differences are:

When using ViewModels you should use

@Html.Render(model)

Why?

It uses the standard MVC pipeline, resolving Action, Controller and View from the ViewModel and then passing control over to MVC to complete the request.

public static MvcHtmlString Render(this HtmlHelper htmlHelper, IRenderableViewModel viewModel)
{
   return htmlHelper.Action(viewModel.get_RenderData().get_Action(), viewModel.get_RenderData().get_Controller(), (object) new
   {
     model = viewModel,
     view = viewModel.get_RenderData().get_View()
   });
}

When not using ViewModels you should use one of the following depending on your requirements

@Html.RenderComponentPresentations()
@Html.RenderComponentPresentationsBySchema("SCHEMA_NAME")
@Html.RenderComponentPresentationsByView("VIEW_NAME")

Why?

This is a much more complex rendering (as far as I've followed into the guts of DD4T)

3

Very broad question, but if you are considering the DD4T 2.0, then the recommended best practice is to use the View-Model appraoch and use @Html.Rendermethod as explained with example in the Blog Post mentioned in the question. Having said that, this does not mean you can not use methods like @Html.RenderComponentPresentationByViewor may be a further complex overridden method for your specific need.

We have had specific implementation where there are significant logic implemented just to identify the View Name, and then passing it to @Html.RenderComponentPresentationByView to render the presentation - now changing all this to ViewModel thing is a quite a good effort, and considering the scenario, I may choose using the old-skool deprecated method.

In my opinion, if I am working with an older DD4T version (1.31 say), I would keep going with the old-skool way - @Html.RenderComponentPresentationByView for rendering the presentation and if I am with DD4T 2.0, then the View Model approach mentioned in the blog post in question makes most sense.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.