Customize/Extend Sitecore SXA Search Results

Pranay
Apr 28, 2022  ยท  3205 views

Here are the different ways of customising the Sitecore SXA's Search Result component based on the usecase.

Customizing the SXA Search Results component

Sitecore SXA Search

Sitecore SXA's Search Result component is a widely used component in Search and other listing pages. It allows a wide range of features but still there will be a need for customization of the results which may not be supported out of the box.

Can't a new rendering variant help?

Mostly not. The rendering variant has the context of just a single Search Result item. So we can only customized the data/format for each result item. If you need to group the results based on some field or property then this will not work.

Duplicating the view file?

The view file for the Search Result is located in the path '/Views/SearchResults/SearchResults.cshtml'. Below are the contents of the file.

@using Sitecore.Web
@using Sitecore.XA.Foundation.MarkupDecorator.Extensions
@using Sitecore.XA.Foundation.RenderingVariants.Extensions
@using Sitecore.XA.Foundation.SitecoreExtensions.Extensions
@using Sitecore.XA.Foundation.Variants.Abstractions.Fields

@model Sitecore.XA.Feature.Search.Models.SearchResultsRenderingModel

@{
  string variantClass = string.Empty;
	if (Model.Attributes.ContainsKey("class"))
	{
	variantClass = Model.Attributes["class"].Aggregate();
	}
}
@if (WebUtil.GetQueryString(Sitecore.XA.Feature.Search.Constants.CreativeExchangeExport) != "true") {
@Model.MessageIsEmpty
@Html.Sxa().Field("ResultsNotFoundText", Model.DataSourceItem, !Model.IsControlEditable) @Html.Sxa().Field("Text", Model.Item, !Model.IsControlEditable)
} else {
  • @foreach (BaseVariantField variantField in Model.VariantFields) { @Html.RenderingVariants().RenderVariant(variantField, Model.PageItem, false, Model) }
}

If you just need to add some additional html elements then the custom View should work. You might be thinking that you can even update the existing search element html structure but that might not reflect in your page. Here is a an example of this problem. So having a new View file will only give the flexibility of adding new Html elements or updating certain existing html tags.

How to customize the Search Result HTML

The Search Result Html is generated from the SXA's Search Result JS file. This file will be part of the SXA base theme and would be available in the media library. If you observe the contents of the file, we will find the html structure generated for the Search component. So this is where the actual Search Result component html is being rendered.

search results js file in base theme

On each Search request, an ajax call is being made and the result set is returned to this js file with multiple event handlers. So if you need to take control of the result set list and display with customized html structure then this is the file you need to customize.

To do that just duplicate the file and name it differently.

  1. Change the name of the search component that you see at the top of of this js file. i.e., change 'XA.component.search.results' to 'XA.component.search.customResults' or something more meaningful.

  2. This js is initialized based on the availability of a class 'search-results' in the page. This class comes from the view file 'Views/SearchResults/SearchResults.cshtml', so to run our custom js file, use a custom view file with a different class and update the js to initialize based on this new class. Something like below.

     var searchResults = $(".custom-search-results:not(.initialized)");
    

Custom Search results js file

  1. Make sure the OOTB class 'search-results' still added in the view so that other ootb search events are still triggered. Here is how I have still included the 'search-results' class.

     < div @Html.Sxa().Component(Model.Rendering.RenderingCssClass ?? "custom-search-results", Model.Attributes).Decorate("class", "search-results") data-class-variant="@variantClass" data-properties='@Model.JsonDataProperties'>........
  • Since we are interested only in the html, we can extend the base model in the js file and overwrite only a single event 'resultsLoaded'. resultsLoaded event is triggered after the ajax call fetches the search results and this is where even the html structure is built. So just overwrite this event and have your custom logic reside here. Here is the custom js file with just the resultsLoaded event.

     	XA.component.search.customResults = (function ($) {
     			"use strict";
     			var api = {},
     					searchResultViews = [],
     					searchResultModels = [];
     			var SearchResultModel = XA.component.search.baseModel.extend(
     					{
     							defaults: {
     									dataProperties: {},
     									noResultsText: "",
     									resultData: {}
     							},
     							initialize: function () { },
     					});
     			var SearchResultView = XA.component.search.baseView.extend(
     					{
     							initialize: function () {
     									var dataProperties = this.$el.data();
     									if (dataProperties.properties.sig === null) {
     											dataProperties.properties.sig = "";
     									}
     									if (this.model) {
     											this.model.set({ dataProperties: dataProperties.properties });
     									}
     									XA.component.search.vent.on(
     											"results-loaded",
     											this.resultsLoaded.bind(this)
     									);
     									this.render();
     							},
     							resultsLoaded: function (resultsData) {
     									console.log(resultsData); //result set
     									//Custom code goes here to render html
     							},
     							events: {},
     							renderPart: function () { },
     							render: function () { },
     					});
     			api.init = function () {
     					if ($("body").hasClass("on-page-editor")) {
     							return;
     					}
     					var searchResults = $(".custom-search-results:not(.custom-initialized)");
     					_.each(searchResults, function (elem) {
     							var $el = $(elem),
     									resultsModel = new SearchResultModel();
     							searchResultModels.push(resultsModel);
     							searchResultViews.push(new SearchResultView({ el: $el, model: resultsModel }));
     							$el.addClass("custom-initialized");
     					});
     			};
     			return api;
     	}(jQuery, document));
     	XA.register('customResults', XA.component.search.customResults);
     	XA.component.search.customResults.init();
    
  • This way we will get the complete control of the result set.

    How to customize the SXA Search component

    To customize the complete SXA search component, clone the Search results rendering, crreate a custom view file and have a custom js file like in the above previous step. It will be a long way to go as we have to override the Controller, Repository class, rendering model etc based on our need. You can see how each of these classes are implemented and related by using some assembly browser.

    Hope this helps you. Please comment your thoughts.

    AUTHOR

    Pranay

    A Software Engineer by profession, a part time blogger and an enthusiast programmer. You can find more about me here.


    Post a comment




    Thank you! You are now subscribed.

    Sign up for our newsletter

    Subscribe to receive updates on our latest posts.

    Thank you! You are now subscribed.