Display templates
are new in sharepoint 2013 replacing XSLT in 2010 which will be used to
customize the UI/display of the webparts. Like, we had item.xsl and control.xsl
back then, its same strategy in 2013 as well. Entire UI code for a webpart is
split into 2 different files, Control and item template. Control template will
have the markup that creates the base look/container/header section for the
webpart where as item template will have
the markup defined for each result/item displayed.
For every display
template(item/control) file(.html) uploaded to the master page gallery, a
respective js file will be generated if no syntax errors found. Publishing
features at site collection need to be activated so sharepoint could generate
those files.
To start with
creating a custom item template, copy any of the OOTB template and start
following its pattern and conventions. I have explained few notations to make
it easy for you and myself.
Ensure all the
changes are written inside the first div under the body of the template.
Sharepoint reads only the markup which is inside the first div(excluding div
element itself) while applying the item template to each item in the webpart.
I have copied part
of the code from item_picture3lines.html for better explanation. Here, the
first div is with id=item_picture3lines.
Id of the div can be changed but not the div element itself.
<body>
<div id="Item_Picture3Lines" >
<!--#_
var encodedId = $htmlEncode(ctx.ClientControl.get_nextUniqueId() + "_picture3Lines_");
var linkURL = $getItemValue(ctx, "Link URL");
linkURL.overrideValueRenderer($urlHtmlEncode);
...
...
_#-->
<div class="cbs-picture3LinesContainer" style="font-size:11px;" id="_#= containerId =#_" data-displaytemplate="_#= $htmlEncode(dataDisplayTemplateTitle) =#_">
...
…
</div>
</div> </body>
<div id="Item_Picture3Lines" >
<!--#_
var encodedId = $htmlEncode(ctx.ClientControl.get_nextUniqueId() + "_picture3Lines_");
var linkURL = $getItemValue(ctx, "Link URL");
linkURL.overrideValueRenderer($urlHtmlEncode);
...
...
_#-->
<div class="cbs-picture3LinesContainer" style="font-size:11px;" id="_#= containerId =#_" data-displaytemplate="_#= $htmlEncode(dataDisplayTemplateTitle) =#_">
...
…
</div>
</div> </body>
Scripting
Javascript/jquery
can be written by wrapping it with <!--#_ _#--> without explicit script tags.
So it's going to look like,
<!--#_
Var temp;
alert("calling script from display template");
_#-->
Var temp;
alert("calling script from display template");
_#-->
External js file can
be included by using the function,includeScript. First parameter is always
this.url
$includeScript(this.url,
"~sitecollection/_layouts/15/reputation.js");
Similarly external
CSS can be referenced using $includeCSS(this.url, "~sitecollection/site
library/custom.css");
Read here on how to
run the scripts after display template or complete DOM render($(document).ready())
Property Mappings
To add new
lines in content search webpart or do
property/managed metadata mapping in display template,
look for
mso:managedPropertyMapping in item template which is responsible for mapping
the columns to the variables in the display template and to show in the
toolpart.
<mso:ManagedPropertyMapping msdt:dt="string">'Link URL'{Link URL}:'Path','Line 1'{Line 1}:'Title','Line 2'{Line 2}:'Author','Line 3'{Line 3}:'ModifiedOWSDATE','FileExtension'</mso:ManagedPropertyMapping>
<mso:ManagedPropertyMapping msdt:dt="string">'Link URL'{Link URL}:'Path','Line 1'{Line 1}:'Title','Line 2'{Line 2}:'Author','Line 3'{Line 3}:'ModifiedOWSDATE','FileExtension'</mso:ManagedPropertyMapping>
'Link URL'{Link
URL}:'Path' defines single mapping for a managed metadata.
'Link URL'{Link URL}:'Path' - first token represents the label of the
property displayed in the toolpart under property mappings
'Link URL'{Link URL}:'Path' - second token represents the
display name of the variable reference to the actual managed metadata property.
This variable will be used in the display template to access the value.
'Link URL'{Link
URL}:'Path'
- last token is the actual name of the managed metadata that is used in
display template. This is not the display name of the column but the name of
the managed metadata property mapped to the crawled property in search schema.
In case of mapping
multiple metadata properties to a single display template property variable,
follow the below syntax
'Link URL'{Link
URL}:'Path;Url'
When no mapping
required but need to access the value of managed metadata inside display
template just add it in single quotes separated by comma like FileExtension is
added.
Context
Sharepoint by
default loads the context(ctx) as part of display template that can be used to
access many of the contextual properties when customizing display templates.
Access the value of
a mapped property by using getitemValue.
Var value = $getItemValue(ctx, "Line 2");
$getItemValue takes
the display name of the property(second token in parenthesis) as the second
parameter. This way code is generic and it still works even if the property
mapping is changed in webpart configuration. Also, if there are managed
metadata properties that need to be used(like listItemID,ItemID) that don’t
need to be listed in the property mappings, the value of it can be fetched by
directly passing the manage metadata property name as per search schema.
The above line of
code fetches Author value as {Line 2} is mapped to Author in the display
template. Below code also fetches the same value,
Var authorVal
= $getItemValue(ctx, "Author");
Few contextual
properties which can be fetched from context,
ctx.CurrentItem.ListItemID
ctx.CurrentItem.SPSiteUrl
To retrieve the
current item index or current row number
use the property CurrentItemIdx from ctx
object.
Var currentItemIndex
= ctx.CurrentItemIdx;
Get the row count or
total number of rows with,
Ctx.CurrentGroup.RowCount
Row count can be
used in the logic when to apply alternate css/styles to the rows, where as row
id to display any header section(table header)
for the entire webpart. Header section can be added to control display template
but if you don’t want to change 2 different files, just check for
currentitemidx=1 and add header section markup in the item template
itself. Note that these properties wont
work in control display template.
To find if the
results are empty inside control display template, I checked for DOM length being empty for div.ms-srch-result-noResults. Thought of using
if (ctx.ClientControl.get_shouldShowNoResultMessage()) but did not work
as expected. Yet to find a better approach.
Get the unique id by using ctx.ClientControl.get_nextUniqueId();
Get the unique id by using ctx.ClientControl.get_nextUniqueId();
Access values in markup
Display value of the
managed metadata property or a variable as part of the markup. Here authorVal
is the variable in the above script having the value of the managed metadata
property, Author.
<span>_#= authorVal =#_</span>