Skip to main content

Notifications

Announcements

No record found.

Microsoft Dynamics CRM (Archived)

Address and Location Capture in Dynamics CRM with Bing Maps

Posted on by Microsoft Employee

Hi,

I have found details in a 2013 bing blog on an HTML web resource that can be placed within a custom entity and will allow you to place a marker on the map and then use this maps location to back fill location fields on the form.

I can get the map onto the form, but it will not complete the back filling of location information.

My guess given the age of the post is that the code employed is now out of date...however I have virtually no experience with this so am clueless on where to start making changes to get it to work with latest online version of CRM.

HTML template (minus bing key):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "www.w3.org/.../xhtml1-transitional.dtd">
<html>
<head>
<title>Address and Location Utility</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<style type="text/css">
body {
font-family: Verdana;
font-size: 10px;
width: 100%;
height: 100%;
position: absolute;
left: 0px;
top: 0px;
margin-left: -1px;
margin-top: -1px;
}
#controls
{
position:absolute;
top:50px;
left:10px;
min-width:170px;
min-height:270px;
background-color:#faf7f5;
z-index:10000;
vertical-align:middle;
font-size:11px;
border: 3px #BDBDBD solid;
padding: 5px;
}
.input
{
margin-top: 3px;
margin-bottom: 3px;
display:block;
clear: both;
}
.pinDetail {
display:block;
clear: both;
font-size:11px;
}
.button {
margin-bottom: 15px;
}
</style>


<script type="text/javascript" src="ecn.dev.virtualearth.net/.../mapcontrol.ashx;amp;s=1"></script>
<!-- We include JQuery from the Microsoft Ajax CDN to assist with our 'Updated' forms attribute values access -->
<script type="text/javascript" src="ajax.aspnetcdn.com/.../jquery-2.0.2.min.js"></script>
<script type="text/javascript">

// Global variables:
var map = null;
var pushpin;
var infobox = null;
var revgeoPushpin = null;
var crmFormType;

// Initiate map:
function GetMap() {
map = new Microsoft.Maps.Map(document.getElementById("mapDiv"), {
credentials: "REMOVED",
zoom: 3, center: new Microsoft.Maps.Location(40.347, -94.218),
mapTypeId: Microsoft.Maps.MapTypeId.birdseye
});

// extend pushpin class to hold geocoding data:
Microsoft.Maps.Pushpin.prototype.geoname = null;
Microsoft.Maps.Pushpin.prototype.geoentitytype = null;
Microsoft.Maps.Pushpin.prototype.geoaddress = null;
Microsoft.Maps.Pushpin.prototype.geoconfidence = null;
Microsoft.Maps.Pushpin.prototype.geomatchcodes = null;
Microsoft.Maps.Pushpin.prototype.geocalculationmethod = null;
Microsoft.Maps.Pushpin.prototype.geopindragged = null;
Microsoft.Maps.Pushpin.prototype.geoaddressrevgeo = null;

// Get CRM Form Type, to choose behavior based on
// Updated or Classic forms:
crmFormType = parent.Xrm.Page.ui.getFormType();

}

// pushpin drag handler flags the pushpin as having been dragged
function dragHandler(e) {
hideInfoBox();
e.entity.geopindragged = true;
}

// Take user-entered coordinates, and add pushpin in that location:
function showLatLon() {

// Clear existing entities:
map.entities.clear();

// get user input coordinates
var lat = document.getElementById("txtLat").value;
var lon = document.getElementById("txtLon").value;

// Validate coordinates
if (isLatLonValid(lat, lon) === false) {
alert('Please enter valid WGS84 decimal values for Latitude and Longitude.');
return false;
}

// Display location with pushpin:
var latlonLocation = new Microsoft.Maps.Location(lat, lon);
map.setView({ zoom: 12, center: latlonLocation });
var pushpin = createPushpin(latlonLocation, "1");
pushpin.geoname = "Manually Entered Location";

// Add pushpin to map, and open infobox:
map.entities.push(pushpin);
showInfoBox(pushpin);

}

// Validate if numeric
function isNumber(input) {
return ((input.length > 0) && ((input - 0) == input));
}

// Validate lat/long pair:
function isLatLonValid(lat, long) {
if ((lat == '') || (isNumber(lat) == false) || (lat > 90) || (lat < -90)) {
return false;
}
if ((long == '') || (isNumber(long) == false) || (long > 180) || (long < -180)) {
return false;
}
return true;
}


// clear map and retrieve credentials for REST Locations request:
function geocodeAddress() {
map.entities.clear();
map.getCredentials(callGeocodeService);
}

