Localize facets in Vue.js


Overview

In some rare cases, it is needed to override part of the data that is associated with the search results. For these case, there is a custom labels mapping structure that enhances the data.

Goal

This document provides insight on Vue.js powered custom mappings feature.

Prerequisite

Configured Hawksearch box or results widget using the Vue template



Labels mapping

The label mappings are realized the same way as the translations. An array with the label values is positioned in Hawksearch results and Hawksearch Box widget templates. In this case, however, the array should be extended with any values that are specific to the indexed data. The most common case is mapping the Sitefinity content type value to a human-readable label in the facets and selections header.

<script data-translations="vue-mappings" type="application/json"> { "Telerik.Sitefinity.Events.Model.Event": "@Html.HtmlSanitize(Html.Resource("EventTypeDisplayName", "HawkWidgetsResources"))", "Telerik.Sitefinity.Libraries.Model.Image": "@Html.HtmlSanitize(Html.Resource("ImageTypeDisplayName", "HawkWidgetsResources"))", "Telerik.Sitefinity.Libraries.Model.Video": "@Html.HtmlSanitize(Html.Resource("VideoTypeDisplayName", "HawkWidgetsResources"))" ... } </script>

The inclusion of this array is required for enabling custom label mapping. Removing it will prevent the system to modify any of the labels. Though it is not mandatory, it is not recommended to remove it from the widget template.


Hawksearch Results


Hawksearch results widget template with included label mappings.

 

