Connecting a SharePoint List to Bing Maps

To find the latest information on this old topic, check out the sharepoint documentation at Integrating location and map functionality in SharePoint | Microsoft Learn

I have seen a lot of different ways to integrate Bing Maps with SharePoint. Some more complex than others. In this blog post we will look at an easy way to integrate Bing Maps with SharePoint and connect to a SharePoint list. Many of the things shown in this blog post are not limited to SharePoint Server and can extend to SharePoint Online and Office 365. To give us a jump start, we will reuse the SharePoint list we created in a previous blog titled Geocoding a SharePoint List Item

Adding Bing Maps to SharePoint

Before we dive into the ‘how to’ we will first demonstrate how simple it is to get Bing Maps into SharePoint. To start off, go to the Bing Maps Interactive SDK and go to the Traffic Module sample.

bmv8-trafficmoduleexample-1.jpg
Traffic Module Sample 
Full sample available at Bing Maps Samples

If you press the View HTML button on the bottom right corner you can get the full HTML for the example.

<!DOCTYPE html>
<html>
    <head>
        <title>traffichideshowtrafficHTML</title>
        <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
        <style type='text/css'>body{margin:0;padding:0;overflow:hidden;font-family:'Segoe UI',Helvetica,Arial,Sans-Serif}</style>
    </head>
    <body>
        <div id='printoutPanel'></div>
        
        <div id='myMap' style='width: 100vw; height: 100vh;'></div>
        <script type='text/javascript'>
            function loadMapScenario() {
                var map = new Microsoft.Maps.Map(document.getElementById('myMap'), {
                    /* No need to set credentials if already passed in URL */
                    center: new Microsoft.Maps.Location(47.606209, -122.332071),
                    zoom: 12
                });
                Microsoft.Maps.loadModule('Microsoft.Maps.Traffic', function () {
                    var manager = new Microsoft.Maps.Traffic.TrafficManager(map);
                    manager.show();
                });
                
            }
        </script>
        <script type='text/javascript' src='https://www.bing.com/api/maps/mapcontrol?key=YourBingMapsKey&callback=loadMapScenario' async defer></script>
    </body>
</html>

Simply open up notepad or any other text editing tool, then copy and paste this code into it. Finally, save the file as TrafficMap.html. You may also want to add your Bing Maps key (if you do not have one already, follow the steps at Getting a Bing Maps Key) to the code to remove the authentication error message that appears on the map. Now open up your SharePoint site and go to your Site Assets folder.

sharepointsiteassets2.jpg

Take the traffic map webpage you just created and upload it. Once the file is uploaded open up the traffic map in new window to test it out and to get the URL to the file. The webpage should look something like this:

sharepointtraffic.JPG

Next, let’s will create a new page in our SharePoint site called MyLocationMap.

Once you have your page, insert a Page Viewer web part. You can find this under the Media and Content category. Now open the tool pane of the Page Viewer web part you just created and add the URL to the traffic map file as the Link property. If you want you can also give the web part a title like “Traffic Flow”. When you are done, save the settings and page should refresh and look something like this:

sharepointpageviewerwebpart.JPG

Essentially, the Page Viewer web part has iframed the traffic map web page into the SharePoint site. With only a few minutes of work we were able to easily integrate a simple Bing Maps application with SharePoint.

Integrating with a SharePoint List

There are a few ways to connect to a SharePoint list from code. The two main ways are: use the ECMAScript in SharePoint which has a library for accessing list data or; use the List REST services which exist for all SharePoint lists. In this post we are going to use the ECMAScript method. Here is a good resource on how to Retrieve Lists Using JavaScript in SharePoint. If you would rather use the SharePoint List REST services take a look at this documentation.

To make this code sample more reusable, we will add support for a query string parameter called ListTitle which will allow us to specify which list we want to connect directly from the URL. As long as the list has a Title, Description, Latitude and Longitude columns this code sample will work. We will also add an infobox control to the map to display the location details when a pushpin is clicked.

Since we are essentially iframing our web page into a SharePoint page, we will have to call the parent of the iframe to get access to the SharePoint ECMAScripts. Normally this would cause a security exception; however, since our webpage is hosted within the same domain as our SharePoint page, this is allowed. To get access to the parent of the iframe we simply need to call functions in the part using window.parent.

Open up notepad or any other text editor and add the following code into it. Save the file as MyLocationListMap.html.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>

