Building ViewModels

Since the entire purpose of Constellation.Foundaiton.ModelMapping is to take Items and transfer their Field values to ViewModels, it’s critical to understand the field value mapping process. This page discusses the necessary Sitecore Data Template design and the field value options available.

What Are ViewModels?

ViewModels are small “plain old class objects”. In the Model View Controller design pattern  they are the Model passed to an MVC View. The Model needs to be as simple as possible and should not contain any information that is not directly needed by the View, whose sole job is to render the Model. We call them ViewModels because the MVC design pattern has a variant called MVVM (model, view, view-model) that explicitly differentiates between Business Objects (the first Model) and View Consumables (the ViewModel).

Creating ViewModels

There is no model generation included in this component. The purpose of Constellation ModelMapper is to push Item data into a ViewModel, which should be as simple as possible, and contain only the data needed by the View. Thus, you are expected to hand build your ViewModels.

The rules that govern the definition of ViewModels are straightforward:

  • ViewModels are your classes, there’s no base class to inherit.
  • Although ViewModels are implicitly designed to support Experience Editor, you should consider them one-way objects in code, they are not business entities. Changes to properties cannot be committed back to Sitecore in code.
  • ViewModels must have empty constructors.
  • Any Property on your Model that you want mapped from an Item Field needs to be public, and cannot be static.
  • Your properties need public Get and Set access.
  • As described below, the Property Name and the Item Field Name must match, without spaces or diacritics, in Title Case, as per the Microsoft style guide for public properties. No dashes or underscores between words.
  • the Type of the Property should be a valid destination type for the Field’s value.

Data Template Design

There are only a few special requirements for Data Templates with the ModelMapper. You can use human-legible names for all your fields and ModelMapper will do its best to match them to POCO properties. Note that your field names must resolve to C# compatible Property names if you remove all the spaces, diacritics, and non-word characters. Some rules I’ve discovered:

  • Field Name cannot match the Item Name, because this: Banner.Banner is illegal in C#.
  • No numbers up front.
  • No dashes or underscores between words.
  • Avoid leading underscores. These are reserved for Sitecore Standard Fields and are treated differently by ModelMapper.
  • ModelMapper will successfully convert this: “This is a Field Name” to this: ThisIsAFieldName

Supported Field Types

The following Sitecore Field Types are supported out of the box:

  • Checkbox
  • Date
  • DateTime
  • Number
  • Droplink
  • Droplist
  • Grouped Droplist
  • Droptree
  • File
  • Image
  • General Link
  • General Link with Search
  • Checklist
  • Multilist
  • Multilist with Search
  • Treelist
  • TreelistEx
  • Any of the “Text” fields (all are treated identically)

If a field type is not on this list, it will be treated as a Single Line Text field. it is possible to “teach” ModelMapper about other fields by providing your own Field and FieldAttribute mappers via the XML configuration. This is an advanced topic to be discussed later.

Field to Property Conversion

The easiest way to capture a Field’s value is to use a string property on your ViewModel.

By default, if you map any Field to a string property, the resulting output will call Field Renderer. Thus, to get an editable Image Field rendered on page, you only need to map the Image Field to a string property on your ViewModel.

There’s a side-effect to using the FieldRenderer. MVC will not render a Field Renderer output as a straight string like this: @ViewModel.StringProperty because the value of the property contains HTML. The Razor view engine with thoughtfully HtmlEncode() your string. You have two choices:

  1. Wrap your output as follows: @Html.Raw(ViewModel.StringProperty)
  2. Use an HtmlString as your property type: public HtmlString SomeFieldname {get; set;}

What about non-text types? Often, you’ll need a Field value to be something besides a string because you need to operate on the fact in some other way:

Simple Type Conversions

the following non-text value fields are supported:

  • Checkbox Field can be mapped to: bool
  • Date and DateTime Fields can be mapped to: DateTime
  • Number Fields can be mapped to: int or decimal

Note that if you map a Field to one of these simple types, you lose Experience Editor support for the field.

Mapping Fields that Reference other Items

Any field where the Value is a Sitecore ID or a pipe-delimited series of IDs can be considered to be a “reference” type field. The rules in this section apply to the following fields:

  • Droplink, DropTree, or any field where the raw value is an ID.
  • Multilist, Treelist, or any field where the raw value is a delimited set of IDs

Rather than having to get a Target Item (or Items) from a Field and then map them to a ViewModel, Constellation ModelMapper lets you skip the intermediate step.  you can simply specify the type of your Model’s property to match the type you want to use to map the Target Item(s). ModelMapper handles getting the targets, instantiating the new models, and mapping the values automatically.

Example:

Consider a Press Release item that contains a Droplink field called “Author” that references Author Items, each of which has a first and last name field.

The first step is to create an Author ViewModel:

public class Author
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

The next step is to create your Press Release ViewModel, setting the “Author” property’s Type to the ViewModel we created above:

public class PressRelease
{
    //...
    public Author Author { get; set; }
    //...
}

The power of this cannot be overstated. Using ModelMapper, you can “walk” a series of items that are chained together by reference fields. here’s an example of how terse this lets you code, without all the uninteresting Sitecore gymnastics:

FeaturedProductCta.Product.Category.DisplayName

In the example above, we have a FeaturedProductCta class that has a Product property mapped to a Product class, which contains a Category property mapped to a Category class, which has a DisplayName property.

Reference Field Rules

For single-ID fields, just set the Property’s type to the ViewModel type you want ModelMapper to create.

For multiple-ID fields, the property should be of type ICollection<T> where T is the Type of ViewModel you want to instantiate for every target Item.

Mapping Sitecore Item Properties

Outside of Item.Fields, there are a few essential Item properties that are useful to be able to include in your ViewModel. ModelMapper handles these automatically. The following properties will be populated on your ViewModel if they exist:

public string Name { get; set; }
public string DisplayName { get; set; }
public ID ID { get; set; }
public T Parent { get; set; }

Note that ModelMapper will look for a property named Parent, and will map the Item’s Parent Item to the specified ViewModel type.

Special Case: The Url ViewModel Property

If you include a property on your ViewModel like so: public string Url { get; set; } ModelMapper will call LinkManager and retrieve the URL for the Item according to the LinkManager’s context configuration.

It’s important to understand that the context under which the ViewModel is created can have an impact on the URL generated. Make sure you read Sitecore’s documentation on LinkManager to ensure you get the URL you’re expecting.