• Publisert
  • 2 min

Clean views with UIHints

Simple lists of label-value-pairs on information pages often result in cluttered views. Tidy those up drastically with some simple UIHint-magic.

In the web world we're often listing string-properties along with a label on our templates. Typically found on pages that represent single entities that has a predefined set of properties, like employees, stores, departments or products. Often, this results in loads of if-checking to avoid displaying a label that has no following value, which quickly kills the readability of our views. Utilizing the UIHintAttribute lets us simplify this greatly.

Our model might look something like this:

[ContentType(GUID = "...")]
public class PersonPage : PageData {
    public virtual string Name { get; }
    public virtual string PhoneNumber { get; }
    public virtual string Address { get; }	
}

And our display template for this section of the page, for instance PersonInfo.cshtml might look like this:

@if(Model.Name != null) {
    <li>
      <span class="label">
        @Html.Translate("/some/strings/name")
      </span>
      @Model.Name
    </li>
}

@if(Model.PhoneNumber != null) {
    <li>
      <span class="label">
        @Html.Translate("/some/strings/phonenumber")
      </span>
      @Model.PhoneNumber
    </li>
}

@if(Model.Address != null) {
    <li>
      <span class="label">
        @Html.Translate("/some/strings/address")
      </span>
      @Model.Address
    </li>
}

Ugly, hard to maintain, error prone, wastes space, repetitive. It just looks wrong.

What if your your view could look like below?

@Html.DisplayFor(x => x.Name)
@Html.DisplayFor(x => x.PhoneNumber)
@Html.DisplayFor(x => x.Address)

Annotate your properties with a nice UIHint, like so:


[ContentType]
public class PersonPage : PageData {
    [UIHint("MyFieldType")]
    public virtual string Name { get; }

    [UIHint("MyFieldType")]
    public virtual string PhoneNumber { get; }

    [UIHint("MyFieldType")]
    public virtual string Address { get; }	
}

Then create a display template (by default, put it in Views/Shared/DisplayTemplates/MyFieldType.cshtml - note that the file name equals the UIHint), like so:


@model string;

@if(Model != null) {
    return;
}

@{
    var propertyName = ViewData.TemplateInfo.HtmlFieldPrefix;
}

<li>
    <span class="label">
      @Html.Translate(string.Format("/contenttypes/icontentdata/properties/{0}/caption", propertyName))
    </span>
    @Model
</li>

Clean, easy to maintain, easy to debug, no wasted space, component reuse.

A big fat bonus is that the translated label on the page will be the same as what the editors see inside Episerver edit mode - giving consistency, ease of use for editors and forcing you to actually translate it properly.

Note: The property name we retrieve in the view will represent anything after the x in the DisplayFor expression, meaning that DisplayFor(x => x.CurrentPage.Address) will not work, as the propertyName will be CurrentPage.Address. Move your properties into a separate partial view, which gets x.CurrentPage as the model.

This is really just using built in functionality in ASP.NET/Razor, but it often seems forgotten, so I thought I'd throw this out there.