Adding Live Maps to Microsoft CRM 3.0


I'd like to introduce Marco Amoedo Martinez, a CRM MVP from Spain and our guest blogger today.

Mapping technologies can be very useful for CRM tools. We can position customers on a map and obtain valuable information about where they are, about where we have more market share, and so on.

Microsoft provides several mapping technologies that could help us add these functionalities to our CRM. We have MapPoint, MapPoint Web services and Live Maps. While the first ones have a license cost or service fee, because they are more powerful and have more value-add functionalities, the last one is free and “simple” to use. So, Live Maps looks like a good starting point for adding maps to our CRM.

A good place to start using maps could be the account form. We will try to add a new tab with a map indicating us the location of our customer. To achieve this we will use an IFrame based customization of Microsoft Dynamics CRM.

Step One: Creating a Web page with the map

The first step is creating a new Web page with all the things needed in order to show a map using Live Maps: importing the jscript control of Live Maps, setting the div tag which will contain the map, and adding jscript code to load the map. The html looks like this:


<!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/jscript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=5" mce_src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=5"></script>

<script type="text/jscript">

var map = null;

function GetMap()

{

map = new VEMap('myMap');

map.LoadMap();

}

</script>

</head>

<body onload="GetMap();">

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

</body>

</html>


More detailed information on the Live Maps SDK.

This Web page will return a generic map, not a map showing up our customer location which is our goal. So, suppose that we have a variable with the customer address. Now we can center the map on the customer address using functions provided by the map. The script code will look like this.


var map = null;

function GetMap()

{

var address = "Emilio Gonzalez Lopez, 15011 A Coruña (A Coruña), Spain";

map = new VEMap('myMap');

map.LoadMap();

map.Find(null,address);

}


Now we have a map centered on customer’s address. But this map doesn’t reflect the exact customer location. Therefore, we will add some more code to place a pushpin in the map over the customer location using an overload of the Find function. This overload will make a call to other function when the find operation completes, and this new function will add the pushpin to the map based on the results of the find call.


var map = null;

function GetMap()

{

var address = "Emilio Gonzalez Lopez, 15011 A Coruña (A Coruña), Spain";

map = new VEMap('myMap');

map.LoadMap();

map.Find(null,address,null,null,0,10,true,true,true,true,FindCallBack)

}

function FindCallBack(shapeLayer, results, positions, moreResults, e)

{

if(positions != null && positions.length > 0)

{

latlong = new VELatLong(positions[0].LatLong.Latitude,positions[0].LatLong.Longitude);

customerPushPin = new VEShape(VEShapeType.Pushpin,latlong);

map.AddShape(customerPushPin);

}

}



Well, we now have a map that shows up the customer location based on the customer address. It would be fine if we could store the latitude and longitude of customer position instead of always try to find it using the address. As we do before, suppose that we have a latitude and longitude variables for storing customer position. Now, the jscript code will check if we already have customer’s latitude and longitude, and place the pushpin, or if it has to find them using customer’s address as we do previously. Also, we will add some code to store the latitude and longitude if we did not already have them. The script now looks like this:


var map = null;

var latitude = 43.37490;

var longitude = -8.43178;

var address = "Emilio Gonzalez Lopez, 15011 A Coruña (A Coruña), Spain";

function GetMap()

{

map = new VEMap('myMap');

map.LoadMap();

if (latitude != null && longitude != null)

{

PlacePushPin(latitude,longitude);

}

else

{

map.Find(null,address,null,null,0,10,true,true,true,true,FindCallBack);

}

}

function FindCallBack(shapeLayer, results, positions, moreResults, e)

{

if(positions != null && positions.length > 0)

{

PlacePushPin(positions[0].LatLong.Latitude,positions[0].LatLong.Longitude);

latitude = positions[0].LatLong.Latitude;

longitude = positions[0].LatLong.Longitude;

}

}

function PlacePushPin(lat, lon)

{

latlong = new VELatLong(lat,lon);

customerPushPin = new VEShape(VEShapeType.Pushpin,latlong);

map.AddShape(customerPushPin);

map.SetCenterAndZoom(latlong,15);

}


Now we have a web page that can show up the location of a customer based on his address or his latitude and longitude. We could add more functionality to this page, like for instance to allow the user to move the pushpin, give driving directions, etc. But before doing this lets proceed to integrate this Web page into Microsoft Dynamics CRM 3.0.

Step Two: Integrate Maps on CRM

As I said before, we will add the Web page to CRM’s customer form using an IFrame. But before doing this, we have to “wire” the script of the map with the CRM data. It’s quite a simple work; we only have to get/set values from/to CRM fields using jscript for latitude, longitude and address (see the CRM SDK page about this). The code will look like this:


