Monday, June 2, 2014

Create SharePoint 2013 Item Display Template overriding RenderBody

This is the second post of a series of blog posts on SharePoint 2013 search display templates.
I’ve given an introduction on Display Templates in previous post, Where I mentioned different types and their relationships. In this post I’ll discuss on Item Display Templates.
If we navigate to the mapped network drive for Display Templates (“<Site URL>_catalogs/masterpage/Display Templates/Search”) we can find available Display Templates.  Let’s take Item_Word.html file as the example.
image
As shown in above diagram, Item Display Template has following main areas
1. Title
This is the title of the Display Template which will be shown in the settings area of the web part.
2. CustomDocumentProperies
This contains some properties about the Display Template itself. Most important of them is the ManagedPropertyMapping section. Within that section we can include any managed property those are accessed within the Item Display Template.
3. RenderBody (ctx)
As you can see from the diagram, “ctx” object is filled with data (e.g.: Icon, HoverUrl, etc..). Then we will call the RenderBody method which will call Item_CommonItem_Body template to generate the search result item.
By using above facts we can create our own Display Templates. As an example we will use following scenario.
Below is an out of the box search web part. We will create a new Display Template just to remove the path component
image
We need to follow the steps given below.
1. Create new template based on existing item template (e.g.: Item_Word)
image
2.Open the Item_Contoso.html and change Titles accordingly
image
3. Test the Display Template with a web part
image
It is working as expected. Now we need to customize the template.
Creating a “Result Type” is not mandatory as we want this Display Template to be available on this web part only.
4. Override RenderBody (ctx)
Since I need to remove the path (URL component displayed in green color) from our web part, I have two options to consider
  • Remove the managed property “Path” from our template
  • Remove the HTML component that renders the path.