<script type="text/javascript">
var map, infobox, dataLayer, ctx, listItems, listTitle;

        function getMap()
        {
map = new Microsoft.Maps.Map(document.getElementById('myMap'), {
                credentials: 'YOUR_BING_MAPS_KEY'
            });

            dataLayer = new Microsoft.Maps.EntityCollection();
map.entities.push(dataLayer);

var infoboxLayer = new Microsoft.Maps.EntityCollection();
map.entities.push(infoboxLayer);

            infobox = new Microsoft.Maps.Infobox(new Microsoft.Maps.Location(0, 0), { 
                        visible: false, 
                        offset: new Microsoft.Maps.Point(0, 20) 
                    });
            infoboxLayer.push(infobox);

            listTitle = getQueryStringValue('ListTitle');

            if(listTitle){
                window.parent.ExecuteOrDelayUntilScriptLoaded(loadList, 'sp.js');
            }
        }

        function loadList(){
            getListItems(listTitle);            
        }

        function getListItems(listTitle){
            ctx = new window.parent.SP.ClientContext.get_current();

var targetList = ctx.get_web().get_lists().getByTitle(listTitle);
var query = window.parent.SP.CamlQuery.createAllItemsQuery();

            listItems = targetList.getItems(query);
            ctx.load(listItems);

            ctx.executeQueryAsync(onLoadItemsSuccess, onLoadItemsFail);
        }

        function onLoadItemsFail(sender, args) {
            alert('Failed to get lists items. Error:' + args.get_message());
        }

        function onLoadItemsSuccess(sender, args) {
var listEnumerator = listItems.getEnumerator();

            var item, pin, loc;
            while (listEnumerator.moveNext())  {
                item = listEnumerator.get_current();
                loc = new Microsoft.Maps.Location(item.get_item("Latitude"), item.get_item("Longitude"));
                pin = new Microsoft.Maps.Pushpin(loc);
                pin.Metadata = {
                    Title : item.get_item("Title"),
                    Location : item.get_item("Location")
                };
                Microsoft.Maps.Events.addHandler(pin, 'click', displayInfobox);
map.entities.push(pin);
            }
        }

        function displayInfobox(e) {
            if (e.targetType == 'pushpin') {
                infobox.setLocation(e.target.getLocation());
                infobox.setOptions({ 
                    visible: true, 
title: e.target.Metadata.Title, 
                    description: e.target.Metadata.Location 
                });
            }
        } 

        function getQueryStringValue(key) {
var queryString = document.URL.split("?");
            if(queryString && queryString.length > 1)
            {
var params = queryString[1].split("&");

                for (var i = 0; i < params.length; i = i + 1) {
var value = params[i].split("=");
                    if (value[0] == key){
                        return value[1];
                    }
                }
}

            return null;
        }

        window.parent.onload = getMap;
</script>
</head>
<body>
<div id='myMap' style="position:relative;width:100%;height:450px;"></div>
</body>
</html>

What does this code actually do? The getMap function loads the map and adds two layers to the map; one for the data and the other for the infobox. This is based on a blog post I created on displaying Multiple pushpins and Infoboxes in Bing Maps Web Control. It then gets the ListTitle query string value and then executes the ExecuteOrDelayUntilScriptLoaded function in the parent page which will execute LoadList function in our code after the sp.js file has finished loading in the main page. This ensures that the ECMAScripts we need are loaded. When the LoadList function is called it takes the ListTitle query string value and passes it to the getListItems function. The getListItems function gets the current client context of the SharePoint site and creates a query to get all items in the list. It then executes the list and if successful calls the onLoadItemsSuccessful function which loops through the list items and creates pushpins and overlays them on the map. If the query failed to load the list items an alert is displayed to user.

Now, take the MyLocationListMap.html file and upload it into your Site Assets folder. Get the URL to the page.

SP_Assets2

Navigate back to the MyLocationMap page in your SharePoint site and open the tool pane to the Page Viewer web part we added earlier. Update the Link property with the URL to the MyLocationListMap.html file and change the title to “My Location Map” then save the changes. The page will refresh and look something like this once you click one of the pushpins.

image

Tip for SharePoint 2013 Users

SharePoint 2013 introduces a new field type named Geolocation that enables you to create SharePoint lists with location information. In Geolocation columns, you can enter location information as a pair of latitude and longitude coordinates in decimal degrees or retrieve the coordinates of the user’s current location from the browser if it implements the W3C Geolocation API. In the list, SharePoint 2013 displays the location on Bing Maps. In addition, a new view named Map View displays the list items as pushpins on a Bing Maps. Together, the Geolocation field and the Map View enable you to give a spatial context to any information by integrating data from SharePoint into a mapping experience, and let your users engage in new ways in your web and mobile apps and solutions. Also, its worth mentioning that SharePoint sites are generally internal applications and would require an Enterprise Bing Maps key. Take a look at the Integrating location and map functionality in SharePoint 2013 documentation for more information.

Here is how the out of the box map looks when you hover over a single list item that has location information.

SP2013_Item

Here is what the new Map View looks like:

SP2013_listItems

This is a great first step for anyone wanting to add Bing Maps to their SharePoint site. Note: the out of the box functionality is limited to this. If you want to customize the map or add complex shapes (like polygons), you will need to do some additional custom development. The steps outlined earlier in this post can be used to do just that. There are also a lot of really great web parts available on CodePlex which you could use as a starting point.

– Ricky Brundritt, EMEA Bing Maps Technology Solution Professional