Showing posts with label Display templates. Show all posts
Showing posts with label Display templates. Show all posts

Thursday, November 13, 2014

Problem with updating managed properties in display templates used in Sharepoint search

Display templates are files with .html extension which are used for customizing appearance of the content in Sharepoint search results. When you upload such files to Site settings > Master page and page layouts > Display templates folder, Sharepoint automatically creates js version of display template, which is actually used by search engine. When you publish or delete basic html file, associated js file is published or deleted automatically.

The structure of most display templates looks like this:

   1: <html xmlns:mso="urn:schemas-microsoft-com:office:office"
   2: xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"> 
   3: <head>
   4: <title>Foo</title>
   5:  
   6: <!--[if gte mso 9]><xml>
   7: <mso:CustomDocumentProperties>
   8: <mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden>
   9: <mso:MasterPageDescription msdt:dt="string">Foo</mso:MasterPageDescription>
  10: <mso:ContentTypeId msdt:dt="string">...</mso:ContentTypeId>
  11: <mso:TargetControlType msdt:dt="string">;#SearchResults;#</mso:TargetControlType>
  12: <mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
  13: <mso:ManagedPropertyMapping msdt:dt="string">'Title':'Title','Path':'Path',
  14: 'Description':'Description','EditorOWSUSER':'EditorOWSUSER',
  15: 'LastModifiedTime':'LastModifiedTime','CollapsingStatus':'CollapsingStatus',
  16: 'DocId':'DocId','HitHighlightedSummary':'HitHighlightedSummary',
  17: 'HitHighlightedProperties':'HitHighlightedProperties',
  18: 'FileExtension':'FileExtension','ViewsLifeTime':'ViewsLifeTime',
  19: 'ParentLink':'ParentLink','FileType':'FileType','IsContainer':'IsContainer',
  20: 'SecondaryFileExtension':'SecondaryFileExtension','DisplayAuthor':'DisplayAuthor',
  21: 'SPSiteURL':'SPSiteURL',...</mso:ManagedPropertyMapping>
  22: </mso:CustomDocumentProperties>
  23: </xml><![endif]-->
  24: </head>
  25: <body>
  26:     <div id="Item_Foo">
  27:         ...
  28:     </div>
  29: </body>
  30: </html>

In the top area of the file metadata section is defined. Very important section is <mso:ManagedPropertyMapping>…</<mso:ManagedPropertyMapping>. It contains list of managed properties which can be used in the current display template. The actual look and feel template is defined inside topmost div tag (in example above it’s the div with id = “Item_Foo”).

During the lifetime of your application it may be needed to update existing display templates which are used in living site. If you only need to update look and feel part of template it won’t cause a lot of problems: just re-upload html file to the the location inside Site settings > Master page and page layouts > Display templates folder and publish it (depending on your settings you may also need to approve the file). But if you added new managed properties to <mso:ManagedPropertyMapping>…</<mso:ManagedPropertyMapping> section you may face with the problem that values of these properties will be always empty when you will try to use them inside display template.

This problem is caused by Sharepoint cache: it somehow caches mapped managed properties so deeply, that simple re-uploading and re-publishing doesn’t help (I tried also restart Sharepoint search and search host services and restart the server, but it didn’t help). In order to clear them from cache I found the following solution: delete original html file from Site settings > Master page and page layouts > Display templates, upload it from scratch and publish. If this display template was used in some search result types, you may also need to re-create this result type. After that try to search the content, for which updated display template should be used (Ctrl-F5 may be needed in browser as well): new managed properties should appear now.

Wednesday, February 26, 2014

How to use custom managed properties in display templates in Sharepoint 2013

When create a new display template for search results page or for Content by search web parts, you may need to use your own custom managed properties inside template. First of all you need to create these properties in Search service application and map it to some crawled property. After that it is possible to use it in display template. In order to do it you need to add new mapping to <mso:ManagedPropertyMapping>…</mso:ManagedPropertyMapping> tag inside display template:

<mso:ManagedPropertyMapping msdt:dt="string">'Link URL'{Link URL}:'Path','Line 1'{Line 1}:'Title','Foo'{Foo}:'Foo'</mso:ManagedPropertyMapping>