var map = null;

var latitude = null;

var longitude = null;

var address = "";

function GetMap()

{

// Try to get lat&long from the CRM

latitude = parent.document.forms[0].all.address1_latitude.DataValue;

longitude = parent.document.forms[0].all.address1_longitude.DataValue;

//Get adress from CRM

var addressLine1 = parent.document.forms[0].all.address1_line1.DataValue;

var postalCode = parent.document.forms[0].all.address1_postalcode.DataValue;

var city = parent.document.forms[0].all.address1_city.DataValue;

var stateOrProvince = parent.document.forms[0].all.address1_stateorprovince.DataValue;

var country = parent.document.forms[0].all.address1_country.DataValue;

//Compose customer address

address = addressLine1+", "+postalCode+" "+city+" ("+stateOrProvince+"), "+country;

map = new VEMap('myMap');

map.LoadMap();

if (latitude != null && longitude != null)

{

PlacePushPin(latitude,longitude);

}

else

{

map.Find(null,address,null,null,0,10,true,true,true,true,FindCallBack);

}

}

function FindCallBack(shapeLayer, results, positions, moreResults, e)

{

if(positions != null && positions.length > 0)

{

PlacePushPin(positions[0].LatLong.Latitude,positions[0].LatLong.Longitude);

latitude = positions[0].LatLong.Latitude;

longitude = positions[0].LatLong.Longitude;

parent.document.forms[0].all.address1_latitude.DataValue = latitude;

parent.document.forms[0].all.address1_longitude.DataValue = longitude;

}

}

function PlacePushPin(lat, lon)

{

latlong = new VELatLong(lat,lon);

customerPushPin = new VEShape(VEShapeType.Pushpin,latlong);

map.AddShape(customerPushPin);

map.SetCenterAndZoom(latlong,15);

}


Notice that the GetMap method now retrieves the value of CRM fields for address, latitude and longitude. Also, in the FindCallBack method we update CRM fields for storing latitude and longitude.

Before continuing, we must place the Web page file in a virtual directory within the IIS web server that contains CRM. The best option is to create a new virtual directory under CRM’s site and place the Web page on it (i. e.: crm.plainconcepts.com/livemaps/), since adding it directly to CRM’s Web site is not supported.

Now we have the Web page ready to be integrated with CRM. So let’s go customize the account form with the IFrame and fields to storing latitude and longitude.


  • Open your CRM web client.

  • Go to Settings | Customization | Customize entities and open account entity.

  • Select Forms and Views, select the entity form and open it.

  • Add a new tab, click on “Add a Tab” at the right side. Set a name (i. e.: Map) and click Ok.

  • Create a new Section, click on “Add a Section” at the right side. Set a name (i. e.: Customer’s Location), in the tab option select the new tab and press Ok.

  • Next, we have to add address1_latitude and address1_longitude to the form (these system fields are intended to store latitude and longitude). Click “Add fields”, select the fields, and select the tab and the section that you have just created.

  • Now we have to add an IFrame, select “Add an IFrame”. On the dialog enter the name of the IFrame, select the tab and the section that you have just created and uncheck the option to restrict cross-frame scripting. On the URL field, type the location of the Web that we have created to show maps (i. e.: crm.plainconcepts.com/livemaps/AccountMap.htm).

  • At the Formatting tab set the options that you want for the appearance of the IFrame.

  • At the Dependencies tab select the account fields used on the jscript code: address1_line1, address1_city, address1_postalcode, address1_stateorprovince, address1_country, address1_latitude and address1_longitude.

  • Save and close the form, and then publish the customizations (select Actions -> Publish).


Only one more customization is left for our solution to works correctly. The attributes address1_latitude and addres1_longitude must be modified to accept the value range used for storing coordinates at Live Maps (Latitude: -90 to 90, Longitude: -180 to 180).


  • Go to the account customization form select attributes, and open the attribute address1_latitude.

  • Change the precision to 5 and the range value from -90 to 90.

  • Repeat the same for address1_longitude but with the range value from -180 to 180.

A precision of 5 is not very accurate. Live maps works with 14 decimals (a double precision floating point), but for our purpose is sufficient since we will lose only some meters. This lost of precision could be mitigated if we make some kind of transformation between CRM and Live Map data.

Conclusion

As we have shown here, adding a map to the CRM is not so complex. The possibilities of this kind of integration are enormous and it could add a great value to our CRM. I leave you a more complete example of this integration with Live Maps. This example also supports moving pushpins and giving driving directions, and it could be illustrative on how to customize live maps. I hope it be useful to you.



Marco Amoedo Martinez


