THURSDAY, JANUARY 19, 2017

Open Google Map from a Location Record

T

his week I’m blogging from Knowledge13 in Las Vegas! So far it’s been a fantastic conference with lots of great content and it’s been fun to meet with so many people interested in improving their ServiceNow implementation. I’m really looking forward to the Fred Luddy keynote this morning. Jacob Andersen and I are here representing our ServiceNow consulting company, Crossfuze Solutions and would love to talk with any of you who could benefit from working with the most experienced ServiceNow implementation and integration consultants in the industry. Stop by the BDNA booth (Booth 1216) during any of the expo times to visit with us and see some of our world-class Incident, Problem, Knowledge, Change, Catalog, CMS, and Asset Management solutions! I’ll also be participating in a sold out panel presentation at 1:40 today where we’ll discuss the importance of data quality in a ServiceNow implementation.

Okay, enough of the high-pressure sales pitch :). This morning I saw a post on the ServiceNow community asking how to display a google map based on a ServiceNow location record. I think this is a fantastic idea and I decided to see if I could come up with a couple of solutions for it this morning. In this post I’ll show you how you can set up a UI Action or UI Macro link to pop open a Google Map window based on any location record in your ServiceNow instance!

Location Google Map UI Macro

The simplest way to set up a Google Map link in ServiceNow is to use a client-side UI Action to construct the URL and pop open a new window. Google Map URLs follow a basic convention that can include the street address or latitude/longitude coordinates of the location you want to display like this…

http://maps.google.com/?q=1200 Pennsylvania Ave SE, Washington, District of Columbia, 20003

Here’s the code and configuration for a UI Action…

‘Open Google Map’ UI Action
Name: Open Google Map
Table: Location [cmn_location]
Action name: open_google_map
Show insert: false
Client: true
Form link/List context menu: true
OnClick: openGoogleMap()
Condition: (!current.street.nil() && !current.city.nil()) || (!current.latitude.nil() && !current.longitude.nil())
Comments: Shows a google map icon on a location field if the location has a street and city listed.

Crossfuze Solutions
www.crossfuze.com
Script:

//Pop open google maps window of location specified
//URL should follow this format...http://maps.google.com/?q=1200 Pennsylvania Ave SE, Washington, District of Columbia, 20003

