TL;DR
- Sample code that displays locations on Google Maps from a Kintone App
- Each record has an address field
- The address field is geocoded to a latitude and longitude using Google Maps API
- The latitude and longitude is displayed on Google Maps
- Everything is stored in my GitHub repo: emilythecat/googlemaps-kintone
Demo
List View | Record View |
---|---|
![]() | ![]() |
Introduction
Here is a blog post and sample code to display Kintone records on Google Maps. It is a submission for the Kintone Customization Contest 2023.
As an example, I have created a "UC Campus" app that lists the University of California campuses. Each record has an address field.
Prerequisites
- Kintone Developer License - Form
- Google Maps API Key - Video tutorial
Steps
-
Create a Kintone App with the following fields:
Field Name Field Code Field Type UC Campus name
Text Founded founded
Number Enrollment enrollment
Number Endowment endowment
Text Mascots mascots
Text Address address
Text - map
Space Import the data from the
uc-campus.csv
file (provided below)Copy the
google-maps-kintone.js
file to your local machine (provided below)-
Insert your Google Maps API Key into the
google-maps-kintone.js
file:const API_KEY = 'Insert_your_API_key_here';
Upload the
google-maps-kintone.js
file to the Kintone App's JavaScript and CSS Customization settingsAll done! Refresh the page to universities the Google Maps
Screenshots of the Steps
Step 1 | Step 2 | Step 3 |
---|---|---|
![]() | ![]() | ![]() |
Debugging
- API key is invalid - verify that the API key is correct, has Google Maps API enabled, and Kintone's domain is allowed
- Verify that the
address
field is filled out for each record - Verify that the Kintone's field codes are matching in the values in the
google-maps-kintone.js
file
Files
uc-campus.csv
UC Campus,Founded,Enrollment (2022),Endowment (2022),Mascots, Address UC Berkeley,1868,"45307",$6.91 billion,Golden Bears, "University Avenue and, Oxford St, Berkeley, CA 94720, USA" UC Davis,1905,"39679",$2.06 billion,Aggies, "1 Shields Ave, Davis, CA 95616, USA" UC Irvine,1965,"35937",$1.25 billion,Anteaters, "260 Aldrich Hall Irvine, CA 92697, USA" UC Los Angeles,1919,"46430",$6.72 billion,Bruins, "Bunche Hall, 315 Portola Plaza, Los Angeles, CA 90095, USA" UC Merced,2005,"9103",$85 million,Golden Bobcats, "5200 Lake Rd, Merced, CA 95343, USA" UC Riverside,1954,"26809",$354 million,Highlanders, "900 University Ave, Riverside, CA 92521, USA" UC San Diego,1960,"42006",$2.39 billion,Tritons, "9500 Gilman Dr, La Jolla, CA 92093, USA" UC San Francisco,1864,"3140",$5.46 billion,Bears, "505 Parnassus Ave, San Francisco, CA 94143, USA" UC Santa Barbara,1909,"26420",$544 million,Gauchos, "Bldg, Davidson Library, 525 UCEN Rd, Isla Vista, CA 93106, USA" UC Santa Cruz,1965,"19478",$269 million,Banana Slugs, "1156 High St, Santa Cruz, CA 95064, USA"
google-maps-kintone.js
(() => { 'use strict'; // Google Maps Settings const API_KEY = 'Insert_your_API_key_here'; const GOOGLE_MAPS_URL = 'https://maps.googleapis.com/maps/api/js?v=3'; const GOOGLE_GEOCODE_URL = 'https://maps.googleapis.com/maps/api/geocode/json'; const CENTER_POINT = { lat: 37.16611, lng: -119.44944 }; const MAP_LANGUAGE = 'en'; const MAP_COUNTRY = 'US'; const APP_MAP_ZOOM = 6; const RECORD_MAP_ZOOM = 15; // Kintone Field Codes const TITLE_FIELD_CODE = 'name'; const ADDRESS_FIELD_CODE = 'address'; const SPACE_FIELD_CODE = 'map'; // Function to generate a link to a record's details page const getRecordLink = recordID => { const hostname = window.location.hostname; const appID = kintone.app.getId(); return `<a href="https://${hostname}/k/${appID}/show#record=${recordID}">More Info</a>`; }; // Function to retrieve coordinates for given addresses using Google Geocoding API const getAddressCoordinates = async addresses => { const coordinates = []; for (const [id, name, address] of addresses) { const response = await fetch(`${GOOGLE_GEOCODE_URL}?address=${encodeURIComponent(address)}&key=${API_KEY}`); const data = await response.json(); if (data.results && data.results[0]?.geometry?.location) { const { lat, lng } = data.results[0].geometry.location; coordinates.push([id, name, lat, lng]); } } return coordinates; }; // Function to load an external script dynamically const loadScript = src => { const head = document.head || document.getElementsByTagName('head')[0]; const script = document.createElement('script'); script.src = src; head.appendChild(script); }; // Check if Google Maps API is loaded const isGoogleMapsLoaded = () => (typeof google !== 'undefined') && (typeof google.maps !== 'undefined'); // Load Google Maps API if not already loaded const loadGoogleMaps = () => { if (!isGoogleMapsLoaded()) { loadScript(`${GOOGLE_MAPS_URL}&key=${API_KEY}&callback=initMap`); } }; // Display a map on the record details page kintone.events.on('app.record.detail.show', (event) => { // Function to draw a map based on address information const drawMap = () => { if (kintone.app.record.getFieldElement(ADDRESS_FIELD_CODE).length === 0) { console.log('Enter an address in the "Address" field'); return; } if (document.getElementsByName('mapOutput').length !== 0) { return; } // Create a map element const mapAddressEl = document.createElement('div'); mapAddressEl.id = mapAddressEl.name = 'mapOutput'; kintone.app.record.getSpaceElement(SPACE_FIELD_CODE).appendChild(mapAddressEl); // Geocode the address and display the map const gc = new google.maps.Geocoder(); const addressValue = kintone.app.record.get().record[ADDRESS_FIELD_CODE].value; gc.geocode({ address: addressValue, language: MAP_LANGUAGE, country: MAP_COUNTRY }, (results, status) => { if (status === google.maps.GeocoderStatus.OK) { mapAddressEl.style.cssText = 'width: 300px; height: 250px'; const point = results[0].geometry.location; const opts = { zoom: RECORD_MAP_ZOOM, center: point, mapTypeId: google.maps.MapTypeId.ROADMAP, scaleControl: true }; const map = new google.maps.Map(mapAddressEl, opts); new google.maps.Marker({ position: point, map, title: results[0].formatted_address }); } }); }; // Load Google Maps and draw map on details page if (!document.getElementsByName('map_latlng').length) { loadGoogleMaps(); let timeout = 10000; // 10 seconds const interval = 100; // 100ms const checkGoogleMaps = setInterval(() => { if (isGoogleMapsLoaded()) { drawMap(); clearInterval(checkGoogleMaps); } else if ((timeout -= interval) <= 0) { clearInterval(checkGoogleMaps); } }, interval); } }); // Display a map on the record list page kintone.events.on('app.record.index.show', async event => { // Create a map element const spaceDiv = kintone.app.getHeaderSpaceElement(); spaceDiv.style.cssText = 'height: 500px; margin-left: 25px; margin-right: 25px; border: solid; border-color: #bf7bed;'; spaceDiv.id = 'map'; // Prepare address data for geocoding const addressData = event.records.map(record => { return [record.$id.value, `${record[TITLE_FIELD_CODE].value}<br>${record[ADDRESS_FIELD_CODE].value}<br>${getRecordLink(record.$id.value)}`, record[ADDRESS_FIELD_CODE].value]; }); try { // Get coordinates and initialize map on list page const coordinates = await getAddressCoordinates(addressData); window.initMap = () => { const map = new google.maps.Map(spaceDiv, { zoom: APP_MAP_ZOOM, center: CENTER_POINT, mapTypeId: "terrain", }); const infoWindow = new google.maps.InfoWindow({}); coordinates.forEach(([id, name, lat, lng], index) => { const marker = new google.maps.Marker({ position: new google.maps.LatLng(lat, lng), map, title: name }); marker.addListener('click', () => { infoWindow.setContent(name); infoWindow.open(map, marker); }); }); }; // Load Google Maps and set up map on list page if (!document.getElementsByName('map_latlng').length) { loadGoogleMaps(); let timeout = 10000; // 10 seconds const interval = 100; // 100ms const checkGoogleMaps = setInterval(() => { if (isGoogleMapsLoaded()) { clearInterval(checkGoogleMaps); } else if ((timeout -= interval) <= 0) { clearInterval(checkGoogleMaps); } }, interval); } } catch (error) { console.error("Error:", error); } }); })();
This post is part of the Kintone Customization Contest 2023.
Submitter: https://forum.kintone.dev/u/emilythecat/
Top comments (1)
Thank you for submitting your project to the Kintone Customization Contest 2023!
Congratulations on your win!
We will be reaching out to you through the Kintone Developer Forum.