In this example we added new mapping for managed property Foo, so it will be possible to get value of this property inside display template like this:

   1:  var foo = $getItemValue(ctx, "Foo");

and then display it to end user. This technique will help you to use not only OTB managed properties like Title or Path, but also custom managed properties in display templates.

Tuesday, February 4, 2014

Localize datetimes in display templates in Content by search web parts in Sharepoint 2013

Display templates are plain html files which are used in Content by search web parts in Sharepoint 2013 for displaying information. In this post I will show how to localize datetimes using locale or language of current SPWeb.

The main problem with localization is that inside display templates you may use only javascript and client object model, but not server code. I.e. you can’t just write:

   1:  var ci = new CultureInfo(SPContext.Current.Web.Locale.LCID);
   2:  var date = ...;
   3:  var localizedDate = date.ToString(ci);

We need to do it on client side. If you will make investigation of what methods are available in javascript for dates localization you will find toLocaleString method of Date object. The problem that this method uses current client’s locale and doesn’t allow to pass specific LCID. It may be needed when current client’s locale and locale, which you want to use for dates localization, are not the same.

The good thing however is that MS ajax (which is available in SharePoint OTB) adds to Date localeFormat method, which allows to display datetime using specified format. The question is how to get datetime format for specific LCID on client side?

In order to do it I used the following way. There is useful standard global javascript object _spPageContextInfo, which contains many useful settings from server side which you may use on client side (see How to get URL of current site collection and other server side properties on client site in Sharepoint). It doesn’t contain date time format, so we will extend it with necessary information (e.g. in masterpage);

   1:  <script type="text/javascript">
   2:      jQuery(function() {                
   3:          if (typeof (_spPageContextInfo) != "undefined" &&
   4:              _spPageContextInfo != null) {
   5:              <%
   6:                  var currentWeb = SPContext.Current.Web;
   7:                  var ci = new CultureInfo(currentWeb.Locale.LCID);
   8:                  var cultureSerialized = new JavaScriptSerializer().Serialize(
   9:                      new
  10:                      {
  11:                          name = ci.Name,
  12:                          dateTimeFormat = ci.DateTimeFormat,
  13:                          numberFormat = ci.NumberFormat
  14:                      });
  15:              %>
  16:              _spPageContextInfo.currentCultureSerialized = <%= cultureSerialized %>;
  17:          }
  18:      });
  19:  </script>

