I don’t think I need to introduce Salesforce and Google Maps. If I do then maybe this blog is not for you. Visualforce has been in salesforce for a while and works amazingly well with Google Maps. But now we have lightning components. Do Google Maps work in lightning components?
The short answer is, no. This is because of locker service. Google Maps add multiple <script> tags when loaded. With locker service enabled, this is not possible due to security restrictions. Currently you can disable locker service but eventually it will be mandatory. So, is there any other way Google Maps can work in lightning components?
YES, Google Maps work in Lightning components. To get Google Maps to work in lightning components we will need to implement maps in visualforce page and embed in lightning components as iFrame. One library that locker service team opened in locker service is window.postMessage. This allows lightning components to send/receive messages to/from visualforce pages. We could use this library and implement Google maps.
I am sure by now you’re all wanting to get into the code. Well, let’s get to it.
Use Case
We will go through Account list and show all the accounts on Google map based on BillingAddress.
Pre-requisites
Following are some of the pre-requisites to get this demo to work:
- You need to get a free Google API key for using Google Maps
- Google Maps work with longitudes and latitudes and not addresses. If we want to display accounts on maps then we will need to get long/lat for these accounts. For this, we need to enable “Data Integration Rules” for account.
- This can update existing records (if you choose to) or automatically setup Long/Lat for new accounts.
Demo
Implementation
Now that we have setup the use case and have the data ready for this, let’s dive into code. More information about architecture and access to source code is available in github:
- GoogleMap.cls:
- This class returns list of all accounts which have BillingLatitude and BillingLongitude
- Do note that using “!=” in a SOQL query can impact performance; we used it just for demo purposes
- GoogleMap.page:
- This page can send/receive messages to/from Lightning components
- It receives a parameter “lcHost” which will be Lighting component URL to send messages to components on Lightning component URLs; required when using window.postMessage
- Once page loads, visualforce will send a message to Lightning component that page was successfully loaded
- Lightning component has no way to know when iFrame is loaded and when to send data for map
- If we try to do it before iFrame is ready then we will get an error as we try to send data to non-existent page
- Upon receiving Google map data, Google map library will be loaded and data will be used for drawing map
- Note: We could have used <apex:map> but I wanted to display multiple accounts and also be able to control different settings for Google maps
- GoogleMap.cmp:
- This component will receive Google map options and data provided by calling component
- This allows the component to be used from any component and not just Account because component just expects data in pre-defined format
- Once visualforce page has been loaded (LC is notified by visualforce via an event), Lightning component will send data to visualforce page
- This component will receive Google map options and data provided by calling component
- DemoApp.app: Application:
- DemoApp loads account information on init
- That information is sent to GoogleMap component for Google Map on visualforce page
Architecture
This was tested in Spring’17 org and works fine even with Locker Service. On the outside, it all looks very complicated but once it has all been setup it looks very promising. window.postMessage library is very promising and offers opportunities for many use cases.
What are you waiting for? Go ahead and get it to work!!
Hi Ratan..
Firstly thanks a lot the article. It gave a good idea on implementing google maps in salesforce lightning. I was hitting hard to find a way..So your article gave a starting point.
I tried to develop what you did in my org. when i try to preview my vf page its failing with below error
‘Uncaught DOMException: Failed to execute ‘postMessage’ on ‘Window’: Invalid target origin ‘https://’ in a call to ‘postMessage’.’
What I foudn in debugging is that its not able to get data for lexorigin.
var lexOrigin = ‘https://{!$CurrentPage.parameters.lcHost}’;
console.log(‘lexOrigin’ , lexOrigin);
my log shows lexOrigin as https://
and vfHOst as https://DOMAIN–CU1–c.cs74.visual.force.com/
Please help me out in fixing the error
Thanks in advance.
Hi Swetha:
Sorry for late reply, I was away for a while. It seems like you might not be sending “lexOrigin” param to visualforce page as part of URL parameters when you send it. I didn’t add many error checks in the code as it was mainly for demo.
You can even try to remove any checks for “lexOrigin” and see how it works. The check is just for security as you can ensure your pages are not included from different locations and don’t send data there erroneously.
Thanks
getting the similar error
Uncaught DataCloneError: Failed to execute ‘postMessage’ on ‘Window’: [object Object] could not be cloned.
Any suggestion.
Alex,
Not sure without looking at the code. But it seems you might be passing an object rather than JSON. take a look at https://stackoverflow.com/questions/42376464/uncaught-domexception-failed-to-execute-postmessage-on-window-an-object-co
Hi,
Am getting this error:
Uncaught DataCloneError: Failed to execute ‘postMessage’ on ‘Window’: [object Object] could not be cloned.
Can someone please help.
Thanks.
Not sure without looking at the code. But it seems you might be passing an object rather than JSON. take a look at https://stackoverflow.com/questions/42376464/uncaught-domexception-failed-to-execute-postmessage-on-window-an-object-co
Hi,
event.data.loadGoogleMap is coming as undefined. How should I fix it?
Anticipating your response.
Thanks
I am not sure which data you are sending. In Visualforce page, do “console.log(event);” and see what is being sent. Maybe you changed some code?
Thanks.
I was able to resolve it.
Hi,
I want to change mapTypeId to ‘satellite’. Where should I put it?
My requirement is to get heat map. Can you please help me.
Thanks.
Hi,
You can find options in https://developers.google.com/maps/documentation/javascript/maptypes. In example above, those options are sent from Lightning component so you can add this option there. You can even expose it to admin to decide which one they want (if you so desire)..
Hi,
I tried the JSON.parse(JSON.stringify(message)). But it just make it an object again after JSON.parse
Any suggestions?
I think you need to just send stringify data and then parse it in VF page
In the GoogleMapHelper.js you have to add this line:
message = JSON.parse(JSON.stringify(message));
Right before this line:
vfWindow.postMessage(message, component.get(“v.vfHost”));
I really love the concept and your well thought-out video.
One issue is that the link to Data Integration Rules is now a 404. Can you remember the title of the page in H&T that you were linking to? I find the documentation on Data Integration Rules quite hard to follow in the context of adding geolocation data to an object:
https://help.salesforce.com/articleView?id=ddc_data_integration_overview.htm&type=5
(and following pages)
Fundamentally, I’d like to know what steps I need to follow (that you alluded to in the prerequisites section) before I can get lat/long in my Account object.
I have updated the article. Here is the new link: https://help.salesforce.com/articleView?id=data_dot_com_clean_admin_automatically_get_geocodes_for_addresses.htm&type=5
Hi you say we need to send Lighting component URL over the param of the visual force page for “lcHost” but i don’t know how to find this url in salesforce.
Can you help ?
Hi,
The google map is not showing. When I try to inspect, this error shows, ” in a frame because it set ‘X-Frame-Options’ to ‘sameorigin’.”
What should I do?
Alvin,
Hard to say without looking at it but if you are using Force.com site then you have to turn of iFrame protection before you can use it.
Thanks
Hello, in community on not admin user, the iframe not working, what i can do?
Maybe cross domain error? What shows up in Browser console/
iframe has been restricted by salesforce. isn’t it?
I don’t think it’s restricted. It depends how you use it. As customers, you can use it as you want. As partners, there are some restrictions. But iFrame itself is allowed as far as I know.