[TUTORIAL] Adding several markers on one Google Map from Dynamic Collection

Adding several markers on one Google Map from Dynamic Collection

Screen Recording 2020-04-02 at 12.18 AM|

I was doing research for one of my clients who asked how he could present information about the facility on the map, along with the title on the place. It wasn’t too hard to find a solution. The internet has several code solutions for that, based on the code that Google Maps is providing.

What made me really excited is that combining the NoCode tool as Webflow with some code from Google Maps API you can easily control WHAT information you will show and HOW the information on the map will look like.

Plus, if you have a Dynamic Collection with places, you can put all of them on ONE map. And I will show you how to do it.

:one: Get the Google Maps API Key for your project

Go to Usa claves de API  |  API de Maps JavaScript  |  Google for Developers and follow the guide to get an API

:two: Add Lattitude and Longitude to the Place CMS item

At this point, I assume you have a CMS collection where each item is pointing to some address. Well, you will need to do a bit of manual work and find out the Lattitude and Longitude for each address.
It is easy-peasy, just add an address to google maps in the browser, and you will see the location parameters in the URL. It will be numerical values after the @ - character. 1st value LATITUDE is, 2nd value is LONGITUDE. They are separated by a comma.

You will need to add a Plain text field for each value (:exclamation:not a Number field) to the CMS item structure.


Important: Why I do not recommend using Geocode that can calculate each place’s location based on the address.

While Google Maps API has a function that allows calculating a location based on the address, we will be running the code and generate a map when the page loads. That means you would be calling geocode every time somebody views your page and not caching your results anywhere in the DB! Plus, as many times as many CMS items you have.

This way, you will hit the limit allowed by Google pretty fast.
The reason that limit exists is to prevent abuse from Google’s resources (whether it is willingly or unwillingly). So after passing the limit, you would end up paying for each page view ~10 US cents

Using Google maps own DEFAULT service for detecting Land and Lat seems a much better solution to me.

:three: Add the div block to place the map on the page

Once you will decide where is your map will be located, add a div-block and give it an ID map

:four: Design the info-block for the place

Somewhere on the same page with the map, add a Collection List and bing it to your Collection with Places.

And here is my favorite part: now you can design how info-popup will look like on the Map for each Place. Your site’s visitor will be able to click on the marker on the page and see that popup. Here you can include information that you want to provide, address, image, etc. And you can CREATE A LAYOUT and STYLE it the way it fits your needs! :heart_eyes:

Only one requirement: wrap it with a specific DIV and gice it a class name that you will then use in the custom code

:five: Add the code (script) that will generate the map and place clickable markers on it

:warning: We will be adding all the following code to the custom code area on the PAGE level, before the <\body> tag

a) You must include an API key with a Maps JavaScript API request. In the following example, replace YOUR_API_KEY with your API key.


  <script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"
  type="text/javascript"></script>

b) Then the actual custom code:
(I added as many comments in the code as possible, for easier orientation)

<script>

// All code will be running when page loads
  window.addEventListener('load', function () {

// Preparing a "list" of locations
    var locations = []

// We have a dynamic collection on the page 
// with all the information that we need. 
// Change the "place" class name 
// with the one that you use for the collection item
    var dynPlaces = document.querySelectorAll('.w-dyn-item.place');   

  // Now we can define each piece of information 
  // that we want to publish to the popup on the map
    dynPlaces.forEach( function(elem) {

// This will be the information that needed to identify 
// the actual location on the map
      var place = [];
  // Change classnames to those that you used 
  // for each element in your "info-block"
      var title = elem.querySelector('.place-title').innerText;
      var pAddress = elem.querySelector('.place-address').innerText;
      var descript = elem.querySelector('.place-description').innerText;
      var pLat = Number(elem.querySelector('.lat').innerText);
      var pLong = Number(elem.querySelector('.long').innerText);
      var infoText = elem.querySelector('.info_content').innerHTML;

      place.push(title, infoText, pLat, pLong); // Adding required info about each place to the array of places

      locations.push(place);   // Adding each place to the array of Locations
    });

// Generating a map with parameters we want:
// - you need set up a zoom level
// - coordinates for the center of the map
// - type of the map 
    var map = new google.maps.Map(document.getElementById('map'), {
      zoom: 15,
      center: new google.maps.LatLng(51.499633, -0.124755),
      mapTypeId: google.maps.MapTypeId.ROADMAP
    });

// We are using "standard" GoogleMap function  
// to create an info-popup for each marker
    var infowindow = new google.maps.InfoWindow();

// Reusable function to create a marker 
// based on the information we provide
    function createMarker(latlng, html) {
      var marker = new google.maps.Marker({
        position: latlng,
        map: map
      });

 // Allow each marker to have an info window
      google.maps.event.addListener(marker, 'click', function() {
        infowindow.setContent(html);
        infowindow.open(map, marker);
      });
      return marker;
    }

    gmarkers = [];
    for (var i = 0; i < locations.length; i++) {
      gmarkers[locations[i][0]] =
        createMarker(new google.maps.LatLng(locations[i][2], locations[i][3]), // passing lat and long
                                locations[i][1]); // passing Info-window information
    }

  }, false);