@model HawksearchWidgets.Mvc.ViewModels.Hawksearch.SearchViewModel @using Telerik.Sitefinity.Frontend.Mvc.Helpers; @using Telerik.Sitefinity.Services @if (Model.Version == "V2L" || Model.Version == "V3L" || Model.Version == "V4L") { <div data-role="hawk-results" class="row hs-wrap" style="display: none;"> <div class="col-md-3 hs-col-3"> <div id="hawkbannerlefttop"></div> <div id="hawkfacets"></div> <div id="hawkbannerleftbottom"></div> <input type="hidden" name="search-term" value="@Model.Keyword" /> </div> <div role="main" class="col-md-9 hs-col-9" id="main-content"> <div id="hawktitle"></div> <div class="right-bg"> <div id="hawkbannertop"></div> <div id="hawktoptext"></div> <div id="hawkrelated"></div> <div id="hawktoppager"></div> <div id="hawktoptext"></div> <div id="hawkitemlist" class="item-list horizontal resource-listing clearfix"> </div> <div id="hawkbottompager"></div> <div class="clear">&nbsp;</div> </div> </div> </div> if (!SystemManager.IsDesignMode) { @Html.Script(Url.WidgetContent("Mvc/Scripts/polyfills.js"), "top", false) @Html.Script(Url.WidgetContent("Mvc/Scripts/hawksearch-init.js"), "head", false) @Html.Script(Url.WidgetContent("Mvc/Scripts/hawksearch.js"), "head", false) } } else if (!SystemManager.IsDesignMode) { if (Model.Languages.Length > 1 && Model.IsMultilingualEnabled) { <div> <span>@Html.Resource("ChangeResultsLanguageLabel", "HawkWidgetsResources") </span> @for (var i = 0; i < Model.Languages.Length; i++) { var language = Model.Languages[i]; var indexName = string.Empty; var uri = this.Request.Url; if (uri != null) { var query = HttpUtility.ParseQueryString(uri.Query); indexName = query.Get("indexName"); } var languageUrl = string.Format(string.IsNullOrWhiteSpace(indexName) ? "{0}?language={1}" : "{0}?language={1}&indexName={2}", Model.UrlPath, language.Name, indexName); <a href="@languageUrl">@language.DisplayName</a> if (i < Model.Languages.Length - 2) { <span>, </span> } else if (i == Model.Languages.Length - 2) { <span> @Html.Resource("OrLabel", "HawkWidgetsResources") </span> } } </div> } // Vue template @Html.Script(Url.WidgetContent("assets/build/js/vendor.bundle.js"), "bottom", false) @Html.Script(Url.WidgetContent("assets/build/js/main.js"), "bottom", false) @Html.StyleSheet(Url.WidgetContent("assets/build/css/vendor.css"), "head") @Html.StyleSheet(Url.WidgetContent("assets/build/css/main.css"), "head") @Html.StyleSheet(Url.WidgetContent("assets/dist/vue-hawksearch.css"), "head") @Html.StyleSheet(Url.WidgetContent("assets/dist/vue-hawksearch-override.css"), "head") <div data-component="vue-app-spa" data-client-guid="@Model.ClientId" data-hawksearch-tracking-api="@Model.TrackingUrl" data-hawksearch-base-api="@Model.HawksearchBaseAPI" data-hawksearch-search-api="@Model.HawksearchSearchingAPI" data-hawksearch-autocomplete-api="@Model.AutocompleteUrl" data-tracking-events="@Model.TrackingEvents" data-index-name="@Model.HawksearchIndexName" data-json-params="@Model.Data" data-current-culture="@Model.CurrentCulture" data-hawksearch-recommendation-api="" data-widget-guid="" data-show-searchbox="@Model.ShowSearchBox.ToString()"> <div class="hawk"> @if (Model.ShowSearchBox) { <div class="hawk__header"> <div data-component="hawksearch-field"> <search-box></search-box> </div> </div> } <div class="hawk__body"> <div data-component="hawksearch-facets"> <facet-list></facet-list> </div> <div data-component="hawksearch-results"> <results></results> </div> </div> </div> </div> <script id="vue-hawksearch-result-item" type="x-template"> <div class="media-body sf-media-body" v-on:click="onClick"> <h3> <template v-if="link"> <a :href=link>{{ title }}</a> </template> <template v-else> {{ title }} </template> </h3> <p> <strong class="sfHighlight">{{ title }}</strong> <span>{{ content }}</span> </p> <a :href="link">{{ link }}</a> </div> </script> <script data-translations="vue-mappings" type="application/json"> { "Telerik.Sitefinity.Events.Model.Event": "@Html.HtmlSanitize(Html.Resource("EventTypeDisplayName", "HawkWidgetsResources"))", "Telerik.Sitefinity.Libraries.Model.Image": "@Html.HtmlSanitize(Html.Resource("ImageTypeDisplayName", "HawkWidgetsResources"))", "Telerik.Sitefinity.Libraries.Model.Video": "@Html.HtmlSanitize(Html.Resource("VideoTypeDisplayName", "HawkWidgetsResources"))" } </script> <script data-translations="vue-translations" type="application/json"> { "Filter By": "@Html.HtmlSanitize(Html.Resource("FilterBy", "HawkWidgetsResources"))", "Search Results": "@Html.HtmlSanitize(Html.Resource("SearchResults", "HawkWidgetsResources"))", "Search Results for": "@Html.HtmlSanitize(Html.Resource("SearchResultsFor", "HawkWidgetsResources"))", "Sort By": "@Html.HtmlSanitize(Html.Resource("SortBy", "HawkWidgetsResources"))", "Enter a search term": "@Html.HtmlSanitize(Html.Resource("EnterKeyword", "HawkWidgetsResources"))", "Quick Lookup": "@Html.HtmlSanitize(Html.Resource("QuickLookup", "HawkWidgetsResources"))", "Clear All": "@Html.HtmlSanitize(Html.Resource("ClearAll", "HawkWidgetsResources"))", "Clear": "@Html.HtmlSanitize(Html.Resource("Clear", "HawkWidgetsResources"))", "No Results": "@Html.HtmlSanitize(Html.Resource("NoResults", "HawkWidgetsResources"))", "Loading": "@Html.HtmlSanitize(Html.Resource("Loading", "HawkWidgetsResources"))", "You've Selected": "@Html.HtmlSanitize(Html.Resource("YouSelected", "HawkWidgetsResources"))", "response_error_generic": "An error occurred while searching for your results. Please contact the site administrator." } </script> }

Hawksearch Box

Hawksearch Box widget template with included label mappings.

 

@model HawksearchWidgets.Mvc.ViewModels.HawksearchBox.SearchBoxViewModel @using Telerik.Sitefinity.Frontend.Mvc.Helpers; @using Telerik.Sitefinity.Modules.Pages @using Telerik.Sitefinity.Services @using Newtonsoft.Json @if (Model.Version == "V2L" || Model.Version == "V3L" || Model.Version == "V4L") { <div class="site-search"> <input type="hidden" value="@Model.Index"> <input type="hidden" value="@Model.ResultsUrl" data-search-page="@Model.ResultsUrl"> <div> <input class="site-search-input" placeholder="@Html.HtmlSanitize(Html.Resource("ImLookingFor", "HawkWidgetsResources"))" type="text" id="txtSiteSearch"> <button class="site-search-btn" id="btnSiteSearch"> <span class="visually-hidden">@Html.HtmlSanitize(Html.Resource("SubmitButtonText"))</span> <svg class="icon icon-search-01"> <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-search-01"></use> </svg> </button> </div> </div> //string hawkCssUrl = Hawksearch.Helpers.HawksearchApiHelper.GetHawksearchUrl().Replace("http://", "https://") + "/includes/hawksearch.css"; @*@Html.StyleSheet(hawkCssUrl, "head", false)*@ @Html.Script(ScriptRef.JQuery, "top", false) if (!SystemManager.IsDesignMode) { @Html.Script(Url.WidgetContent("Mvc/Scripts/polyfills.js"), "top", false) @Html.Script(Url.WidgetContent("Mvc/Scripts/hawksearch-init.js"), "head", false) @Html.Script(Url.WidgetContent("Mvc/Scripts/hawksearch.js"), "head", false) @Html.Script(Url.WidgetContent("Mvc/Scripts/hawksearch-autosuggest.js"), "bottom", false) @Html.Script(Url.WidgetContent("Mvc/Scripts/hawksearchbox.js"), "bottom", false) } } else { // Vue template @Html.Script(Url.WidgetContent("assets/build/js/vendor.bundle.js"), "bottom", false) @Html.Script(Url.WidgetContent("assets/build/js/main.js"), "bottom", false) @Html.StyleSheet(Url.WidgetContent("assets/build/css/vendor.css"), "head") @Html.StyleSheet(Url.WidgetContent("assets/build/css/main.css"), "head") @Html.StyleSheet(Url.WidgetContent("assets/dist/vue-hawksearch.css"), "head") @Html.StyleSheet(Url.WidgetContent("assets/dist/vue-hawksearch-override.css"), "head") <div data-component="vue-app-searchbox" data-client-guid="@Model.ClientId" data-hawksearch-tracking-api="@Model.TrackingUrl" data-hawksearch-base-api="@Model.HawksearchBaseAPI" data-hawksearch-search-api="@Model.HawksearchSearchingAPI" data-hawksearch-autocomplete-api="@Model.AutocompleteUrl" data-search-page="@Model.ResultsUrl" data-show-searchbox="True" data-json-params="@Model.Data" data-index-name="@Model.Index" data-current-culture="@Model.CurrentCulture"> <div class="hawk"> <div class="hawk__header"> <div data-component="hawksearch-field"> <search-box search-page="@Model.ResultsUrl"></search-box> </div> </div> </div> </div> <script data-translations="vue-mappings" type="application/json"> { "Telerik.Sitefinity.Events.Model.Event": "@Html.HtmlSanitize(Html.Resource("EventTypeDisplayName", "HawkWidgetsResources"))", "Telerik.Sitefinity.Libraries.Model.Image": "@Html.HtmlSanitize(Html.Resource("ImageTypeDisplayName", "HawkWidgetsResources"))", "Telerik.Sitefinity.Libraries.Model.Video": "@Html.HtmlSanitize(Html.Resource("VideoTypeDisplayName", "HawkWidgetsResources"))" } </script> <script data-translations="vue-translations" type="application/json"> { "Filter By": "@Html.HtmlSanitize(Html.Resource("FilterBy", "HawkWidgetsResources"))", "Search Results": "@Html.HtmlSanitize(Html.Resource("SearchResults", "HawkWidgetsResources"))", "Search Results for": "@Html.HtmlSanitize(Html.Resource("SearchResultsFor", "HawkWidgetsResources"))", "Sort By": "@Html.HtmlSanitize(Html.Resource("SortBy", "HawkWidgetsResources"))", "Enter a search term": "@Html.HtmlSanitize(Html.Resource("EnterKeyword", "HawkWidgetsResources"))", "Quick Lookup": "@Html.HtmlSanitize(Html.Resource("QuickLookup", "HawkWidgetsResources"))", "Clear All": "@Html.HtmlSanitize(Html.Resource("ClearAll", "HawkWidgetsResources"))", "Clear": "@Html.HtmlSanitize(Html.Resource("Clear", "HawkWidgetsResources"))", "No Results": "@Html.HtmlSanitize(Html.Resource("NoResults", "HawkWidgetsResources"))", "Loading": "@Html.HtmlSanitize(Html.Resource("Loading", "HawkWidgetsResources"))", "You've Selected": "@Html.HtmlSanitize(Html.Resource("YouSelected", "HawkWidgetsResources"))", "response_error_generic": "An error occurred while searching for your results. Please contact the site administrator." } </script> }