How to Integrate Virtual Earth Maps with a SharePoint List

How to Integrate Virtual Earth Maps with a SharePoint List

Rate This
  • Comments 99

Greg Hi everyone,

My name is Greg Chan and I’m a Program Manager in the SharePoint Designer team. I’ve also been involved in the development and testing of the Application Templates for Windows SharePoint Services 3.0. Just a couple weeks ago, I attended Tech Ed in Orlando and presented a breakout session called "Designing and Building Sophisticated Composite Applications with Microsoft Office SharePoint Designer 2007".

Today, I’ll show you how to integrate the Virtual Earth Map control with your SharePoint list. This is actually part of the demo I gave in Tech Ed, and it has generated a lot of interest. Many of you have requested more information on this, so as promised, I’m dedicating this post to it. Some of you may be wondering… "Isn’t this the same as the Plotting Your Data Using Virtual Earth blog that Jon Campbell posted awhile back?" While there are overlaps, the key difference is that this post will talk about plotting a single address as opposed to multiple addresses.  A big benefit for doing single address is that Virtual Earth is good at plotting a single address without the need for longitudes and latitudes.  We simply need to pass in the address value and take advantage of functions provided by Virtual Earth to geocode it. (I don’t know about you, but when I search for driving directions, I’m not typing in longs and lats...)

Let's get started!

Here’s the scenario -- you own a bike shop and use a SharePoint site to manage the manufacturing process for building bicycles. In your site, you have a Suppliers list that stores information about each of your supplier like phone number, address, e-mail, etc. The list is based off the Contacts list. You want to insert a map control inside the display form for each supplier to show the location of the supplier.

Step 1 - Modifying the Display Form