// call geocoding service with user-entered location details:
function callGeocodeService(credentials) {
var searchRequest = 'dev.virtualearth.net/.../Locations' +
document.getElementById("txtWhere").value +
'?output=json&jsonp=geocodeServiceCallback&key=' + credentials;
var mapscript = document.createElement('script');
mapscript.type = 'text/javascript';
mapscript.src = searchRequest;
document.getElementById('mapDiv').appendChild(mapscript);
}

// call reverse-geocoding service with current pushpin location:
function callReverseGeocodeService(credentials) {
// Get pushpin location:
var pinLocation = revgeoPushpin.getLocation();
var searchRequest = 'dev.virtualearth.net/.../Locations' + pinLocation.latitude + "," + pinLocation.longitude + '?output=json&jsonp=revgeoServiceCallback&key=' + credentials;
var mapscript = document.createElement('script');
mapscript.type = 'text/javascript';
mapscript.src = searchRequest;
document.getElementById('mapDiv').appendChild(mapscript);
}

// Callback for REST Locations request:
function revgeoServiceCallback(result) {

if (result &&
result.resourceSets &&
result.resourceSets.length > 0 &&
result.resourceSets[0].resources &&
result.resourceSets[0].resources.length > 0) {
// Take only first result:
var revgeoResult = result.resourceSets[0].resources[0];
var location = new Microsoft.Maps.Location(revgeoResult.point.coordinates[0], revgeoResult.point.coordinates[1]);

// get calculation method:
var calculationMethod = getCalcMethod(revgeoResult);

// Add geocoding metadata to appropriate pin:
revgeoPushpin.geoname = revgeoResult.name;
revgeoPushpin.geoentitytype = revgeoResult.entityType;
revgeoPushpin.geoaddress = revgeoResult.address;
revgeoPushpin.geoconfidence = revgeoResult.confidence;
revgeoPushpin.geomatchcodes = revgeoResult.matchCodes;
revgeoPushpin.geocalculationmethod = calculationMethod;
revgeoPushpin.geoaddressrevgeo = true;


// Open infobox for revgeo pin:
showInfoBox(revgeoPushpin);
}
else {
if (result && result.errorDetails) {
alert("Message :" + response.errorDetails[0]);
}
alert("No results for the query");
}
}

// Callback for REST Locations request:
function geocodeServiceCallback(result) {

if (result &&
result.resourceSets &&
result.resourceSets.length > 0 &&
result.resourceSets[0].resources &&
result.resourceSets[0].resources.length > 0) {
var results = result.resourceSets[0].resources;
var locationArray = new Array();
for (var j = 0; j < results.length; j++) {

var location = new Microsoft.Maps.Location(results[j].point.coordinates[0],
results[j].point.coordinates[1]);
var pushpin = createPushpin(location, (j + 1).toString());

// get calculation method:
var calculationMethod = getCalcMethod(results[j]);

// Add geocoding metadata to pin:
pushpin.geoname = results[j].name;
pushpin.geoentitytype = results[j].entityType;
pushpin.geoaddress = results[j].address;
pushpin.geoconfidence = results[j].confidence;
pushpin.geomatchcodes = results[j].matchCodes;
pushpin.geocalculationmethod = calculationMethod;
pushpin.geopindragged = false;
pushpin.geoaddressrevgeo = false;

// Add pin to map:
map.entities.push(pushpin);

// Add location to array for map auto-scaling:
locationArray.push(location);
}

// Set view depending on whether result is unique or not:
if (results.length == 1) {
var bbox = results[0].bbox;
var viewBoundaries = Microsoft.Maps.LocationRect.fromCorners(new Microsoft.Maps.Location(bbox[0], bbox[1]),
new Microsoft.Maps.Location(bbox[2], bbox[3]));
map.setView({ bounds: viewBoundaries });
} else {
// Show a best view for all locations
var viewBoundaries = Microsoft.Maps.LocationRect.fromLocations(locationArray);
map.setView({ bounds: viewBoundaries, padding: 75 });
}
// Open infobox for top result:
showInfoBox(map.entities.get(0));
}
else {
if (result && result.errorDetails) {
alert("Message :" + response.errorDetails[0]);
}
alert("No results for the query");
}
}

// obtain calculation method from a location result:
function getCalcMethod(result) {

// Identify the calculation method for our display point:
var calculationMethod = "";
if (result.geocodePoints && result.geocodePoints.length != null) {
// loop through to find the calculation method for the geocodePoint of type 'Display':
for (var k = 0; k < result.geocodePoints.length; k++) {
if (result.geocodePoints[k].usageTypes.toString().match(/Display/)) {
calculationMethod = result.geocodePoints[k].calculationMethod;
}
}
}
return calculationMethod;

}