It will add the following script to output if current locale is 1033 (en-us):

   1:  _spPageContextInfo.currentCultureSerialized =
   2:  {
   3:     "name":"en-US",
   4:     "dateTimeFormat":{
   5:        "AMDesignator":"AM",
   6:        "Calendar":{
   7:           "MinSupportedDateTime":"\/Date(-62135596800000)\/",
   8:           "MaxSupportedDateTime":"\/Date(253402293599999)\/",
   9:           "AlgorithmType":1,
  10:           "CalendarType":1,
  11:           "Eras":[
  12:              1
  13:           ],
  14:           "TwoDigitYearMax":2029,
  15:           "IsReadOnly":false
  16:        },
  17:        "DateSeparator":"/",
  18:        "FirstDayOfWeek":0,
  19:        "CalendarWeekRule":0,
  20:        "FullDateTimePattern":"dddd, MMMM d, yyyy h:mm:ss tt",
  21:        "LongDatePattern":"dddd, MMMM d, yyyy",
  22:        "LongTimePattern":"h:mm:ss tt",
  23:        "MonthDayPattern":"MMMM d",
  24:        "PMDesignator":"PM",
  25:        "RFC1123Pattern":
  26:  "ddd, dd MMM yyyy HH\u0027:\u0027mm\u0027:\u0027ss \u0027GMT\u0027",
  27:        "ShortDatePattern":"M/d/yyyy",
  28:        "ShortTimePattern":"h:mm tt",
  29:        "SortableDateTimePattern":
  30:  "yyyy\u0027-\u0027MM\u0027-\u0027dd\u0027T\u0027HH\u0027:\u0027mm\u0027:\u0027ss",
  31:        "TimeSeparator":":",
  32:        "UniversalSortableDateTimePattern":
  33:  "yyyy\u0027-\u0027MM\u0027-\u0027dd HH\u0027:\u0027mm\u0027:\u0027ss\u0027Z\u0027",
  34:        "YearMonthPattern":"MMMM yyyy",
  35:        "AbbreviatedDayNames":[
  36:           "Sun",
  37:           "Mon",
  38:           "Tue",
  39:           "Wed",
  40:           "Thu",
  41:           "Fri",
  42:           "Sat"
  43:        ],
  44:        "ShortestDayNames":[
  45:           "Su",
  46:           "Mo",
  47:           "Tu",
  48:           "We",
  49:           "Th",
  50:           "Fr",
  51:           "Sa"
  52:        ],
  53:        "DayNames":[
  54:           "Sunday",
  55:           "Monday",
  56:           "Tuesday",
  57:           "Wednesday",
  58:           "Thursday",
  59:           "Friday",
  60:           "Saturday"
  61:        ],
  62:        "AbbreviatedMonthNames":[
  63:           "Jan",
  64:           "Feb",
  65:           "Mar",
  66:           "Apr",
  67:           "May",
  68:           "Jun",
  69:           "Jul",
  70:           "Aug",
  71:           "Sep",
  72:           "Oct",
  73:           "Nov",
  74:           "Dec",
  75:           ""
  76:        ],
  77:        "MonthNames":[
  78:           "January",
  79:           "February",
  80:           "March",
  81:           "April",
  82:           "May",
  83:           "June",
  84:           "July",
  85:           "August",
  86:           "September",
  87:           "October",
  88:           "November",
  89:           "December",
  90:           ""
  91:        ],
  92:        "IsReadOnly":false,
  93:        "NativeCalendarName":"Gregorian Calendar",
  94:        "AbbreviatedMonthGenitiveNames":[
  95:           "Jan",
  96:           "Feb",
  97:           "Mar",
  98:           "Apr",
  99:           "May",
 100:           "Jun",
 101:           "Jul",
 102:           "Aug",
 103:           "Sep",
 104:           "Oct",
 105:           "Nov",
 106:           "Dec",
 107:           ""
 108:        ],
 109:        "MonthGenitiveNames":[
 110:           "January",
 111:           "February",
 112:           "March",
 113:           "April",
 114:           "May",
 115:           "June",
 116:           "July",
 117:           "August",
 118:           "September",
 119:           "October",
 120:           "November",
 121:           "December",
 122:           ""
 123:        ]
 124:     },
 125:     "numberFormat":{
 126:        "CurrencyDecimalDigits":2,
 127:        "CurrencyDecimalSeparator":".",
 128:        "IsReadOnly":false,
 129:        "CurrencyGroupSizes":[
 130:           3
 131:        ],
 132:        "NumberGroupSizes":[
 133:           3
 134:        ],
 135:        "PercentGroupSizes":[
 136:           3
 137:        ],
 138:        "CurrencyGroupSeparator":",",
 139:        "CurrencySymbol":"$",
 140:        "NaNSymbol":"NaN",
 141:        "CurrencyNegativePattern":0,
 142:        "NumberNegativePattern":1,
 143:        "PercentPositivePattern":0,
 144:        "PercentNegativePattern":0,
 145:        "NegativeInfinitySymbol":"-Infinity",
 146:        "NegativeSign":"-",
 147:        "NumberDecimalDigits":2,
 148:        "NumberDecimalSeparator":".",
 149:        "NumberGroupSeparator":",",
 150:        "CurrencyPositivePattern":0,
 151:        "PositiveInfinitySymbol":"Infinity",
 152:        "PositiveSign":"+",
 153:        "PercentDecimalDigits":2,
 154:        "PercentDecimalSeparator":".",
 155:        "PercentGroupSeparator":",",
 156:        "PercentSymbol":"%",
 157:        "PerMilleSymbol":"‰",
 158:        "NativeDigits":[
 159:           "0",
 160:           "1",
 161:           "2",
 162:           "3",
 163:           "4",
 164:           "5",
 165:           "6",
 166:           "7",
 167:           "8",
 168:           "9"
 169:        ],
 170:        "DigitSubstitution":1
 171:     }
 172:  };