Open in SharePoint Designer the display form (DispForm.aspx) of the SharePoint list containing the address information. Then, we want to use the data view to generate the map. (Yet another reason why we call data view the swiss army knife of web parts...) Below are the detailed steps to do this:

  1. In SharePoint Designer, open up DispForm.aspx under the Suppliers folder.
  2. Bring up the Data Source Library task pane.
  3. Select the Suppliers list and drag it onto the design surface, below the default list form controls.
  4. Bring up the Common Data View Tasks menu for the data view.
  5. Pick the Filter option.
  6. In the Filter Criteria dialog:
    1. Field Name = ID
    2. Comparison = Equals
    3. Value = Create a new parameter
  7. In the Data View Parameters dialog:
    1. Name your parameter (i.e. SupplierID)
    2. Parameter Source = Query String
    3. Query String Variable = ID
    4. Default Value = 36 (optional, I prefer to enter a # that maps to an item that I know already exists in my list)
  8. Hit OK and OK.

Note - All standard SharePoint forms contain an ID parameter in the query section of the URL:


Each item in a SharePoint list is mapped to a unique ID value. This ID value is what we're using to filter the data view.

As a result, we’ve just inserted a data view of the suppliers list that is filtered down to show ONLY the current supplier and not all other suppliers. Right now, the data view is still rendered as a table by the default XSLT. Next step, we’re going to write custom XSLT and JavaScript to format the data view as a map!

Step 2 - Use custom XSLT + JavaScript to create Virtual Earth Map control

In order to create the Virtual Earth Map control, we’ll need to utilize some JavaScript functions provided by the Virtual Earth SDK. Below are JavaScript snippets that we need.

Load the map

var map;


// Loads the Virtual Earth map control

function loadMyMap() {

            map = new VEMap(&&apos;myMap&apos;);


            map.FindLocation &apos;<xsl:value-of select="@WorkAddress" />,     <xsl:value-of select="@WorkCity" />, <xsl:value-of select="@WorkState" />,  <xsl:value-of select="@WorkZip" />&apos;, displayPushPinCallBack);


FindLocation() will take the address values passed in and center the map to that location. This is a great function! For the function parameters, we’re passing in the XSL values of the Address, City, State and Zip Code field of the supplier.

Add the pushpin

function displayPushPinCallBack() {

      var pin = new VEPushpin(




          &quot;<xsl:value-of select="@Title" />&quot;,





GetCenter() will return the longitude and latitude values of the center of the map, which is currently the location of the address you passed in from FindLocation(). We’re also passing in the XSL value of the Title field of the supplier.

The entire XSL stylesheet

Here’s the entire XSL that we will use to format the data view into a Virtual Earth Map control.

<?xml version="1.0" encoding="utf-8" ?>

<xsl:stylesheet version="1.0" xmlns:xsl="">

  <xsl:output method="html" indent="no"/>

  <xsl:template match="/">

    <xsl:call-template name="dvt_1"/>


  <xsl:template name="dvt_1">

    <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />

    <xsl:call-template name="dvt_1.body">

      <xsl:with-param name="Rows" select="$Rows" />



  <xsl:template name="dvt_1.body">

    <xsl:param name="Rows" />


    <!-- Link to the Virtual Earth Map control JS file -->

    <script src="">


    <xsl:for-each select="$Rows">

      <xsl:call-template name="dvt_1.rowview" />



  <xsl:template name="dvt_1.rowview">

    <div id='myMap' style="width:650px; height:400px;"></div>

    <script type="text/javascript">


      _spBodyOnLoadFunctionNames.push(&quot; loadMyMap &quot;);

      var map;

      // Loads the Virtual Earth map control

      function loadMyMap() {

          map = new VEMap(&apos;myMap&apos;);


          map.FindLocation(&apos;<xsl:value-of select="@WorkAddress" />,

<xsl:value-of select="@WorkCity" />,

<xsl:value-of select="@WorkState" />,

<xsl:value-of select="@WorkZip" />&apos;, displayPushPinCallBack);


      function displayPushPinCallBack() {

          var pin = new VEPushpin(




            &quot;<xsl:value-of select="@Title" />&quot;,








  • _spBodyOnLoadFunctionNames() adds a function to the onload event of the body element. This ensures that loadMyMap() is called whenever the display form is loaded. The Using Javascript to Manipulate a List Form Field blog has a more detailed description of this.
  • The actual XSL is pretty basic. We’re simply using XSL to generate the <div> container for the map control and also passing in XSL values for the JavaScript function calls.

Next thing you'll want to do is take that entire XSL stylesheet and save it out as a separate XSL file. This will make things a lot cleaner and easier to manage. We'll save this out into a file called LiveMaps.xsl, and store it in the folder for the Suppliers list, along with the DispForm.aspx.

Step 3 - Format the data view using LiveMaps.xsl

Now we want to use LiveMaps.xsl to render the data view.

  1. Go back to DispForm.aspx in SharePoint Designer.
  2. Right-click on the data view, which is a Data Form Web Part.
  3. Select Web Part Properties.
  4. Expand the Miscellaneous category.
  5. For XSL Link, click on the button to the right of the input field.
  6. Navigate to the LiveMaps.xsl file and select it.

All Done!

Back on the browser, when you go to the display form of any supplier, there’ll be a great map view that will show you the location of the supplier. You’ll be able to interact with the map, just like you would on



  • Nick recently blogged about a new web part available for users of his BDC Meta Man tool that allows users

  • Works great.

  • Very Cool... Thanks

  • Microsoft's Virtual Earth technology powers the maps on Live Search and many other web-based applications,

  • Nice sample and walkthrough.  I would like to build this into a contact list and then save the list as a template, so all new contact lists on the site have the functionality available.  However, the map data view has the original List ID hardcoded from designer.  How can I make the List ID a parameter (similar to the record ID) so it can be changed dynamically and context sensitive to the calling list?  The List ID is not located int he URL, so can it be bound from a different location?

  • Just found the answer to my previous question, so I thought I would share.  When the data view is created, the List ID is bound to a hardcoded default value.  Simply modify the parameter binding so the correct List ID is acquired from CAML.  This appears to work OK in the limited testing I have performed thus far...


    <ParameterBinding Name="ListID" Location="None" DefaultValue="..."/>


    <ParameterBinding Name="ListID" Location="CAMLVariable" DefaultValue="CurrentListID"/>

  • I'm still doing something wrong. I don't have much experience with SharePoint designer but this demo looked pretty easy. I'm still getting "Unable to display this webpart."

    Maybe I did something wrong when I added the data view

  • Simon: check out

    Chad E/Shankar: I just answered the driving directions question in the comments of the above post - i that should get you going.

    This code should still work just fine, but I will verify. There have been a few changes between v4 and v6 (the current release of VE as of today) - check out for more info. They have a link that indicates what is new.

  • Thanks Jon- that worked !!

  • Works great, pretty easy.

    If I'm not using a contact list, but a custom list I just need to change the variables names in the map,FIndLocation() right?

    The page is showing a VE error for the address, including "<div>" in the address, any help here?

    THe name of the pinpoint is defined by what variable in the code?

  • Any tip on how to display all pinpoints from the list?

  • Daniel: for plotting multiple points, check out I am in the process of putting something together that is new and improved for all those people wanting batch geocoding, so stay tuned.

    As for your question about the pushpin -

    function displayPushPinCallBack() {

             var pin = new VEPushpin(

               1, // this is the ID of the pushpin. you can use it modify the pushpin via javascript later if you want to, but for most people this is just something you have to set. When you are displaying multiple pins you should be sure that this is unique.

               map.GetCenter(), // this is where you want the pushpin. since findlocation sets the center of the map over your address, you can use GetCenter() to grab the coordinates.

               null, // the custom icon for your pushpin (i think). note that this has changed in the current SDK

               &quot;<xsl:value-of select="@Title" />&quot;, // this is the title/name of your pushpin. you can put whatever you want here

               &apos;&apos; // this is the description of your pushpin. you can put whatever you want here - images, text, links, tables, etc. I have even hosted an iframe here with a little effort.




    If you want to change the title or description as shown in the popup, just dump in the appropriate fields or text into the spaces i mention above and you should be good to go.

  • I get the message 'unable to display this webpart'

    I have a custom list with a location, address, postal code etc..

    I have tried to use v4 and now v6 with the following :

    map.Find(null,'<xsl:value-of select="@WorkZip">');

    I loaded the stylesheet into the same directory vis SPD.

    The step 3.5 does not show me a button on the right hand side of the box but when I type the file name in it shows in the XSL.

    New to MOSS how would I debug this to see what is being loaded and when?


  • I resolved the issue I had and posted on the 20th. I changed the script to v6, removed the pushpin and added layers.

  • I'm struggling getting this to display. I am just getting a blank area at the bottom of the page.

    When I check the code rendered to the page I see and error below the line

    <script src="" type="text/javascript">

    var 1456bt="Invalid invoke target specifed.",1709ct="Invalid argument passed; both start and end must be preset .  . . .

    But I do see the correct address parameters passed in the script below.

    Any ideas?

Page 3 of 7 (99 items) 12345»
Leave a Comment
  • Please add 1 and 2 and type the answer here:
  • Post