+1-888-365-2779
Try Now
More in this section
Categories
Bloggers
Blogs RSS feed

Integrating GoogleMaps with Sitefinity DynamicModules

by Boyan Barnev
This blog post is a continuation of our previous example for Filtering Sitefinity DynamicContentView on the Frontend.

To provide a brief background in that post we demonstrated how you can easily create a widget that would display your dynamic module's content, and allow your users to filter this content dynamically on the frontend. Today's post will continue using the same sample, so we would strongly recommend checking the previous post for some further details.

For today's examples we want to extend the concept, and sprinkle some sugar on top, namely we would like to display our office locations on a map. The catch here is that as everything else in Sitefinity we want to make the product do the work for you, so any new offices that we create should be automatically added on the map for you.

The task can be split into two logical parts:

1. Providing the location of each office on the client

This task is quite easy - you can use your imagination and define any approaches that suit your particular template and use case scenario, however one of the simplest ways to go would be to add a field to our list template, which will display the location information. If you don't want this data displayed on the list template, though, you can just style it as display:none, for example:
<style>
    .sfLocation
    {
 
        display: none;
    }
</style>
 
<telerik:RadListView ID="dynamicContentListView" ItemPlaceholderID="ItemsContainer" runat="server" EnableEmbeddedSkins="false" EnableEmbeddedBaseStylesheet="false">
    <LayoutTemplate>
        <ul class="sfitemsList sfitemsListTitleDateTmb">
            <asp:PlaceHolder ID="ItemsContainer" runat="server" />
        </ul>
    </LayoutTemplate>
    <ItemTemplate>
        <li class="sfitem sfClearfix">
            <h2 class="sfitemTitle">
                <sf:DetailsViewHyperLink ID="DetailsViewHyperLink" TextDataField="Title" runat="server" />
            </h2>
            <sf:FieldListView ID="PublicationDate" runat="server" Format="{PublicationDate.ToLocal():MMM d, yyyy, HH:mm tt}" WrapperTagName="div" WrapperTagCssClass="sfitemPublicationDate" />
            <asp:Label ID="TextField1" runat="server" Text='<%# Eval("Location")%>' CssClass="sfLocation" />
        </li>
    </ItemTemplate>
</telerik:RadListView>
<sf:Pager ID="pager" runat="server"></sf:Pager>
<asp:PlaceHolder ID="socialOptionsContainer" runat="server"></asp:PlaceHolder>

That's it, part 1 is now completed.

2. What remains is getting the location for every item, and adding it as a marker on our map.

We'll be using the Google Maps Javascript API Version 3, which is now the official Javascript API Google has released for working with their GoogleMaps service.

To use the Google Maps Javascript API Version 3 you'll need to first reference it in the head section of your page. using our JavaScript widget you can very quickly add the link to http://maps.google.com/maps/api/js?sensor=false  and specify that it'd be included in the head tag of the page.

Next we can declare the div element that will host our map, and define the map itself:
<div id="map" style="width: 700px; height: 600px; margin: 10px"></div>
    <script type="text/javascript">
        var map = new google.maps.Map(document.getElementById('map'), {
            zoom: 5,
            center: new google.maps.LatLng(-33.92, 151.25),
            mapTypeId: google.maps.MapTypeId.ROADMAP
        });

Once we've done that we have to find all listed items and get their location data (by retrieving the values of our Locations field):
var geocoder;
        $(document).ready(function () {
            geocoder = new google.maps.Geocoder();
            $(".sfLocation").each(function () {
                addMarker($(this).text());
            });
        })

inside the addMarker() function we're resolving the passed address from above, using Google Maps Javascript API Version 3 Geocoding service, and adding each successfully resolved address as a marker on our map:
function addMarker(address) {
            geocoder.geocode({ 'address': address }, function (results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    map.setCenter(results[0].geometry.location);
                    var marker = new google.maps.Marker({
                        map: map,
                        position: results[0].geometry.location
                    });
                } else {
                    console.log("Unable to find location: " + status);
                }
            });
        }

That's about everything you need to do in order to display your locations on the map.

For the sake of clarity we have created a new template, based on the one form the previous sample, if you have followed the above instructions properly, it should look something like this:
<%@ Control Language="C#" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.PublicControls.BrowseAndEdit" Assembly="Telerik.Sitefinity" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.ContentUI" Assembly="Telerik.Sitefinity" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.Comments" Assembly="Telerik.Sitefinity" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.Fields" Assembly="Telerik.Sitefinity" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI" Assembly="Telerik.Sitefinity" %>
<%@ Register TagPrefix="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI" TagPrefix="sitefinity" %>
<sitefinity:ResourceLinks ID="resourcesLinks" runat="server">
    <sitefinity:ResourceFile JavaScriptLibrary="JQuery" />
