Skip to content
This repository has been archived by the owner on May 30, 2022. It is now read-only.

Handlebar Renderings

David San Filippo edited this page Sep 14, 2017 · 3 revisions

Background

On the back end, ASF wraps Sitecore Items with dynamic objects which are bound to Handlebar templates using Handlebars.Net. If you’re looking to extend the binding process, review the documentation on this framework here. https://github.com/rexm/Handlebars.Net

Please note that the newest implementation of Handlebars uses a proxy and only calls the field renderer and other properties when encountered in a template. As a result, these components perform very well. Previous Versions used a dictionary that mapped fields from the object and were much slower. As a result using Handlebar Components are highly recommended.

For full syntax of Handlebars, you can review any Handlebars tutorial, such as the main one located on the JS version of the framework: http://handlebarsjs.com/

Handlebar Advantages

I highly recommend using these components for several reasons:

  • Appear as Regular components to Content Authors
  • Can be built quicker than traditional components
  • Can be tweaked with Variations Very Easily
  • Can be bound to Similar Data Sources Easily
  • Can be AB Tested and Personalized at both Data Source and Template Level

The Containers

There are 3 main Sitecore Data Source Containers:

  • Handlebar Container – Just maps fields of Sitecore Item to Expando Object for binding
  • Handlebar Collection – Will map selected Items and their referenced children (up to 3 levels deep only) to an Expando Item. Collection is addressable by “Items” key word
  • Handlebar Query – Will use a Sitecore query to fetch items to be bound. Collection is addressable by “Items” key word

There are two other containers that can bind to other kinds of data:

  • Facet Container - Allows you to bind to any facet (OOB or Custom) to easily surface facet data.
  • There is also a JSON Rest Container that can bind any restful “get” url that you configure it to a template.

Syntactic Sugar Each Field Can be Accessed through the Dynamic Object. The rendered value of the field will go through the standard Sitecore Editor. This enables the Experience editor to work properly in edit mode. To make things more powerful, we’ve automatically added additional properties based on the field type to enable more complex layouts. These include:

  • IsPageEditorEditing – This is added to the top of every collection and item and can be used with an if statement to inject markup that only targets page editor.
  • ItemUrl – Every Item will have this to point to the web url of the item.
  • ItemId – The Guid that represents the item

Additionally depending on Field Type we add helper properties on the fly:

  • Multilist Fields (Treelist, etc also included)

    • Children are added to the field name
    • FieldName_Count – Returns number of items in the list.
  • Droplink, DropTree, Grouped Drop Link

    • Referenced Item is added to the field name
  • LinkField

    • FieldName_Url – returns friendly url stored in the field
    • FieldName_Text – returns the test description of the link field
  • ImageField

    • FieldName_Src – returns the raw Media Library url
    • FieldName_Alt – Returns the configured Alt Text for the Media Item
  • Date, DateTime (DateField)

    • FieldName_ShortDate – returns the date formatted ToShortDateString
    • FieldName_LongDate – returns the date formatted ToLongDateString
  • All Fields

    • FieldName_Value – Returns the actual raw Field.Value, useful when you need to bypass the field renderer and pass to custom helpers. 

Helpers Handlebars .Net allows you to register custom helpers. We have created a pipeline where you can register any custom helpers you want and provided implementations for an ifEqual block helper and a formatDate helper. They are registered in the custom pipeline in the Handlebars.config file.

Placeholder Yes, You can Now Embed Placeholders in your templates, meaning there is very little you can't do in a handlebar template.

<div class="row">
<div class="col-md-6">
{{{ placeholder 'AirspaceLeft' }}}
</div>
<div class="col-md-6">
{{{ placeholder 'AirspaceRight' }}}
</div>
</div>

ifEqual Pass it two properties (one can be a property of the context Item). Note this is a Block Helper, as compared to the otehr which is a normal helper.

{{#ifEqual 'test' 'test2'}}
They are equal
{{else}}
They are not equal
{{/ifEqual}}

formatDate
Parses first value as date then formats to String with second param {{ formatDate Date_Value 'MM/yyyy' }}

Query Container Filters

To make search more flexible and powerful, we’ve added a few syntactic helpers when setting field filters on the Handlebar Query container including:

  • Negation – Prefix the value with ! if you want the filter to say “not equal to” instead of the default equal to.
  • Match the ID of Sitecore Context Item – Use a value of $ID if you want a field on the template to match the ID of the current page
  • Match a value of a field on the Context Item. Use a value of $ followed by the field name to compare a field on the bound item to a field on the page Item.

Sample Templates

Single Item:

<div class="blog-post">
<h1>{{{Title}}} <small>{{Date_ShortDate}}</small></h1>
<div class="thumbnail">{{{Image}}}</div>
<div>{{{Summary}}}</div>
<div>{{{Content}}}</div>
<div class="panel callout">
<ul class="menu simple">
    <li><a href="#">Author: {{{Author.Name}}}</a></li>
</ul>
</div>
</div>

Simple List:

{{ #if IsPageEditorEditing }}
  <div>Experience Editor Mode</div>
{{ /if }}
{{ #each Items }}
  <div class="blog-post">
  {{ #if IsPageEditorEditing }}
    <h3>{{{Title}}} <small>{{Date_ShortDate}}</small></h3>
  {{else}}
    <h3><a href="{{ItemUrl}}">{{{Title}}}</a> <small>{{Date_ShortDate}}</small></h3>
  {{ /if }}
  <div class="thumbnail">{{{Image}}}</div>
  <div>{{{Summary}}}</div>
  <div class="panel"><small><a href="{{{ Author.ItemUrl }}}">by {{{Author.Name}}}</a><br />
  <a href="{{{ Category.ItemUrl }}}">Posted In {{{Category.Name}}}</a></small></div>
  </div>
{{ /each }}

Carousel:

<div class="owl-carousel owl-theme" data-options="{ &quot;singleItem&quot;:true,&quot;autoPlay&quot;:true,&quot;transitionStyle&quot;:&quot;fade&quot;}
{{ #each Items }}
  <div class="carousel-Item">
  <div class="row">
    <div class="large-5  small-5 medium-5 columns">{{{Image}}}</div>
    <div class="large-7  small-7 medium-7 columns">
    {{ #if IsPageEditorEditing }}
      <h3>{{{Title}}} <small>{{Date_ShortDate}}</small></h3>
    {{else}}
      <h3><a href="{{ItemUrl}}">{{{Title}}}</a> <small>{{Date_ShortDate}}</small></h3>
    {{ /if }}
    <div>{{{Summary}}}</div>
    <div class="panel"><small><a href="{{{ Author.ItemUrl }}}">by {{{Author.Name}}}</a><br />
    <a href="{{{ Category.ItemUrl }}}">Posted In {{{Category.Name}}}</a></small></div>
  </div>
  </div>
  </div>
{{ /each }}
</div>

Samples

For more examples of how to use handlebars, review the Blog Implementation of the StarterKit site and the Airspace Sample microsite implementation. Both make extensive use of handlebars, including defining custom page templates with default page configurations on their standard values.

Closing Thoughts

While you can bind to independent items with handlebar containers, the primary use case is to actually add semantic fields to your page templates themselves. This way you can query and display lists of contents on actual pages easily using handlebar templates. The query container and syntax helpers here were designed to help in configuring queries and templates on the standard values of a page template. Note that it may be prudent to include the supporting template and items in a branch template instead of a normal template if you can’t rely on global settings. As with any component, also carefully consider configuring Caching on the components. (Though it may be tricky if you have different templates within the same container data sources. Consider adding Custom Rendering Parameters and ensuring Cache by Parameters is enabled to force uniqueness).