Updating the Store Locator Widget with the GeoLocation API

Updating the Store Locator Widget with the GeoLocation API

July 19, 2013 0 Comments

The content you're reading is getting on in years
This post is on the older side and its content may be out of date.
Be sure to visit our blogs homepage for our latest news, updates and information.

When customers visit your store locations page from any mobile device, they’re at a critical juncture in their buyer decision process. Without a store locator, you could lose their business. Courtney Wilson described how to create a store locator back in March, and we have now built some of that functionality into Sitefinity 6.1’s GeoLocation API.

I am going to update Courtney’s control to give the API a test run. However, I first need to look at what functionality is available.

GeoLocation API


Represents geolocation data in Sitefinity.




Gets or sets a guid representing the content item with which this geolocation is associated.


Gets or sets a string representing the content type of the content item with which this geolocation is associated.




Gets the guid identifying this geolocation instance.


Gets or sets the latitude.


Gets or sets the longitude.


Gets or sets the data provider name.

Telerik.Sitefinity.GeoLocations.Model.IGeoLocationDistance : IDataItem

Represents the distance between two geolocation points.




A double representing the distance between two geolocation points.


Provides the ability to get, update, and delete geolocations. It is provided by the SystemManager.

IGeoLocationService geoLocationService = SystemManager.GetGeoLocationService();




Deletes a geolocation specified by its id.


Returns a geolocation based matching the arguments.


Return geolocations using by a center point and radius. Optional arguments provide sorting and further filtering.


Updates a geolocation.


Contains criteria used to filter geolocations.




Gets or sets a string representing the content type associated with the geolocation data. Using this will only retrieve content of that type.




Gets or sets the data provider name.


The default constructor.


Use this enumeration to specify how to sort geolocation data in relation to another geolocation point.




Sort with the closest first, farthest away last.


Sort with the farthest away first, closest last.


Provides additional functionality for filtering and sorting geolocation.

var manager = DynamicModuleManager.GetManager() as IGeoLocationManager;




Filters an item query by geolocation data based on radius and other criteria.


Sorts a list of geolocations based upon distance from another

Creating the Content Type

Sitefinity 6.0 included a new content type for Address, and there’s one thing you need to do to take full advantage of it.

Go to the Settings menu in Administration then click Google Maps on the left side. Follow the instructions to obtain a Google Maps v3 API Key, and enter it into the field. After saving, address fields will automatically populate the geolocation based on the provided address or map selection.

The only fields needed for this demo is Title and Address, and I recommend removing all fields covered by Address. Additionally, the Distance field is no longer necessary and may even cause confusion. I named the module Stores instead of StoreLocator.


The original Ecommerce Store Locator source code is located on GitHub. Download it and install it according to the instructions. Take note that the name of the control is now StoreLocatorCustom.

Since the control accesses fields that are no longer present, it’s not in working condition. To clean it up, I’m going to start at BindStores() in StoreLocatorCustom.ascx.cs.

var manager = DynamicModuleManager.GetManager();
Type storeType = 
var stores = manager.GetDataItems(storeType)
					.Where(s => s.Status == ContentLifecycleStatus.Live);
Figure 1.

The lines in figure 1 are pretty much the same.

var radius = double.Parse(ddlDistance.SelectedValue);
var userLocation = GetCoordinate(txtSourceZip.Text.Trim())
var itemFilter = new ItemFilter { ContentType = storeType.ToString()};
IEnumerable<IGeoLocation> geolocations;
Figure 2.

The next four lines are variables for GeoLocationManager methods. I retained the GetCoordinate method since I’m not removing the Google Maps control. I defined the geolocations variable, but left it uninitialized since I use it as an out parameter in the following line.

stores = (manager as IGeoLocationManager).FilterByGeoLocation(stores, userLocation.Latitude, userLocation.Longitude, radius, out geolocations, itemFilter: itemFilter);
var sortedStores = (manager as IGeoLocationManager).SortByDistance(stores, geolocations, 
	userLocation.Latitude, userLocation.Longitude, DistanceSorting.Asc);
Figure 3.

The code in figure 3 does most of the work. First, I am filtering by geolocation to ensure only the stores within the selected radius are returned. Then I sort them. I removed the method that measures distance since it’s built into the SortByDistance method.

DynamicContent firstStore = sortedStores.FirstOrDefault();
if (firstStore != null)
    var address = firstStore.GetAddressFields().First().Value;
    litDefaultLat.Text = String.Format("{0}", address.Latitude);
    litDefaultLong.Text = String.Format("{0}", address.Longitude);
Figure 4.

I made modified the code in Figure 4 to use the address field for the latitidude and longitude. Dynamic content can have multiple address fields, and GetAddressFields returns a dictionary. If you're working with multiple address fields, be sure to specify the name in your ItemFilter and in the indexer for GetAddressFields.

listStores.DataSource = sortedStores;
lblStoreCount.Text = sortedStores.Count().ToString();
Figure 5.

Figure 5 is identical to the old version.

User Interface

I will work lightly on the user interface, simply updating the fields in the ItemTemplate section to support the new Address type.

<div style="padding: 10px 10px 10px 10px;">
    <b><a href='javascript:showMap(<%# Eval("Address.Latitude")%>, 
		<%# Eval("Address.Longitude")%>)'><%# Eval("Title")%></a></b>
    <br />
    <%# Eval("Address.Street")%>
    <br />
    <%# Eval("Address.City")%>, <%# Eval("Address.StateCode")%> <%# Eval("Address.Zip")%>
    <br />
    <span style='display:<%# Eval("Distance").ToString() == "0.00" ? "none" : "block"%>'>
	Distance: <%# Math.Truncate((double)Eval("Distance")) %> miles</span>
Figure 6.

I suggested removing the Distance field from your content type earlier, so why did I leave it in the user interface?

Dynamic content is constructed with the IGeoLocationDistance interface, so you no longer need to store ephemeral data with real content.


I easily eliminated many lines of code by using the built-in API, and its usage was straightforward. The GeoLocation API works with any type containing an address field.

For more, visit our webinars page to sign up for the Creating Better UX with the Sitefinity Geolocation API Webinar.

Chris Eargle

View all posts from Chris Eargle on the Progress blog. Connect with us about all things application development and deployment, data integration and digital business.

Comments are disabled in preview mode.
Latest Stories
in Your Inbox

Subscribe to get all the news, info and tutorials you need to build better business apps and sites

More From Progress
ProgressNEXT: Premier Event for Modern Application Development
Read More
Seven Reasons to Check Out Sitefinity 11.1
Read More
Getting Started with Your Omnichannel Content Strategy
Read More