Integrating GoogleMaps with Sitefinity DynamicModules

Integrating GoogleMaps with Sitefinity DynamicModules

Posted on April 04, 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.

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.
progress-logo

The Progress Team

View all posts from The Progress Team 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