// Create pushpin with appropriate options and event handlers:
function createPushpin(location, label) {
var pushpin = new Microsoft.Maps.Pushpin(location, { draggable: true, text: label });
var pushpinclick = Microsoft.Maps.Events.addHandler(pushpin, 'click', pinClickHandler);
var pushpindragend = Microsoft.Maps.Events.addHandler(pushpin, 'drag', dragHandler);
return pushpin;
}

// hide any existing info boxes:
function hideInfoBox() {
//Hide existing infoboxes
try {
infobox.setOptions({ visible: false });
}
catch (err) {
}
}

// Show infobox for a specific pushpin:
function showInfoBox(pushpin) {

//Hide other infoboxes
hideInfoBox();

// Get pushpin location:
var pinLocation = pushpin.getLocation();

// Create the info box content for the pushpin
var description = "<div class='pinContent' style='border=1'>";
if (pushpin.geoentitytype != null) { description += "<div class='pinDetail'><b>Entity type:</b> " + pushpin.geoentitytype + "</div>" };
if (pushpin.geoconfidence != null) { description += "<div class='pinDetail'><b>Confidence:</b> " + pushpin.geoconfidence + "</div>" };
if (pushpin.geomatchcodes != null) { description += "<div class='pinDetail'><b>Match Codes:</b> " + pushpin.geomatchcodes + "</div>" };
if (pushpin.geocalculationmethod != null) { description += "<div class='pinDetail'><b>Calculation Method:</b> " + pushpin.geocalculationmethod + "</div>" };
description += "<div class='pinDetail'><b>Lat:</b> " + pinLocation.latitude + "</div>";
description += "<div class='pinDetail'><b>Lon:</b> " + pinLocation.longitude + "</div>";
if (pushpin.geoaddressrevgeo == true) { description += "<div class='pinDetail'><b style='color:red'>Alert: Address from RevGeo</b></div>" };
if (pushpin.geopindragged == true) { description += "<div class='pinDetail'><b style='color:red'>Alert: Pin Dragged</b></div>" };
description += "</div>";

// Determine infobox height based on specific pieces of content:
var infoboxHeight = 180;
infoboxHeight += (Math.max(0, (Math.ceil(pushpin.geoname.length / 25) - 1))) * 18;
if (pushpin.geopindragged) infoboxHeight += 15;
if (pushpin.geoaddressrevgeo) infoboxHeight += 15;

infobox = new Microsoft.Maps.Infobox(pinLocation, { title: pushpin.geoname, description: description, offset: new Microsoft.Maps.Point(7, 25), visible: true, zIndex: 1000, height: infoboxHeight });
infobox.setOptions({
actions: [
{
label: "Zoom",
eventHandler: function (mouseEvent) {
// Zoom to pin location:
map.setView({ zoom: 17, center: pinLocation });
}
},
{
label: "Reverse Geocode",
eventHandler: function (mouseEvent) {

// initiate reverse geocode:
revgeoPushpin = pushpin;
map.getCredentials(callReverseGeocodeService);

}
},
{
label: "Populate Form",
eventHandler: function (mouseEvent) {

// Geocoding metadata will be available as properties of pushpin object

// If using 'Classic Forms' (not the Read-Only forms of type 11):
if (crmFormType != 11) {
var controls = parent.Xrm.Page.ui.controls;
controls.get("address1_latitude").getAttribute().setValue(pinLocation.latitude ? pinLocation.latitude : "");
controls.get("address1_longitude").getAttribute().setValue(pinLocation.longitude ? pinLocation.longitude : "");
controls.get("address1_line1").getAttribute().setValue(pushpin.geoaddress.addressLine ? pushpin.geoaddress.addressLine : "");
controls.get("address1_city").getAttribute().setValue(pushpin.geoaddress.locality ? pushpin.geoaddress.locality : "");
controls.get("address1_stateorprovince").getAttribute().setValue(pushpin.geoaddress.adminDistrict ? pushpin.geoaddress.adminDistrict : "");
controls.get("address1_postalcode").getAttribute().setValue(pushpin.geoaddress.postalCode ? pushpin.geoaddress.postalCode : "");
controls.get("address1_country").getAttribute().setValue(pushpin.geoaddress.countryRegion ? pushpin.geoaddress.countryRegion : "");
} else {

// Use workaround to populate address properties in Updated Process forms:
// TO-DO: revisit after Orion release:
prepAttribute('address1_line1');
prepAttribute('address1_city');
prepAttribute('address1_stateorprovince');
prepAttribute('address1_postalcode');
prepAttribute('address1_country');
prepAttribute('address1_latitude');
prepAttribute('address1_longitude');
setFormValue('address1_line1', (pushpin.geoaddress.addressLine ? pushpin.geoaddress.addressLine : ""));
setFormValue('address1_city', (pushpin.geoaddress.locality ? pushpin.geoaddress.locality : ""));
setFormValue('address1_stateorprovince', (pushpin.geoaddress.adminDistrict ? pushpin.geoaddress.adminDistrict : ""));
setFormValue('address1_postalcode', (pushpin.geoaddress.postalCode ? pushpin.geoaddress.postalCode : ""));
setFormValue('address1_country', (pushpin.geoaddress.countryRegion ? pushpin.geoaddress.countryRegion : ""));
setFormValue('address1_latitude', (pinLocation.latitude ? pinLocation.latitude : ""));
setFormValue('address1_longitude', (pinLocation.longitude ? pinLocation.longitude : ""));

}
}
}
]
});

map.entities.push(infobox);
}