</sitefinity:ResourceLinks>
<span>City</span>
<br />
<asp:TextBox ID="cityTextBox" runat="server" />
<br />
<span>Country</span>
<br />
<asp:TextBox ID="countryTextBox" runat="server" />
<br />
<span>ZipCode</span>
<br />
<asp:TextBox ID="zipCodeTextBox" runat="server" />
<br />
<asp:Button ID="searchBtn" Text="Search" runat="server" />
 
<div>
    <div id="map" style="width: 700px; height: 600px; margin: 10px"></div>
    <script type="text/javascript">
        var map = new google.maps.Map(document.getElementById('map'), {
            zoom: 5,
            center: new google.maps.LatLng(-33.92, 151.25),
            mapTypeId: google.maps.MapTypeId.ROADMAP
        });
        var geocoder;
        $(document).ready(function () {
            geocoder = new google.maps.Geocoder();
            $(".sfLocation").each(function () {
                addMarker($(this).text());
            });
        })
 
        function addMarker(address) {
            geocoder.geocode({ 'address': address }, function (results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    map.setCenter(results[0].geometry.location);
                    var marker = new google.maps.Marker({
                        map: map,
                        position: results[0].geometry.location
                    });
                } else {
                    console.log("Unable to find location: " + status);
                }
            });
        }
 
    </script>
</div>
 
<style>
    .sfLocation
    {
 
        display: none;
    }
</style>
 
<telerik:RadListView ID="dynamicContentListView" ItemPlaceholderID="ItemsContainer" runat="server" EnableEmbeddedSkins="false" EnableEmbeddedBaseStylesheet="false">
    <LayoutTemplate>
        <ul class="sfitemsList sfitemsListTitleDateTmb">
            <asp:PlaceHolder ID="ItemsContainer" runat="server" />
        </ul>
    </LayoutTemplate>
    <ItemTemplate>
        <li class="sfitem sfClearfix">
            <h2 class="sfitemTitle">
                <sf:DetailsViewHyperLink ID="DetailsViewHyperLink" TextDataField="Title" runat="server" />
            </h2>
            <sf:FieldListView ID="PublicationDate" runat="server" Format="{PublicationDate.ToLocal():MMM d, yyyy, HH:mm tt}" WrapperTagName="div" WrapperTagCssClass="sfitemPublicationDate" />
            <asp:Label ID="TextField1" runat="server" Text='<%# Eval("Location")%>' CssClass="sfLocation" />
        </li>
    </ItemTemplate>
</telerik:RadListView>
<sf:Pager ID="pager" runat="server"></sf:Pager>
<asp:PlaceHolder ID="socialOptionsContainer" runat="server"></asp:PlaceHolder>

If you want to achieve the same result, but for a single location - when opening an item details view you can have that with some very slight modifications. Just go to our widget on the page (or Design -> Widgettempaltes->YourModuleType - full item content template), Edit it, and edit the Full item content template (under Single item settings tab).

Here's an example of a modified Full item content template for our module:
<%@ Control Language="C#" %>
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.DynamicModules.Web.UI.Frontend" TagPrefix="sf" %>
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI.Fields" TagPrefix="sf" %>
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI" TagPrefix="sf" %>
  <%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI" TagPrefix="sitefinity" %>
<sitefinity:ResourceLinks ID="resourcesLinks" runat="server">
    <sitefinity:ResourceFile JavaScriptLibrary="JQuery" />
  </sitefinity:ResourceLinks>
<div>
    <div id="map" style="width: 500px; height: 400px; margin: 10px"></div>
    <script type="text/javascript">
        var map = new google.maps.Map(document.getElementById('map'), {
            zoom: 10,
            center: new google.maps.LatLng(-33.92, 151.25),
            mapTypeId: google.maps.MapTypeId.ROADMAP
        });
        var geocoder;
        $(document).ready(function () {
            geocoder = new google.maps.Geocoder();
          if($(".sfLocation")){
            addMarker($(".sfLocation").text());
          }
                });
        
        function addMarker(address) {
                     geocoder.geocode({ 'address': address }, function (results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    map.setCenter(results[0].geometry.location);
                    var marker = new google.maps.Marker({
                        map: map,
                        position: results[0].geometry.location
                    });
                } else {
                    console.log("Unable to find location: " + status);
                }
            });
        }
 
    </script>
</div>
<style>
    .sfLocation
    {
        display: inline;
       
    }