For other locales it will contain localized information. Now, when we have necessary datetime format on client side we can use it in display templates by overriding default datetime renderer:

   1:  customDateRenderer=function(a) {
   2:      if(!Srch.U.n(a) && !a.isEmpty &&
   3:          Date.isInstanceOfType(a.value)) {
   4:          try {
   5:              return a.value.localeFormat
   6:                 (_spPageContextInfo.currentCultureSerialized.
   7:                     dateTimeFormat.ShortDatePattern);
   8:          }
   9:          catch(er) {
  10:              return Srch.ValueInfo.Renderers.
  11:                  defaultRenderedValueHtmlEncoded(a);
  12:          }
  13:      }
  14:      else {
  15:          return Srch.ValueInfo.Renderers.
  16:              defaultRenderedValueHtmlEncoded(a);
  17:      }
  18:  };
  19:  ...
  20:  var dt = $getItemValue(ctx, "Published");
  21:  dt.overrideValueRenderer(customDateRenderer);

After that datetimes will be localized in display templates based on locale of current SPWeb.

Monday, June 3, 2013

Enumerate all properties of javascript context object in display templates in Sharepoint 2013

If you create custom display template e.g. for search result type, it is useful to know what properties are exposed in the javascript context object (ctx). It can be achived quite easy. In the html file of your display template write the following code:

   1: for (var p in ctx.CurrentItem)
   2: {
   3:     console.log(p + ":" + $getItemValue(ctx, p));
   4: }

After that when search result will show the item which corresponds to the result type, for which you specified custom display template, if you will open javascript console (F12 in IE and FF and select Console tab), you will see something like this:

   1: Rank:11.27 
   2: DocId:5367 
   3: WorkId:5367 
   4: Title:test123 
   5: Author:Developer 
   6: Size:0 
   7: Path:http://example.com/test/DispForm.aspx?ID=1 
   8: Description: 
   9: Write:Mon Jun 3 19:55:58 UTC+0300 2013 
  10: CollapsingStatus:0 
  11: HitHighlightedSummary: 
  12: HitHighlightedProperties:&lt;HHTitle&gt;&lt;c0&gt;test123&lt;/c0&gt;&lt;/HHTitle&gt;&lt;HHUrl&gt;
  13: http://example.com/test/DispForm.aspx?ID=1&lt;/HHUrl&gt;&lt;author hashh=&quot;0&quot;&gt;Developer&lt;/author&gt; 
  14: contentclass:STS_ListItem_GenericList 
  15: PictureThumbnailURL: 
  16: ServerRedirectedURL: 
  17: ServerRedirectedEmbedURL: 
  18: ServerRedirectedPreviewURL: 
  19: FileExtension:aspx 
  20: ContentTypeId:0x0100...
  21: ParentLink:http://example.com/test/AllItems.aspx 
  22: ViewsLifeTime: 
  23: ViewsRecent: 
  24: SectionNames: 
  25: SectionIndexes: 
  26: SiteLogo: 
  27: SiteDescription: 
  28: deeplinks: 
  29: importance: 
  30: SiteName:http://example.com
  31: IsDocument:No 
  32: LastModifiedTime:Monday, June 3, 2013 
  33: FileType: 
  34: IsContainer:No 
  35: WebTemplate: 
  36: SecondaryFileExtension: 
  37: docaclmeta: 
  38: OriginalPath:http://example.com/test/DispForm.aspx?ID=1 
  39: EditorOWSUSER:Developer 
  40: DisplayAuthor:Developer 
  41: ResultTypeIdList:38;6 
  42: PartitionId:0c37852b-34d0-418e-91c6-2ac25af4be5b 
  43: UrlZone:0 
  44: AAMEnabledManagedProperties:AttachmentURI;deeplinks;DefaultEncodingURL;ExternalMediaURL;HierarchyUrl;
  45: OrgParentUrls;OrgUrls;OriginalPath;ParentLink;Path;PictureThumbnailURL;PictureURL;PublishingImage;
  46: recommendedfor;ServerRedirectedEmbedURL;ServerRedirectedPreviewURL;ServerRedirectedURL;SiteLogo;
  47: SitePath;SPSiteURL;UserEncodingURL 
  48: ResultTypeId:38 
  49: RenderTemplateId:~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_test.js 
  50: piSearchResultId:0_1 
  51: ParentTableReference:[object Object] 
  52: csr_id:ctl00_PlaceHolderMain_ctl01_csr2_item 

This information will help you to create display template.