// obtain clicked pushpin, and open infobox:
function pinClickHandler(e) {
if (e.targetType = "pushpin") {
//Hide other infoboxes
hideInfoBox();
// open infobox for target pushpin:
showInfoBox(e.target);
}
}

// Click on attribute controls in Polaris-style, "Updated" forms:
// TO-DO: Review this methodology after Orion release
function prepAttribute(attribute) {
var winParent = (parent == null) ? document.defaultView : window.parent;
if (winParent != null) {
var attrDivs = $(winParent.window.document).find("div[data-attributename='" + attribute + "']");
$(attrDivs).each(function () {
$(this).children().each(function () {
if ($(this).prop("tagName") == "DIV") {
winParent.window.Mscrm.Utilities.click($(this));
}
});
});
} else {
alert("An error occurred on prepare");
}
};

// Update attributes in Polaris-style, "Updated" forms:
// TO-DO: Review this methodology after Orion release
function setFormValue(attribute, value) {
var winParent = (parent == null)? document.defaultView: window.parent;
if (winParent != null) {
var attrDivs = $(winParent.window.document).find("div[data-attributename='" + attribute + "']");
$(attrDivs).each(function () {
$(this).children().each(function () {
if ($(this).prop("tagName") == "DIV") {
winParent.window.Mscrm.Utilities.click($(this));
var txt = $(this).find("[attrname='" + attribute + "']");
if (txt.length > 0)
$(txt).val(value);
}
});
});
} else {
alert("An error occurred on update");
}
};


</script>
</head>
<body onload="GetMap();">
<div id='mapDiv' style="position:absolute; width:100%; height:100%;"></div>
<div id="controls">
<div class="input"><h2>Geocode Tools</h2></div>
<div class="input"><b>Geocode Address:</b></div>
<div class="input"><input id="txtWhere" type="text" size="20" /></div>
<div class="input"><input id="GeocodeButton" type="button" value="Go" onclick="geocodeAddress()" class="button" /></div>
<div class="input"><b>Show location:</b></div>
<div class="input"><i>Latitude:</i></div>
<div class="input"><input id="txtLat" type="text" size="20" /></div>
<div class="input"><i>Longitude:</i></div>
<div class="input"><input id="txtLon" type="text" size="20" /></div>
<div class="input"><input id="LatLonButton" type="button" value="Go" onclick="showLatLon()" class="button" /></div>
</div>
</body>
</html>

*This post is locked for comments

  • Community Member Profile Picture
    Community Member Microsoft Employee on at
    RE: Address and Location Capture in Dynamics CRM with Bing Maps

    Hi Prashant,

    Thanks for the response, I assumed that it was probably use of out of date code...but I am not a computer coder so I am a little clueless how I implement the required changes to the above code based on the link you sent through...

    Can you help??

    Liam

  • Suggested answer
    Prashant_ Profile Picture
    Prashant_ 1,040 on at
    RE: Address and Location Capture in Dynamics CRM with Bing Maps

    You are using old bing library I believe you have to use new one i.e. V8 .Following link will help you create reverse geocoding scenario.

    https://www.bing.com/api/maps/sdk/mapcontrol/isdk/searchbypoint

      

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

December Spotlight Star - Muhammad Affan

Congratulations to a top community star!

Top 10 leaders for November!

Congratulations to our November super stars!

Tips for Writing Effective Suggested Answers

Best practices for providing successful forum answers ✍️

Leaderboard

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 291,269 Super User 2024 Season 2

#2
Martin Dráb Profile Picture

Martin Dráb 230,198 Most Valuable Professional

#3
nmaenpaa Profile Picture

nmaenpaa 101,156

Leaderboard

Featured topics

Product updates

Dynamics 365 release plans