Some answers to the comments below:


-------


Mike:  Make sure that your are using map.find() method passing the correct address as an argument. Also, try to put the same address string in maps.live.com and see what happens. Virtual Earth is still in enhancement for address outside the US, in Spain there are also some address that are not find correctly.


Serge: I am trying to figure what is failing but I cannot find the problem. Give more details of the error, and I will try to help you. About showing several accounts on the same map, you could achieve this using a multi-selection button on account’s grid. Take a look to this example on the SDK http://msdn2.microsoft.com/en-us/library/bb267367.aspx


Andrew: The Web Page is the responsible for getting the data from CRM Form when is loaded. If you give a look to the Onload event of the HTML page showed on the IFrame you will see that there is some jscript code that retrieves the data from the CRM Form.


Paul:  There is a line of Jscript code on the HTML page that composes the string of the address to search on the map. Try to modify this line to only use the postal code and the country.

Comments (24)

  1. Great article, just wanted to point out that Virtual Earth is free for development purposes but will require licensing for production systems.

    http://www.microsoft.com/virtualearth/faq.mspx

    ==========================

    John O’Donnell

    Microsoft CRM MVP

    http://www.crowecrm.com

  2. El del CRM says:

    Las dos últimas semanas he estado bastante atareado, ya casi están aquí las vacaciones y hay que dejar

  3. Marco: Great post! Thanks for all the detail and hard work. Can’t wait to test it all out.

    -Matt Wittemann

    Microsoft CRM MVP

  4. Pmarius says:

    I hate to make negative comments on the heel of such a well written article and example of Marco’s stellar development skills.  But let me ask a simple question to the community and the microsoft Program and Product mangers that read this blog.  

    Why is a mapping solution not built into the product? There was a basic one in v 1.2.  It was at least something you could choose during install, or turn on and off in the isv.config file, it help demo the product, and it showed the power of a web application.  And actually my guys actuall used it.

    It is goofey that a customer has to hire a developer to write an unsupported application to work with CRM to generate what has been shown here to be a relatively simple process. I know that John O’Donnell and his team can do this, so can my team, sure we have visual studio and developers, and write code. But I don’t think that Joe sales manager, Rather Gale Sales Manager, and her part time IT guy can make this work.  It is just too fricken complicated for 90% of the people running this product to put a Map point tab on an account that draws a map from thier office to the customers address.  

    To do this you need:

    1) Have to Own Visual Studio

    2) Have to sign up for a map point account, which ain’t simple.

    3) Have to pour thru 57 blog articles to get find the code.

    4) Test

    5) Recompile

    6) Call Support

    7) Hang up

    4) etc……

    Get the drift, complicated! We are putting customers thur 3 hours of developer time, a design document, an engagment letter with their partner, a pilot group to approve the design, a rework, and a sign off meeting, which will come to about 3,000 bucks billing and lost productivity to put a web map on the form of a web based application that points to a web service that is run by the company that they bought the CRM app from. It should not be this complicated.  Kind of reminds me of that "Microsoft iPod" marketing video.  Just overly complicated.  

    Just one man’s late night "rage against the machine"  

  5. jseidens says:

    Have to agree. This is something that should already be integrated into CRM out-of-the-box. Dynamics GP has had it for quite some time and we do have customers that both use and require this type of functionality as part of their Contact Management application. We are going to "attempt" to follow this article and see if we can get it working in a Development environment while tracking time, effort and grunts of frustration. We are not a Development house and do not intend to be but if it is as simple as stated, that would indeed be sweet.

  6. jseidens says:

    Addendum: a couple of non-developers and we were able to get this working in under an hour. I am really impressed. Still would be "nice" to have it come with the shipped product, but our customers will really see value in this feature. Thank you for the article and the lesson.

  7. STL says:

    Hi there, I’m trying to use your script with Live Maps. I downloaded the file from http://geeks.ms/files/folders/24756/download.aspx    however, the README has a blank page on the end. Is that where the JSCRIPT should be or should I be using the jscript that is being used above?

    Thanks

  8. Marco Amoedo says:

    John: You are right; I have misunderstood the TOU. You can use Live Maps free of charge for any public application (with a limit of 100,000 transactions a day), but for private/intranet applications (like this example) an agreement should be signed with Microsoft. http://dev.live.com/terms/virtualearthoverview.aspx  

    Matt: Thank you for the comments. Your file explorer solution is also great and I am waiting to download the new Demo VPC to test it. Good luck at your new job 🙂  

    Pmarius: I understand your opinion; I also think that there are hundreds of customizations that could come “out of the box”. But I am sure that there is no time for all, and they have to be prioritized. Also, have in mind that adding maps to CRM has a lot of things to take account of: What mapping technology to use? How we can customize it? What functionalities to include? It is not so easy. I think that the great value of Dynamics CRM is the highly extensible CRM platform that permits us to give our customers the functionalities that they need. I prefer powerful and easy customization capabilities to a full featured CRM with less extensibility, but perhaps my opinion is impartial since I am a software engineer and a part of my work is to customize CRM 🙂  

    Jseiden: Thank you for the comments. I am very happy that you found this post useful and easy to understand.

    STL: The readme is ok. The blank page at the end of the readme file should not contain anything.  The script code is at the HTML pages that you should put in your IIS Server as indicated at the readme, and then you use them within an Iframe on the CRM.

  9. Mark Coleman says:

    Anyone try to get this to work on a laptop running the MSCRM laptop client? I get an onload error Access Denied, and a full map of the US is displayed. It works great on the same laptop through the MSCRM web access and also on any outlook desktop client. It doesn’t work on a laptop client.

    Any help would be much appreciated as this is a pretty cool integration.

  10. Paul says:

    Great tip and I’ve been trying to make it work in the UK, however I believe the address format being passed to live maps is not being understood.  For my needs we only need to pass the post code, I’ve tried stripping parts out of the code but it’s still picking the full address up.  

    Can anyone shed some light ?!

    Can’t wait to get this functionality working !

  11. The address seems to be searching first in the US, is there a way to default the map to the UK as it does when you visit live.maps.com.  

    I’m hoping this will correct the address issues we are having as they are resolving to the USA first.  (IE if we enter a postcode it finds a location in the us, but if we do the same in live.maps.com it finds the correct postal code in the uk)..

    PS Absolutly excellent article and use for the ever adaptable CRM.  – Well done.

  12. Andrew says:

    Hi Marco.  I also followed the instructions to a T but can’t seem to make it work either.  I feel like I’m missing something crutial.  Is there code in the OnLoad pae that I’m missing?  What causes the web page in my iFrame to make the call to CRM getting the address data, transfer it to the map webpage and then return the map with the CRM Account’s coordinates?

  13. Evan says:

    I’m also having trouble getting the maps to work.  I followed the instructions, but nothing comes up in the maps section.

  14. Serge says:

    Marco,

    I tried your code and it worked fine. The only thing doesn’t work is print option. When report previewed, Map doesn’t show customer’s address and I see the error stating:

    var lat = parent.document.forms[0].all.address1_latitude.DataValue;

    Value is Null or Object not set…

    Can you help please?

    Also, how we can preview multiple contacts locations on the map?

  15. EED says:

    This is fabulous!  Thanks for the info.  Everything works great.

  16. Mike says:

    I can not get this customization to work for some reason. I am returning a map in the iFrame, however it is just a generic map of the middle of the US, from very far away. Any idea what would cause me to get this return??

  17. Mike says:

    I used this code for a custom entity. I changed the html to match all of the schema names on my custom form. The iFrame only returns a generic map of the US, from far away. Anybody else hae this problem, or know why I might not be returning the map I need?

  18. DeniseG says:

    please remove me from alerts

  19. Nate Olson says:

    This is an excellent article.  I followed the instructions to a T and it worked perfect for a couple weeks now I am getting a generic map of the US with the Access Denied error.  This seems to have something to do with the parent.document.forms[0].all.address1_latitude.DataValue line it seems to loose access to the parent.  Any ideas?

  20. Sean T says:

    This is probably a simple case of an unknown requirement for MS Live Maps… why does this not work in IE and not Firefox 2 or FF3?  That must be why it’s free for up to 100k requests…

  21. Bassamahmad says:

    Hi there:

    Thank you for your great integration example.

    You mentioned that you "must place the Web page file in a virtual directory within the IIS web server that contains CRM". Is this a CRM requirement? And is there other way to integrate a Web page on another server in iFrame without getting “Access Denied” when the JavaScript try to assign a value in CRM field?

    Thank you,

    Bassam

  22. Jay says:

    Hello,

    I am trying to make this work with CRM 4.0.  All of the attribute names are the same but regardless of the address that I use the lat and long are always geocoded to the same place in france.  Any ideas?

  23. kevin says:

    Hello,

    I am also trying to get this to work in CRM 4.0, like Jay.  Any solution out there?

  24. Caitlin says:

    I have the same question as Bassamahmad — I am using CRM Online, so it would be much better if I could upload the map file to my regular website and call it from there…but I’m guessing it’s not being able to access the parent CRM form. When I try the first two examples I get maps fine, but when I use the CRM data it just goes blank – no error. Help would be appreciated.

Skip to main content