Hi Folks! Welcome back. In the previous post, we had set up the Map with all the markers supplied in the data source, and to not get affected by the Search Results on the page, we provided the Search Results Signature to Map Control Properties. And have placed the Location Finder. In this case, the distance is not shown. The central point inputs on the Map data source are used to adjust the Map view and do not contribute to evaluating the distance if the g query string parameter is not present. g hold the geolocation coordinates and are used to evaluate distance by the Search API.

The map shows all the markers and is not affected by the search result page size

No distance is shown

To show distance, there can be multiple solutions. One approach is to save the searched location in the cookie and read this cookie in a custom embedded function for the Scriban template that helps in evaluating the distance.

Following is the code implementing the above idea.

Create a JS file locally and copy the below code or download GeolocationCookieManager.js. Upload the file to the scripts folder of the site theme. e.g /sitecore/media library/Themes/tenant/site/themename/Scripts.

XA.component.geolocationcookiemanger = (function ($, document) {

“use strict”;
var api = {},
scriptsLoaded = false;

api.init = function() {
if ($(“body”).hasClass(“on-page-editor”)) {
return;
}

if(!scriptsLoaded)
{
scriptsLoaded = true;
XA.component.search.vent.on(“hashChanged”, function(hash) {
var reloadPage = false;

var components = $(‘*[data-properties]’);
_.each(components, function(elem) {
var $el = $(elem),
properties = $el.data(“properties”);
var signature = properties.searchResultsSignature;
if (typeof signature !== “undefined”)
{
var gsign = signature.length > 0 && signature !== “” ? signature + “_g” : “g”;
var gsignVal = hash[gsign];
if (typeof gsignVal !== “undefined” && gsignVal !== null && gsignVal !== “”) {
if(XA.cookies.readCookie(gsign) !== gsignVal)
{
XA.cookies.createCookie(gsign, gsignVal);
reloadPage = true;
}
}
}
});
if(reloadPage)
{
window.location.reload(); //needed to send the newly updated cookie to server so the map loads with the distance value
}
});
}
};

return api;

}(jQuery, document));

XA.register(“geolocationcookiemanger”, XA.component.geolocationcookiemanger);

Add a class file to your existing VS project suitable for a custom embedded function for the Scriban template. Copy the below code or download the source code from MapExtension Repository.

using System;
using Scriban.Runtime;
using Sitecore.Data.Items;
using Sitecore.XA.Foundation.Scriban.Pipelines.GenerateScribanContext;
using Sitecore.ContentSearch.Data;
using Sitecore.XA.Foundation.Search.Models;
using Sitecore.XA.Foundation.SitecoreExtensions.Extensions;
using Sitecore.Mvc.Presentation;
using Sitecore.Data.Fields;
using System.Linq;
using System.Web;