function openGoogleMap() {
   //Retrieve the 'Location' record
   var sysId = typeof rowSysId == 'undefined' ? gel('sys_uniqueValue').value : rowSysId;
   var gr = new GlideRecord('cmn_location');
   gr.get(sysId);

   //Create and display the Map URL
   var mapURL = "http://maps.google.com/?q=";
   //Try location and city
   if(gr.street && gr.city){
      mapURL = mapURL + gr.street + ',' + gr.city + ',' + gr.state + ',' + gr.zip + ',' + gr.country;
   }
   //Else try latitude and longitude
   else if(gr.latitude && gr.longitude){
      mapURL = mapURL + gr.latitude + ',' + gr.longitude;
   }
   //Strip '#' symbols to avoid encoding errors
   mapURL = mapURL.replace(/#/g, "");
   window.open(mapURL);
}

Once the UI Action is created, you should be able to right-click a location record from a list or click the ‘Open Google Map’ link as shown here…

Location Google Map UI Action

While it’s nice to be able to open a map from a location record, it’s probably even more useful to be able to open a map directly from a referenced location record. The code for the UI Macro is a bit more complex, but once created it’s very simple to include for any reference field in your system by personalizing the dictionary entry for the location reference field (or the ‘cmn_location’ table dictionary entry if you want to include the option on every location field in your system). You can create the UI Macro using these settings.

‘open_google_map’ UI Macro
Name: open_google_map
Description:Shows a google map icon on a location field if the location has a street and city listed.
Activate by adding the attribute: ref_contributions=open_google_map to a location reference field

Crossfuze Solutions
www.crossfuze.com

Script:

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
   <g:evaluate var="jvar_guid" expression="gs.generateGUID(this);" />
   <j:set var="jvar_n" value="open_google_map${jvar_guid}:${ref}"/>

   <g2:evaluate var="jvar_show_google_map_display" jelly="true">
      var id = __ref__.getSysIdValue();
      if (id == null)
         "none";
      else {
         var loc = new GlideRecord('cmn_location');
         loc.get(id);
         if ((!loc.street.nil() $[AND] !loc.city.nil()) || (!loc.latitude.nil() $[AND] !loc.longitude.nil()))
            "";
         else
            "none";
      }
   </g2:evaluate>

   <a id="${jvar_n}"
   onclick="openGoogleMap('${ref}')"
   name="${jvar_n}"
   style="display:$[jvar_show_google_map_display]"
   title="${gs.getMessage('Open a Google Map for this location')}">
       <img border="0" src="https://maps.gstatic.com/favicon2.ico" height="16" width="16"/>   </a>

   <script>
      needsRefreshLoc = false;
      function onChange_location_show_google_map(element, original, changed, loading) {
         var s = '${ref}'.split('.');
         var referenceField = s[1];
         if (needsRefreshLoc == false) {
            needsRefreshLoc = true;
            return;
         }
         if (changed.length == 0) {
            $('${jvar_n}').hide();
            return;
         }
         var locRec = g_form.getReference(referenceField, locationGoogleMapReturn);
      }
     
      function locationGoogleMapReturn(locRec) {
         var e = $('${jvar_n}');
         if ((locRec.street $[AND] locRec.city) || (locRec.latitude $[AND] locRec.longitude))
            e.show();
         else
            e.hide();
      }
     
      //Event.observe(g_form.getControl(${ref}.split('.')[1]), 'change', onChange_cmn_location_show_google_map);
      var l = new GlideEventHandler('onChange_location_show_google_map', onChange_location_show_google_map, '${ref}');
      g_event_handlers.push(l);

      //Pop open google maps window of location specified
      //URL should follow this format...http://maps.google.com/?q=1200 Pennsylvania Ave SE, Washington, District of Columbia, 20003

      function openGoogleMap(reference) {
         var s = reference.split('.');
         var referenceField = reference.substring(s[0].length+1);
         var sysId = g_form.getValue(referenceField);
         //Retrieve the 'Location' record
         var gr = new GlideRecord('cmn_location');
         gr.get(sysId);

         //Create and display the Map URL
         var mapURL = "http://maps.google.com/?q=";
         //Try location and city
         if(gr.street $[AND] gr.city){
            mapURL = mapURL + gr.street + ',' + gr.city + ',' + gr.state + ',' + gr.zip + ',' + gr.country;
         }
         //Else try latitude and longitude
         else if(gr.latitude $[AND] gr.longitude){
            mapURL = mapURL + gr.latitude + ',' + gr.longitude;
         }
     //Strip '#' symbols to avoid encoding errors
     mapURL = mapURL.replace(/#/g, "");
         window.open(mapURL);
      }
   </script>
</j:jelly>

Once the UI Macro has been created and the ‘ref_contributions’ attribute added to the reference field or table dictionary, you should see a google map icon displayed next to your location field whenever a location is referenced that includes address or latitude/longitude details.

Location Google Map UI Macro

23 Comments

Bill Collins 10-09-2013, 01:51

I’ve made the UI Action work. Working on a modification of the UI Macro to not use reference field, but to appear at end of name field on same record which contains latitude and longitude. Does current UI Macro work as hover over? -Bill

P.S. Can’t believe I’m the first post? Awesome usefulness! Thank you.

Reply
Mark Stanger 10-09-2013, 04:40

Thanks Bill. The current macro doesn’t support the ability to hover and display the popup. Unfortunately, ServiceNow doesn’t really provide any capability to do hover popups for anything other than their own records, KB articles, and catalog items currently. I’ve looked into some CSS hacks to do it a time or two, but haven’t been able to get to a solution I was happy with.

Reply
Howard Elton 10-09-2013, 05:37

Hi Mark,
Thanks for this script! I noticed a bug though, when using it on a field that has been dot walked to from another form. The fix is below

Change this line:
var referenceField = s[1];

To
var referenceField = reference.substring(s[0].length+1);

A dot walked field has more than 2 elements when split, so only looking at the second one won’t work. The new line just removes element 0 and the “.”

I hope that makes sense. Thank you again. I have learnt a lot from this script.

Howard

Reply
Mark Stanger 10-09-2013, 05:57

Good catch! I’ve updated the UI macro code above with your fix. Thanks!

Reply
Mike Herron 11-09-2013, 02:05

Hi,

Thanks for the article. I’m struggling to get the UI Macro to appear on my records (such as Incident) where Location Name is pulled from the Location table (cmn_location)

The UI action works perfectly – when viewing on the location table itself however the UI macro just won’t appear for me :'(

I’m relatively new to SN but I’m confident I’ve done exactly as described above. Any guesses on why the UI Macro isn’t appearing? (FYI my locations have Street / City / Long / Latt populated)

Reply
Mark Stanger 11-09-2013, 08:05

I’m not sure what might be happening, but I’ve just added the configuration to the ‘Location’ field on the incident form at demo022.service-now.com. The only recommendation I can give is to go there and compare your UI macro and reference field attributes to what I’ve added there.

Reply
David Martin Clavo 30-10-2013, 08:25

Hello Mark,

It seems that the Google Maps icon at https://plus.google.com/_/favicon?domain=maps.google.com has recently doubled size to 32x32px , probably to support Retina screens.
So the line:

should be updated to:

Alternatively the icon should be uploaded as an image to ServiceNow and linked from there (although then the icon is not updated when Google decides to change it).

Cheers,
David

Reply
Mark Stanger 30-10-2013, 08:32

Thanks for the heads up! There are probably a couple of different ways to approach this. It looks like part of your comment is missing, but I’ve updated the UI macro code above to force the width and height on the image.

Reply
David Martin Clavo 30-10-2013, 08:35

Yes, sorry, I typed HTML code and I forgot to “escape” it.
I was proposing to do exactly what you did, add width=”16″ and height=”16″ 🙂
That way the image looks nice in normal screen and even nicer on retina screens 😉
Cheers,
David

Reply
Jeremy D. 27-12-2013, 13:01

Mark,

I’ve been scouring the Wiki and Forums for methods similar to this. Do you have any insight on how to implement a location map for buildings and offices? I’ve heard mention of it from Knowledge11 and Knowledge12, but don’t see any documented ways to do implement. The Google feature is great for multiple geographic locations, but would love this ability at a local site.

Thanks!

Jeremy

Reply
Mark Stanger 27-12-2013, 19:52

@Jeremy, Unfortunately I don’t have a good answer for you at this point although I may be investigating that soon for a client I’m working with. As is the case with most integrations, the challenge is really in finding another tool that can show the floorplan along with specific coordinates for offices, etc. Once you have that, it shouldn’t be that much different from what I’m doing here with google maps.

Reply
Ben 23-04-2014, 07:52

Great write-up! I have a question, sort of un-related. I see in the screenshot there is a phone icon to dial the user’s phone number directly from the incident form. This is exactly what we are looking to implement now, but I haven’t found any information about this. Where can I find information no how to accomplish this?

Reply
Mark Stanger 23-04-2014, 08:28

The icon in the screenshot is actually only used to toggle the display of an ‘Alternate contact number’ field for the user. There’s no native support for dialing a phone number in ServiceNow, but they did recently add a ‘Notify’ plugin that integrates with Twilio that should be able to dial a user. That lacks the convenient icon on the user field but it could all be built. Here’s a link to the SN ‘Notify’ plugin. Please feel free to contact Crossfuze if you need consulting assistance!

http://wiki.servicenow.com/index.php?title=Notify

Reply
Jeff Schodde 09-05-2014, 12:32

This works great! Thanks for sharing!

Reply
Mark Stanger 09-05-2014, 13:05

You’re welcome!

Reply
Martin S 02-09-2014, 05:18

Really nice!

And I also wanted to suggest updating the icon as it’s the blue Google icon right now (https://plus.google.com/_/favicon?domain=maps.google.com), and not the Maps icon: http://maps.gstatic.com/favicon2.ico.

I had the same problem as Mike Herron with the related link not showing up on the record page. But in the UI Action “Open Google Map” I added it to a view under “UI Action Visability”. I think I tried the Asset or Default view. Then it worked for that view. When I removed this it worked for all views. I tried this on Eureka.

Reply
Mark Stanger 02-09-2014, 06:56

Thanks Martin! Google keeps changing their favicon location, hopefully the one you gave me will last a bit longer. 🙂

Reply
Ravish Rawat 13-07-2015, 07:52

Does this works on Fuji also because i tried and it is not working ???

Anyone able to do this on fuji ??

Reply
Mark Stanger 13-07-2015, 08:17

It should, but there might be some small changes to be made depending on your setup. This UI macro code works great in the Fuji instance I’ve been working in.

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
   <g:evaluate var="jvar_guid" expression="gs.generateGUID(this);" />
   <j:set var="jvar_n" value="open_google_map${jvar_guid}:${ref}"/>

   <g2:evaluate var="jvar_show_google_map_display" jelly="true">
      var id = __ref__.getSysIdValue();
      if (id == null)
         "none";
      else {
         var loc = new GlideRecord('cmn_location');
         loc.get(id);
         if ((!loc.street.nil() $[AND] !loc.city.nil()) || (!loc.latitude.nil() $[AND] !loc.longitude.nil()))
            "";
         else
            "none";
      }
   </g2:evaluate>

   <a>
      <span id="${jvar_n}" onclick="openGoogleMap('${ref}')"
          class="btn btn-default"
          title="${gs.getMessage('Open a Google Map for this location')}"
          alt="${gs.getMessage('Open a Google Map for this location')}"
          style="display:$[jvar_show_google_map_display]; margin-right: 5px">
         <img border="0" src="https://maps.gstatic.com/favicon2.ico" height="13" width="13"/>
      </span>
   </a>

   <script>
      needsRefreshLoc = false;
      function onChange_location_show_google_map(element, original, changed, loading) {
         var s = '${ref}'.split('.');
         var referenceField = s[1];
         if (needsRefreshLoc == false) {
            needsRefreshLoc = true;
            return;
         }
         if (changed.length == 0) {
            $('${jvar_n}').hide();
            return;
         }
         var locRec = g_form.getReference(referenceField, locationGoogleMapReturn);
      }
     
      function locationGoogleMapReturn(locRec) {
         var e = $('${jvar_n}');
         if ((locRec.street $[AND] locRec.city) || (locRec.latitude $[AND] locRec.longitude))
            e.show();
         else
            e.hide();
      }
     
      //Event.observe(g_form.getControl(${ref}.split('.')[1]), 'change', onChange_cmn_location_show_google_map);
      var l = new GlideEventHandler('onChange_location_show_google_map', onChange_location_show_google_map, '${ref}');
      g_event_handlers.push(l);

      //Pop open google maps window of location specified
      //URL should follow this format...http://maps.google.com/?q=1200 Pennsylvania Ave SE, Washington, District of Columbia, 20003

      function openGoogleMap(reference) {
         var s = reference.split('.');
         var referenceField = reference.substring(s[0].length+1);
         var sysId = g_form.getValue(referenceField);
         //Retrieve the 'Location' record
         var gr = new GlideRecord('cmn_location');
         gr.get(sysId);

         //Create and display the Map URL
         var mapURL = "http://maps.google.com/?q=";
         //Try location and city
         if(gr.street $[AND] gr.city){
            mapURL = mapURL + gr.street + ',' + gr.city + ',' + gr.state + ',' + gr.zip + ',' + gr.country;
         }
         //Else try latitude and longitude
         else if(gr.latitude $[AND] gr.longitude){
            mapURL = mapURL + gr.latitude + ',' + gr.longitude;
         }
     //Strip '#' symbols to avoid encoding errors
     mapURL = mapURL.replace(/#/g, "");
         window.open(mapURL);
      }
   </script>
</j:jelly>
Reply
Perfect solution for Fuji 18-12-2015, 14:55

Thanks again Mark for sharing this solution. I don’t think I could have solved this one alone. Going to have to read into GlideEventHandler and how that works, seems useful.

I found a community article asking a similar question so I shared your solution (with a credit/link to snguru):
https://community.servicenow.com/message/858503

We figured out how to modify the ui macro image in Fuji, but it wouldn’t go away if there was no value in the reference field. Can you explain why this extra code is necessary (in terms of hiding the icon when no value is in the field).

Reply
Mark Stanger 18-12-2015, 15:05

Thanks! The UI macro code itself is all rendered and executed at the same time the form loads. As such, it can evaluate the current value of the field when the form loads and display the macro accordingly. If you want to change the macro or take other actions as the field changes then you need to include the appropriate client-side code (included in script tags). The ‘Configuration item’ reference field macro is a good example of doing this out-of-box.

Reply
One Issue 18-12-2015, 15:28

So I have a user reference field that I am applying the same solution to two different macros. It seems that the first macro in the ref_contributions list has some strange behavior. When it’s a new form, it shows. When I clear the value, it works as expected, but when I add a new value, the first macro does not reappear, though the second does. Any ideas?

Reply
Mark Stanger 18-12-2015, 15:36

It’s probably a naming conflict. Because you’ve got 2 macros using similar code on the same form, you need to make sure all of the functions and variables in your script have unique names. Otherwise they will conflict with each other and you’ll end up with unpredictable results.

Reply

Leave a Reply


Latest Comments

  • David: It appears that I can hit sys_properties table with REST. This works, but I haven’t yet discovered the...
  • Mark Stanger: Hey David, It doesn’t surprise me that scoped apps have made this more difficult. I’m not...
  • David: Mark, do you have an example of how to do this in a scoped app? It seems there are many hoops to jump through...
  • Mark Stanger: The only possibility is to create a system property to override this in your application. Check out the...