Updating the Store Locator Widget with the GeoLocation API

Updating the Store Locator Widget with the GeoLocation API

Posted on 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

Telerik.Sitefinity.GeoLocations.Model.IGeoLocation

Represents geolocation data in Sitefinity.

Name

Description

ContentItemId

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

ContentType

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

CustomKey

 

Id

Gets the guid identifying this geolocation instance.

Latitude

Gets or sets the latitude.

Longitude

Gets or sets the longitude.

ProviderName

Gets or sets the data provider name.

Telerik.Sitefinity.GeoLocations.Model.IGeoLocationDistance : IDataItem

Represents the distance between two geolocation points.

Name

Description

Distance

A double representing the distance between two geolocation points.

Telerik.Sitefinity.GeoLocations.IGeoLocationService

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

IGeoLocationService geoLocationService = SystemManager.GetGeoLocationService();

Name

Description

DeleteLocation()

Deletes a geolocation specified by its id.

GetLocation()

Returns a geolocation based matching the arguments.

GetLocationsInCircle()

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

UpdateLocation()

Updates a geolocation.

Telerik.Sitefinity.GeoLocations.ItemFilter

Contains criteria used to filter geolocations.

Name

Description

ContentType

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

CustomKey

 

ProviderName

Gets or sets the data provider name.

ItemFilter()

The default constructor.

Telerik.Sitefinity.GeoLocations.DistanceSorting

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

Name

Description

Asc

Sort with the closest first, farthest away last.

Desc

Sort with the farthest away first, closest last.

Telerik.Sitefinity.GeoLocations.IGeoLocationManager

Provides additional functionality for filtering and sorting geolocation.

var manager = DynamicModuleManager.GetManager() as IGeoLocationManager;

Name

Description

FilterByGeoLocation

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

SortByDistance

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.

CodeBehind

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 = 
	TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.Stores.Store");
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;
listStores.DataBind();
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>
</div>
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.

Conclusion

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

Comments are disabled in preview mode.
Topics

Sitefinity Training and Certification Now Available.

Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.

Learn More
Latest Stories
in Your Inbox

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

Loading animation