Hit Highlighting using Search Display Templates in SharePoint 2013

SharePoint 2013 introduces the concept of Display Templates, specifically for search based web parts. This replaces the need to make use of XSLT to modify the way search results appear. However, one of the challenges I faced with a client is the ability to show the key terms in a record that caused it to show in the results. Following the limited guidance and several blog posts, I was able to create my own display template for an external content type.

<body>
	<script>
		$includeCSS(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Search/portalsearch.css");
	</script>
    <div id="Portal_External_Data">
<!--#_ 
        if(!$isNull(ctx.CurrentItem) && !$isNull(ctx.ClientControl)){
            var id = ctx.ClientControl.get_nextUniqueId();
            var itemId = id + Srch.U.Ids.item;
			var hoverId = id + Srch.U.Ids.hover;
			var hoverUrl = "~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_ExternalData_HoverPanel.js";
            $setResultItem(itemId, ctx.CurrentItem);
			if(ctx.CurrentItem.IsContainer){
				ctx.CurrentItem.csr_Icon = Srch.U.getFolderIconUrl();
			}
			ctx.currentItem_ShowHoverPanelCallback = Srch.U.getShowHoverPanelCallback(itemId, hoverId, hoverUrl);
            ctx.currentItem_HideHoverPanelCallback = Srch.U.getHideHoverPanelCallback();
            
            var activeClass = "portal-search-result-active";
            if(!$isEmptyString(ctx.CurrentItem.PortalActiveFlagCode)) {
            	if(ctx.CurrentItem.PortalActiveFlagCode.toLowerCase() == 'no'){
            		activeClass = "portal-search-result-inactive";
            	}
            };
_#-->
            <div id="_#= $htmlEncode(itemId) =#_" name="Item" data-displaytemplate="PortalExternalData" class="ms-srch-item" onmouseover="_#= ctx.currentItem_ShowHoverPanelCallback =#_" onmouseout="_#= ctx.currentItem_HideHoverPanelCallback =#_">
				<div class="portal-search-result portal-search-facility _#= activeClass =#_" title="Entity ID: _#= ctx.CurrentItem.PortalEntityCode =#_">
					<h1 class="portal-search-result-title">_#= ctx.CurrentItem.Title =#_</h1>
					<div class="portal-search-result-panel">
					<!-- ... -->				
					</div>
					<div class="portal-search-result-link"><a href="_#= ctx.CurrentItem.Path =#_">View Profile</a></div>
                </div>

                <div id="_#= $htmlEncode(hoverId) =#_" class="ms-srch-hover-outerContainer"></div>
            </div>
<!--#_ 
        } 
_#-->
    </div>
</body>

This produced a very nice change to the default item in my search results, but there was no indication in the record what term(s) were causing the record to appear in the results. So I began looking into the various display templates provided out of the box to see how Microsoft did this. The first display template I investigated was the item_discussion.html display template (remember, do not modify the JavaScript file since SharePoint will create this automatically when you save the HTML file). This is a pretty complex template so it was a bit difficult to see where the highlighting was utilized. The next one I investigated was the item_person.html display template. This template made it pretty easy to see how Microsoft was handling hit highlighting.

The first thing I found related to hit highlighting is on line 26 of the template:

var hhProps = Srch.U.createXMLDocument("<root>" + ctx.CurrentItem.HitHighlightedProperties + "</root>");

The Srch.U.createXMLDocument(string) creates an XML Document that is later used by another utility function attached to the Srch.U object. Around line 76 this utility function is used with the hhProps variable created above:

var encodedJtitle = $htmlEncode(ctx.CurrentItem.JobTitle);
var displayJtitle = Srch.U.getSingleHHXMLNodeValue(hhProps, "jobtitle");
if ($isEmptyString(displayJtitle)) { displayJtitle = encodedJtitle }

The Srch.U.getSingleHHXMLNodeValue(xmlDoc, nodeName) parses the XML document containing hit highlighted properties and returns a HTML Fragment with the highlighted term wrapped in a strong tag. The tag is assigned the css class ms-srch-item-highlightedText. If the term is not found in the property, only the text is returned. If the property doesn’t exist in the XML document, an empty string is returned.

Using this knowledge, I was able to highlight the terms in search results with a template similar to the following:

<body>
	<script>
		$includeCSS(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Search/portalsearch.css");
	</script>
    <div id="Portal_External_Data">
<!--#_ 
        if(!$isNull(ctx.CurrentItem) && !$isNull(ctx.ClientControl)){
            var id = ctx.ClientControl.get_nextUniqueId();
            var itemId = id + Srch.U.Ids.item;
			var hoverId = id + Srch.U.Ids.hover;
			var hoverUrl = "~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_ExternalData_HoverPanel.js";
            $setResultItem(itemId, ctx.CurrentItem);
			if(ctx.CurrentItem.IsContainer){
				ctx.CurrentItem.csr_Icon = Srch.U.getFolderIconUrl();
			}
			ctx.currentItem_ShowHoverPanelCallback = Srch.U.getShowHoverPanelCallback(itemId, hoverId, hoverUrl);
            ctx.currentItem_HideHoverPanelCallback = Srch.U.getHideHoverPanelCallback();
            
            var activeClass = "portal-search-result-active";
            if(!$isEmptyString(ctx.CurrentItem.PortalActiveFlagCode)) {
            	if(ctx.CurrentItem.PortalActiveFlagCode.toLowerCase() == 'no'){
            		activeClass = "portal-search-result-inactive";
            	}
            };
            
            var hhProps = Srch.U.createXMLDocument("<root>" + ctx.CurrentItem.HitHighlightedProperties + "</root>");

			var currentLabel = "", currentVal = "", currentCSS = "portal-search-result-datapoint";
_#-->
            <div id="_#= $htmlEncode(itemId) =#_" name="Item" data-displaytemplate="PortalExternalData" class="ms-srch-item" onmouseover="_#= ctx.currentItem_ShowHoverPanelCallback =#_" onmouseout="_#= ctx.currentItem_HideHoverPanelCallback =#_">
				<div class="portal-search-result portal-search-facility _#= activeClass =#_" title="Entity ID: _#= ctx.CurrentItem.PortalEntityCode =#_">
					<!--#_
						var currentVal = Srch.U.getSingleHHXMLNodeValue(hhProps, "HHTitle");
				
						if($isEmptyString(currentVal)) {
							currentVal = $htmlEncode(ctx.CurrentItem.Title);
						}			
					_#-->
					<h1 class="portal-search-result-title">_#= currentVal =#_</h1>
					<div class="portal-search-result-panel">
					<!--#_
						var currentLabel = "Complex";
						var currentVal = Srch.U.getSingleHHXMLNodeValue(hhProps, "portalcomplexname");
						var currentCSS = "portal-search-result-datapoint";
				
						if($isEmptyString(currentVal)) {
							currentVal = $htmlEncode(ctx.CurrentItem.PortalComplexName);
						}			
						if(currentVal.indexOf("ms-srch-item-highlightedText") > 0){
							currentCSS = currentCSS + " portal-search-result-datapoint-highlight";
						}
					_#-->
					    <span class="_#= currentCSS =#_"><span class="portal-search-result-label">_#= currentLabel =#_</span> _#= currentVal =#_</span>
					<!-- ... -->						
					</div>
					<div class="portal-search-result-link"><a href="_#= ctx.CurrentItem.Path =#_">View Profile</a></div>
                </div>

                <div id="_#= $htmlEncode(hoverId) =#_" class="ms-srch-hover-outerContainer"></div>
            </div>
<!--#_ 
        } 
_#-->
    </div>
</body>

There appears to be a lot of functionality attached to the Srch.U object, but using it requires a lot of trial and error right now. Hopefully, Microsoft will release some updated documentation that includes this object (along with a lot of other missing objects in the JavaScript object model). If you have resources you’ve found, I would love for you to post that in the comments of this article for everyone’s benefit!

Advertisements

4 thoughts on “Hit Highlighting using Search Display Templates in SharePoint 2013

  1. Hey Chris,
    I’m a UI designer/developer and wanted to know if there was a way to have the hit highlighting show in the hover panel content AND the detail page?
    I customized the hover to show the description of the item as it was lengthy. The content is pulled from a database, not a list.

    1. The focus of this post is to show how to include hit highlighted results. The way those look is entirely up to CSS and the HTML structure applied. For this scenario, the active CSS class simply provides a yellow background applied to a span tag containing the hit highlighted result. By default, SharePoint will automatically provide the matched hit highlighted item with bold text. So, the combination of the two results in a span tag containing a yellow background and the matched term in bold.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s