namespace CustomSXA.Foundation.MapExtension
{
public class GetGeospatial : IGenerateScribanContextProcessor
{
private delegate Geospatial GetGeospatialModel(Item item, string distanceUnit);

public void Process(GenerateScribanContextPipelineArgs args)
{
var getGetGeospatialModelImplementation = new GetGeospatialModel(GetGeospatialModelImplementation);
args.GlobalScriptObject.Import(“sc_geospatial”, getGetGeospatialModelImplementation);
}

public Geospatial GetGeospatialModelImplementation(Item item, string distanceUnit = “Miles”)
{
if (item != null && item.InheritsFrom(Sitecore.XA.Foundation.Geospatial.Templates.IPoi.ID))
{
var centre = this.SetLocationCentre();
if (centre != null)
{
return new Geospatial(item, centre, (Unit)Enum.Parse(typeof(Unit), distanceUnit));
}
}
return null;
}

public Coordinate SetLocationCentre()
{
string sign = RenderingContext.CurrentOrNull.Rendering.Parameters[“Signature”];
string coordinates = string.Empty;
double lat, lon;
if (System.Web.HttpContext.Current.Request.Cookies[$”{sign}_g”] != null)
{ //Map component signature g value
coordinates = System.Web.HttpContext.Current.Request.Cookies[$”{sign}_g”].Value;
}
else if (System.Web.HttpContext.Current.Request.Cookies[“g”] != null)
{ //regular default g value
coordinates = System.Web.HttpContext.Current.Request.Cookies[“g”].Value;
}
else if (!string.IsNullOrWhiteSpace(RenderingContext.CurrentOrNull?.Rendering.DataSource))
{ //coordinates from map data source
Item dataSource = Sitecore.Context.Database.GetItem(RenderingContext.CurrentOrNull.Rendering.DataSource);
ReferenceField field = dataSource.Fields[“Central point mode”];
if (field != null && field.TargetItem[“Value”] == “Auto”)
{
string vLat = dataSource[“Central point latitude”];
string vLon = dataSource[“Central point longitude”];
if (!string.IsNullOrWhiteSpace(vLat) && !string.IsNullOrWhiteSpace(vLon))
{
lat = Convert.ToDouble(vLat);
lon = Convert.ToDouble(vLon);
return new Coordinate(lat, lon);
}
}
}

if (string.IsNullOrWhiteSpace(coordinates))
{ //signature g value from the first component found
string gcookieKey = HttpContext.Current.Request.Cookies.AllKeys.ToList().FirstOrDefault(k => k.EndsWith(“_g”));
if (HttpContext.Current.Request.Cookies[gcookieKey] != null)
{
coordinates = HttpContext.Current.Request.Cookies[gcookieKey].Value;
}
}

if (!string.IsNullOrWhiteSpace(coordinates))
{
string[] coordinatesValues = coordinates.Split(‘|’);
if (coordinatesValues.Length == 2)
{
lat = Convert.ToDouble(coordinatesValues[0]);
lon = Convert.ToDouble(coordinatesValues[1]);
return new Coordinate(lat, lon);
}
}
return null;
}
}
}

Create a patch config file named CustomSXA.Foundation.MapExtension.config in App_ConfigIncludeFoundation folder of your project and update it with the below configuration.

<?xml version=”1.0″?>
<configuration xmlns:patch=”http://www.sitecore.net/xmlconfig/”>
<sitecore>
<pipelines>
<generateScribanContext>
<processor type=”CustomSXA.Foundation.MapExtension.GetGeospatial, CustomSXA.Foundation.MapExtension” resolve=”true” />
</generateScribanContext>
</pipelines>
</sitecore>
</configuration>

Install the required Sitecore and Scriban NuGet packages. Build the project, copy the CustomSXA.Foundation.MapExtension.dll to webrootbin and FoundationCustomSXA.Foundation.MapExtension.config to your webrootApp_ConfigIncludeFoundation folder.

Let’s create a new custom variant for POI and use the custom embedded scirban function. Traverse to /sitecore/content/tenant/site/Presentation/Rendering Variants/POI/Default.

Duplicate this item and name it as Marker.

In the new variant, update the Template field of item /sitecore/content/tenant/site/Presentation/Rendering Variants/POI/Marker/Distance, with below code.

{{ if o_geospatial }}
Distance: {{ o_geospatial.distance | math.round 1 }} {{ o_geospatial.unit }}
{{else}}
{{o_geospatial = sc_geospatial i_item ‘Kilometers’}}
{{ if o_geospatial }}
Distance: {{ o_geospatial.distance | math.round 1 }} {{ o_geospatial.unit }}
{{end}}
{{end}}

Traverse to /sitecore/content/tenant/site/Presentation/POI Types/Simple POI

Change Default variant to Marker. Save it.

Preview the item where all the components are configured. Below is the output where it shows the distance in Markers.

Distances are shown in the markers

Same Distance Scriban can be used for the Search Results component. 

Traverse to the Search Results variant. e.g. /sitecore/content/demotenant/sitecorethinker/Presentation/Rendering Variants/Search Results/vertical

Duplicate this item and name it as Locations.

Copy the Distance scriban item /sitecore/content/tenant/site/Presentation/Rendering Variants/POI/Marker/Distance under this new Locations Variant so it looks like below.

Distance in Search Results Variant

In the case of the Search Results component, o_geospatial is available and hence is able to provide the distance. Else part can be removed. Save it. Change the variant to Locations on the Search Results component.

Set Location variant in Search Results

Preview the page, now Search Results also show the distance.

Distance in both Markers and Search Results

Hope this helps. Happy SXA Learning