Since managed property “Path” is referred by other places, it is not the best practice to remove it. So I will remove the HTML component that renders the path. How can I find the source of that HTML?
As I mentioned in my earlier post, when a Display Template calls RenderBody method it will call Item_CommonItem_Body template. The rendering part happens there. But can we directly modify that template according to our requirement?
It’s not the correct approach as that template is referred by all Item Display Templates. Instead I will copy necessary code segment from Item_CommonItem_Body template and insert that in our template
image
5. Find the code that renders the path and remove that component
Following is the code that renders the path.
image
We will remove _#= truncatedUrl =#_ element and save the template. If we need we can do necessary modifications as well. Final result looks like below
image
Following is the final Display Template
  1. <html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882">
  2.   <head>
  3.     <title>Contoso Item</title>
  4.  
  5.     <!--[if gte mso 9]><xml>
  6. <mso:CustomDocumentProperties>
  7. <mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden>
  8. <mso:MasterPageDescription msdt:dt="string">Displays a result tailored for a Microsoft Word document.</mso:MasterPageDescription>
  9. <mso:ContentTypeId msdt:dt="string">0x0101002039C03B61C64EC4A04F5361F385106603</mso:ContentTypeId>
  10. <mso:TargetControlType msdt:dt="string">;#SearchResults;#</mso:TargetControlType>
  11. <mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
  12. <mso:ManagedPropertyMapping msdt:dt="string">'Title':'Title','Path':'Path','Description':'Description','EditorOWSUSER':'EditorOWSUSER','LastModifiedTime':'LastModifiedTime','CollapsingStatus':'CollapsingStatus','DocId':'DocId','HitHighlightedSummary':'HitHighlightedSummary','HitHighlightedProperties':'HitHighlightedProperties','FileExtension':'FileExtension','ViewsLifeTime':'ViewsLifeTime','ParentLink':'ParentLink','FileType':'FileType','IsContainer':'IsContainer','SecondaryFileExtension':'SecondaryFileExtension','DisplayAuthor':'DisplayAuthor','ServerRedirectedURL':'ServerRedirectedURL','SectionNames':'SectionNames','SectionIndexes':'SectionIndexes','ServerRedirectedEmbedURL':'ServerRedirectedEmbedURL','ServerRedirectedPreviewURL':'ServerRedirectedPreviewURL'</mso:ManagedPropertyMapping>
  13. <mso:HtmlDesignConversionSucceeded msdt:dt="string">True</mso:HtmlDesignConversionSucceeded>
  14. <mso:HtmlDesignStatusAndPreview msdt:dt="string">http://sp13:8080/sites/4750/_catalogs/masterpage/Display%20Templates/Search/Item_Contoso.html, Conversion successful.</mso:HtmlDesignStatusAndPreview>
  15. </mso:CustomDocumentProperties>
  16. </xml><![endif]-->
  17.   </head>
  18.   <body>
  19.     <div id="Item_Contoso">
  20.       <!--#_
  21.         if(!$isNull(ctx.CurrentItem) && !$isNull(ctx.ClientControl)){
  22.             var id = ctx.ClientControl.get_nextUniqueId();
  23.             var itemId = id + Srch.U.Ids.item;
  24.             var hoverId = id + Srch.U.Ids.hover;
  25.             var hoverUrl = "~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_Word_HoverPanel.js";
  26.             $setResultItem(itemId, ctx.CurrentItem);
  27.             ctx.CurrentItem.csr_Icon = Srch.U.getIconUrlByFileExtension(ctx.CurrentItem);
  28.             ctx.CurrentItem.csr_OpenApp = "word";
  29.             ctx.currentItem_ShowHoverPanelCallback = Srch.U.getShowHoverPanelCallback(itemId, hoverId, hoverUrl);
  30.             ctx.currentItem_HideHoverPanelCallback = Srch.U.getHideHoverPanelCallback();
  31. _#-->
  32.       <div id="_#= $htmlEncode(itemId) =#_" name="Item" data-displaytemplate="ContosoItem" style="padding: 0; margin: 0;" class="ms-srch-item" onmouseover="_#= ctx.currentItem_ShowHoverPanelCallback =#_" onmouseout="_#= ctx.currentItem_HideHoverPanelCallback =#_">
  33.  
  34.         <!--#_
  35.         var id = ctx.CurrentItem.csr_id;
  36.         var title = Srch.U.getHighlightedProperty(id, ctx.CurrentItem, "Title");
  37.         if ($isEmptyString(title)) {title = $htmlEncode(ctx.CurrentItem.Title)}
  38.         var appAttribs = "";
  39.         if (!$isEmptyString(ctx.CurrentItem.csr_OpenApp)) { appAttribs += "openApp=\"" + $htmlEncode(ctx.CurrentItem.csr_OpenApp) + "\"" };
  40.         if (!$isEmptyString(ctx.CurrentItem.csr_OpenControl)) { appAttribs += " openControl=\"" + $htmlEncode(ctx.CurrentItem.csr_OpenControl) + "\"" };
  41.         var showHoverPanelCallback = ctx.currentItem_ShowHoverPanelCallback;
  42.         if (Srch.U.n(showHoverPanelCallback)) {
  43.             var itemId = id + Srch.U.Ids.item;
  44.             var hoverId = id + Srch.U.Ids.hover;
  45.             var hoverUrl = "~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_Default_HoverPanel.js";
  46.             showHoverPanelCallback = Srch.U.getShowHoverPanelCallback(itemId, hoverId, hoverUrl);
  47.         }
  48.         var displayPath = Srch.U.getHighlightedProperty(id, ctx.CurrentItem, "Path");
  49.         if ($isEmptyString(displayPath)) {displayPath = $htmlEncode(ctx.CurrentItem.Path)}
  50.         var url = ctx.CurrentItem.csr_Path;
  51.         if($isEmptyString(url)){
  52.             var useWACUrl = !$isEmptyString(ctx.CurrentItem.ServerRedirectedURL);
  53.             if(ctx.ScriptApplicationManager && ctx.ScriptApplicationManager.states){
  54.                 useWACUrl = (useWACUrl && !ctx.ScriptApplicationManager.states.openDocumentsInClient);
  55.             }
  56.             if(useWACUrl)
  57.             {
  58.                 url = ctx.CurrentItem.ServerRedirectedURL;
  59.             } else {
  60.                 url = ctx.CurrentItem.Path;
  61.             }        
  62.         }
  63.         ctx.CurrentItem.csr_Path = url;
  64.         var pathLength = ctx.CurrentItem.csr_PathLength;
  65.         if(!pathLength) {pathLength = Srch.U.pathTruncationLength}
  66.  
  67.         var maxTitleLengthInChars = Srch.U.titleTruncationLength;
  68.         var termsToUse = 2;
  69.         if(ctx.CurrentItem.csr_PreviewImage != null)
  70.         {
  71.             maxTitleLengthInChars = Srch.U.titleTruncationLengthWithPreview;
  72.             termsToUse = 1;
  73.         }
  74.  
  75.         var clickType = ctx.CurrentItem.csr_ClickType;
  76.         if(!clickType) {clickType = "Result"}        
  77. _#-->
  78.         <div id="_#= $htmlEncode(id + Srch.U.Ids.body) =#_" class="ms-srch-item-body" onclick="_#= showHoverPanelCallback =#_">
  79.           <!--#_
  80.             if (!$isEmptyString(ctx.CurrentItem.csr_Icon)) {
  81. _#-->
  82.           <div class="ms-srch-item-icon">
  83.             <img id="_#= $htmlEncode(id + Srch.U.Ids.icon) =#_" onload="this.style.display='inline'" src="_#= $urlHtmlEncode(ctx.CurrentItem.csr_Icon) =#_" />
  84.           </div>
  85.           <!--#_
  86.             }
  87.             var titleHtml = String.format('<a clicktype="{0}" id="{1}" href="{2}" class="ms-srch-item-link" title="{3}" onfocus="{4}" {5}>{6}</a>',
  88.                                           $htmlEncode(clickType), $htmlEncode(id + Srch.U.Ids.titleLink), $urlHtmlEncode(url), $htmlEncode(ctx.CurrentItem.Title),
  89.                                           showHoverPanelCallback, appAttribs, Srch.U.trimTitle(title, maxTitleLengthInChars, termsToUse));
  90. _#-->
  91.           <div id="_#= $htmlEncode(id + Srch.U.Ids.title) =#_" class="ms-srch-item-title">
  92.             <h3 class="ms-srch-ellipsis">
  93.               _#= titleHtml =#_
  94.             </h3>
  95.           </div>
  96.           <!--#_
  97.             if (!$isEmptyString(ctx.CurrentItem.HitHighlightedSummary)) {
  98. _#-->
  99.           <div id="_#= $htmlEncode(id + Srch.U.Ids.summary) =#_" class="ms-srch-item-summary">_#= Srch.U.processHHXML(ctx.CurrentItem.HitHighlightedSummary) =#_</div>
  100.           <!--#_
  101.             }
  102.             var truncatedUrl = Srch.U.truncateHighlightedUrl(displayPath, pathLength);
  103. _#-->
  104.           <div id="_#= $htmlEncode(id + Srch.U.Ids.path) =#_" tabindex="0" class="ms-srch-item-path" title="_#= $htmlEncode(ctx.CurrentItem.Path) =#_" onblur="Srch.U.restorePath(this, '_#= $scriptEncode(truncatedUrl) =#_', '_#= $scriptEncode(ctx.CurrentItem.Path) =#_')" onclick="Srch.U.selectPath('_#= $scriptEncode(ctx.CurrentItem.Path) =#_', this)" onkeydown="Srch.U.setPath(event, this, '_#= $scriptEncode(ctx.CurrentItem.Path) =#_', '_#= $scriptEncode(truncatedUrl) =#_')" >
  105.  
  106.           </div>
  107.         </div>
  108.         <!--#_
  109.         if (!$isEmptyString(ctx.CurrentItem.csr_PreviewImage))
  110.         {
  111.             var altText = Srch.Res.item_Alt_Preview;
  112.             if(!$isEmptyString(ctx.CurrentItem.csr_PreviewImageAltText)){
  113.                 altText = ctx.CurrentItem.csr_PreviewImageAltText;
  114.             }
  115.  
  116.             var onloadJS = "var container = $get('" + $scriptEncode(id + Srch.U.Ids.preview) + "'); if(container){container.style.display = 'inline-block';}" +
  117.                            "var path = $get('" + $scriptEncode(id + Srch.U.Ids.path) + "'); if (path) { Srch.U.ensureCSSClassNameExist(path, 'ms-srch-item-preview-path');}" +
  118.                            "var body = $get('" + $scriptEncode(id + Srch.U.Ids.body) + "'); if (body) { Srch.U.ensureCSSClassNameExist(body, 'ms-srch-item-summaryPreview');}";
  119.  
  120.             var previewHtml = String.format('<a clicktype="{0}" href="{1}" class="ms-srch-item-previewLink" {2}><img class="ms-srch-item-preview" src="{3}" alt="{4}" onload="{5}" /></a>',
  121.                                         $htmlEncode(clickType), $urlHtmlEncode(url), appAttribs, $urlHtmlEncode(ctx.CurrentItem.csr_PreviewImage), $htmlEncode(altText), onloadJS);
  122. _#-->
  123.           <div id="_#= $htmlEncode(id + Srch.U.Ids.preview) =#_"class="ms-srch-item-previewContainer">
  124.           _#= previewHtml =#_
  125.         </div>
  126.         <!--#_
  127.         }
  128. _#-->
  129.  
  130.  
  131.  
  132.  
  133.         <div id="_#= $htmlEncode(hoverId) =#_" class="ms-srch-hover-outerContainer"></div>
  134.       </div>
  135.       <!--#_
  136.         }
  137. _#-->
  138.     </div>
  139.   </body>
  140. </html>
That’s all we need to do.

12 comments:

Unknown said...

Really useful - thank you.

Brum said...

Thank you for showing this!

Unknown said...

Thank you very much. This helped me a lot!

Enrique Sánchez said...

Thank you very much.

Radu Chirila said...

Fabulous article. Thanks!

Unknown said...

Well done...

Unknown said...

Outstanding! What a wonderful content you've written on SharePoint.Thank you so much for sharing your knowlege on SharePoint Developer with us. Please keep sharing such as great content in future.

PeffvonBremch said...

Thanks for this solution.
But after removing the path, there's too much space between the elements.
How can I remove that white space?

Jakob Flygare said...

When I follow your instructions I get an error:
'class' is an unexpected token. Expecting white space. Line 139, position 65..

siva said...


sharepoint is a web based collaborative platform
.it is basically an intranet and content management system
you can get more information at sharepoint online training.Read More At sharepoint online course

svrtechnologies said...

Pretty article! I found some useful information in your blog, it was awesome to read, sharepoint training thanks for sharing this great content to my vision, keep sharing...

Peter Johnson said...

Highly informative article. This site has lots of information and it is useful for us.Thanks for sharing Signova Group