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. In this post, let’s explore how to provide the distance in such a case.
This is the third post in the series of an SXA Map component.
- SXA Map component
- SXA Map component Part 2 With Search results and Location Finder
- SXA Map component Part 3 Show distance in POI Marker
- SXA Map component Part 4 Show POI markers for the same coordinates
- SXA Map component Part 5 Filter locations with Radius Filter or Custom Filter Slider components
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; using Sitecore.XA.Foundation.SitecoreExtensions.Interfaces; using Sitecore.DependencyInjection; using Microsoft.Extensions.DependencyInjection; 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() { IRendering rendering = ServiceLocator.ServiceProvider.GetService<IRendering>(); if (rendering == null) return null; string sign = 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_Config\Include\Foundation 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 webroot\bin and Foundation\CustomSXA.Foundation.MapExtension.config to your webroot\App_Config\Include\Foundation 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.
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.
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.
Preview the page, now Search Results also show the distance.
Hope this helps.
Check out the SXA Map component Part 4 on how to show POI markers for the same coordinates.
Happy SXA Learning 🙂