</style>
 
  <sf:DynamicDetailContainer id="detailContainer" runat="server">
    <LayoutTemplate>
        <div class="sfitemDetails">
            <sf:SitefinityLabel ID="mainShortTextFieldLiteral" runat="server" Text='<%# Eval("Title") %>' WrapperTagName="h1" HideIfNoText="true" CssClass="sfitemTitle" />
            <sf:FieldListView ID="PublicationDate" runat="server" Format="{PublicationDate.ToLocal():MMM d, yyyy, HH:mm tt}" WrapperTagName="div" WrapperTagCssClass="sfitemPublicationDate" />
            <div class='sfitemShortTxtWrp'>       
                <sf:SitefinityLabel runat="server" Text='Phone number:' WrapperTagName="div" HideIfNoText="true" CssClass="sfitemFieldLbl" />       
                <sf:SitefinityLabel runat="server" Text='<%# Eval("PhoneNumber")%>' WrapperTagName="div" HideIfNoText="true" CssClass="sfitemShortTxt" />
            </div>
            <div class='sfitemShortTxtWrp'>       
                <sf:SitefinityLabel runat="server" Text='Country:' WrapperTagName="div" HideIfNoText="true" CssClass="sfitemFieldLbl" />       
                <sf:SitefinityLabel runat="server" Text='<%# Eval("Country")%>' WrapperTagName="div" HideIfNoText="true" CssClass="sfitemShortTxt" />
            </div>
            <div class='sfitemShortTxtWrp'>       
                <sf:SitefinityLabel runat="server" Text='Location:' WrapperTagName="div" HideIfNoText="true" CssClass="sfitemFieldLbl" />       
                <asp:Label ID="TextField1" runat="server" Text='<%# Eval("Location")%>' CssClass="sfLocation" />
            </div>
            <div class='sfitemShortTxtWrp'>       
                <sf:SitefinityLabel runat="server" Text='City:' WrapperTagName="div" HideIfNoText="true" CssClass="sfitemFieldLbl" />       
                <sf:SitefinityLabel runat="server" Text='<%# Eval("City")%>' WrapperTagName="div" HideIfNoText="true" CssClass="sfitemShortTxt" />
            </div>
            <div class='sfitemShortTxtWrp'>       
                <sf:SitefinityLabel runat="server" Text='Street:' WrapperTagName="div" HideIfNoText="true" CssClass="sfitemFieldLbl" />       
                <sf:SitefinityLabel runat="server" Text='<%# Eval("Street")%>' WrapperTagName="div" HideIfNoText="true" CssClass="sfitemShortTxt" />
            </div>
            <div class='sfitemShortTxtWrp'>       
                <sf:SitefinityLabel runat="server" Text='Zip code:' WrapperTagName="div" HideIfNoText="true" CssClass="sfitemFieldLbl" />       
                <sf:SitefinityLabel runat="server" Text='<%# Eval("ZipCode")%>' WrapperTagName="div" HideIfNoText="true" CssClass="sfitemShortTxt" />
            </div>
        </div>
    </LayoutTemplate>
</sf:DynamicDetailContainer>
<asp:PlaceHolder ID="socialOptionsContainer" runat="server"></asp:PlaceHolder>

The complete sample - OfficesModuleGoogleMaps is attached to this blog post, and as usual, you can find a demonstrative video of the final results here.

A useful fact that you should be aware of, is that with our upcoming Sitefinity 6.0 release, you'll be able to display the single item location (including a Map location) out of the box.

Hope you enjoyed the sample, and stay tuned for the next one.

5 comments

Leave a comment
  1. Sebastian Apr 04, 2013
    What is "location" in the following code?  Is it lat/long, UTM, address etc?...

    <asp:Label ID="TextField1" runat="server" Text='<%# Eval("Location")%>' CssClass="sfLocation" />

    Thanks!
    Sebastian
  2. Sebastian Apr 04, 2013
    What is "location" in the following code?  Is it lat/long, UTM, address etc?...

    <asp:Label ID="TextField1" runat="server" Text='<%# Eval("Location")%>' CssClass="sfLocation" />

    Thanks!
    Sebastian
  3. Boyan Apr 05, 2013
    Hi Sebastian,

    Location is just a field we've added to our module, and currently contains the City name, and Country it's located in - for the purposes of the Blog post we've used GoogleMaps Geocoder class:

    function addMarker(address) {                      geocoder.geocode({ 'address': address }, function (results, status)
     which allows for passing in an actual address, which Geocoder tries to resolve, and if it succeeds it will return the GoogleMaps position.
  4. Greg Apr 15, 2013
    Looks great! One question - does the specific street address get geocoded, or just the general city? This could be very helpful for a store locations database...

    Thanks,
    Greg
  5. Tauseef Jan 16, 2014
    Hi Boyan,

    I am developing a website in Sitefinity6.2.  How can I install it using Sitefinity Thunder? It my first time using SF. :)

    Thanks,
    Tauseef

    Leave a comment