</script>

:six: BONUS: add the button that will show the place on the map and open the info popup.

We also can add an embed button inside our dynamic item which will center a map on that item (place) and open the info-window for it:

  • Add an embed element inside the Collection item
  • Add this code inside and replace NAME_OF_DYNAMIC_ITEM with binding to the Collection item Name

<a href="javascript:google.maps.event.trigger(gmarkers['NAME_OF_DYNAMIC_ITEM'],'click');" 
   class="w-button">Show on the map</a>

Of course, you will need to add an additional class name to that button (anchor) to be able to style it the way you need it. Just add a class to the code here, then place a standard Webflow button to the page and give it the same exact class name. By styling that “standard” button you will be changing slites on these embedded buttons

19 Likes

:raised_hands:t2:

That’s amazing! It’s so useful!

Thanks so much for sharing!

1 Like

Great!
Is there any way of two items sharing the same location?
I will need to replicate this where you sometimes have several pins (projects) in the same place.
Thanks much!

Do you mean this functionality?
Shared with CloudApp

It is probably possible with some more complicated functions from google maps developers’ site. I don’t have that experience, sorry.

Yes, that’s what I meant.
Many thanks.

Thank you so much, this is fantastic. Could it be converted to work with Mapbox?

Thanks @sabanna for this tutorial! Any chance you can share a read-only link to the example you created to see how you setup the page layout?

https://preview.webflow.com/preview/dynamic-google-maps?utm_medium=preview_link&utm_source=designer&utm_content=dynamic-google-maps&preview=b0bb1610d9bf6d84b6412492a7eaa831&mode=preview

1 Like

Thank you @sabanna for sharing this tutorial, this is awesome!
One question: would you know how to assign some properties to the places (e.g. : type of place, neighborhood, etc) and use some dynamic filter to filter the places by property and to have the map automatically updated (markers also filtered)? Would it be possible to update the sample project with this kind of enhancement?
Many thanks!

Hi, @WebflowUser

You treat the list of properties the same as any other CMS collection. Apply type of property or neighborhood as a category and build the filtering based on those categories.

While it is not a problem to combine filtering and maps, for sure, I doubt you would be able to “refresh” map on each filtering event. At least not with this code example :point_up:

I used the function that is centering the map based on the address/location parameters when the user clicks on the item with those parameters. It would be much harder to calculate the center of the map each time user would filter out some items.

Hi @sabanna,
I’m following the tutorial step by step, but it doesn’t work. The map does not show markers. Can you help me find out what’s going on?

Hi, @Daniel-Eis!

I would need to see the published page and read-only link to the project.

1 Like

Hi, @sabanna!

Link published page:

Link to read the project:
https://preview.webflow.com/preview/encontreumdesafio?utm_medium=preview_link&utm_source=designer&utm_content=encontreumdesafio&preview=b90747e0bb5cbe200c28c016975df62e&pageId=5f3c2395ed4a310be2222d48&mode=preview

I tried to apply the map on the page “Destaque”

Hey, @Daniel-Eis!

That project has quite a few issues.

  1. You included the default Webflow map component and custom code that call the map through the google maps API. It causes conflict. If you want to have this multi-marker map, you will need to delete the default one.
    Image 2020-09-17 at 10.15.29 AM


    Image 2020-09-17 at 10.16.10 AM

  2. Inside the custom code that I provided, I used classes and IDs to point or connect the functions and the source. Unfortunately, I don’t see it on your page:

  • you need to give an ID to the div where the map will be rendered
  • you need to make sure the class on collection item and class in the code are the same, either change it in the code, or on the project.

Try to address these issues and let’s see if it will resolve the problem.

Hi @sabanna,
I pasted the code again, the API key and all class names are the same as the references. However, the map still does not appear on the website … is there any detail missing?

Please, use this link as a reference to see map space https://encontreumdesafio.webflow.io/destaques

  1. lat and long values has the wrong format, remove the second dot

  1. you don’t have a description [part in your place element, so you will need to remove this line

1 Like

hi @sabanna,
thank you very much. Now everything is right! God bless you =)

1 Like

I’m having a lot of trouble with this. I’ve been working on the dynamic CMS pages and mine are “listings” of art spaces. Once I use the javascript, the map shows up (nothing in it) and then it disappears.

https://preview.webflow.com/preview/artist-safespaces?utm_medium=preview_link&utm_source=designer&utm_content=artist-safespaces&preview=83c02d2449a11be17eb1cfafe08ec625&pageId=5f6e7eebc7ed7c0757939d01&itemId=5f6e7f4cc87daf9d98191ec4&mode=preview

Hi there I love this but an having trouble getting it to work. Any help I would really appreciate.

https://preview.webflow.com/preview/filmhere-a-800b240b8bf691-b5db97e39162f?utm_medium=preview_link&utm_source=dashboard&utm_content=filmhere-a-800b240b8bf691-b5db97e39162f&preview=08bd4620937ab6b567f29e09a60820ff&mode=preview