Using MVC - Display Templates Advanced Usage

JanL@kentico.com[email protected] Czech RepublicMember, Administrator, Kentico Staff admin
edited May 2017 in Back-end Development

This is a series of articles about using MVC, mainly in relation to Kentico Cloud. Let's highlight some of the MVC artifacts and patterns that are worth using!

Contents:

Advanced Usage of Display Templates

In the last part, we've shown that it is a good practice to invoke templates from within other templates. But, there are two exceptions:

  • When you don't want any escaping, encoding or any other transformation of the data
  • When there is no other template to call for

The first case can be demonstrated on HTML attributes. You should call:

<div class="@Model.ClassName" … />

… instead of …

<div class="@Html.DisplayFor(vm => vm.ClassName)" />

Also, the invocation of a template is not desirable in the last template in the invocation chain:

  • View
    • Template
      • Template

In the last template (often a template for a simple BCL type), you don't want to call:

@model string

<div>
    @Html.DisplayForModel()
</div>

… but …

@model string

<div>
    @ViewData.TemplateInfo.FormattedModelValue
</div>

Indirect Template Usage

You often want to render collections with for, foreach or other iterative constructs. But how do you reference the property in a foreach loop?

Rest easy, you can do the following:

@foreach (var item in collection)
{
    @Html.DisplayFor(vm => item.Property)
}

Even though the vm identifier of the view model is not used in the lambda body, MVC is still smart enough to pull the proper type and all the attributes off of the ModelMetadata object.

Parameterizing the Behavior of the Template

What if you wish the template to behave differently based on some parameter value? The default Display, DisplayFor and DisplayForModel methods are not meant to be overridden to support that.

You can use the additionalViewData parameter for that. You can pass an anonymous object with whatever properties in it:

@Html.DisplayFor(vm => vm.CompanyCafes, new { ShowImage = true })

In the template file, you can check for that parameter and alter the view accordingly:

@if (ViewData.ContainsKey("ShowImage") && (bool)ViewData["ShowImage"])
{
    <div class="cafe-image-tile-image-wrapper" style="background-image:url('@Model.Photo.First().Url'); background-size: cover; background-position: right center;"></div>
}

If you wish to form a contract or a signature to such a parametrized behavior, you can have your custom helper method:

@Html.DateTimeFormattedFor(vm => vm.PostDate, "D")

The code of such a method would be:

public static MvcHtmlString DateTimeFormattedFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, string format)
{
    if (expression.ReturnType != typeof(DateTime?) && expression.ReturnType != typeof(DateTime))
    {
        return MvcHtmlString.Empty;
    }

    return htmlHelper.DisplayFor(expression, "DateTime", new { FormatCharacter = format });
}

Wrapping Up

In this part, you've learned that there are exceptions from the general rule of nesting templates and you now know what to put into the template body. You also know how easy it is to use templates in loops. And finally, you know both the basic and advanced methods of parametrizing the behavior of templates.

Now, it's your turn. What do you think of the recommendations and the examples? Let us know!

In the part 5, we'll post another part describing how to use templates with Kentico Cloud specifically. Enjoy!

Tagged:
Sign In or Register to comment.