Google Maps Infobox images pop out to another infobox with an image gallery

Tags: , ,



So I have this location that I have images for. I have about 15 images and I want there to only be 4 images on the infoWindow for the location and then you can click on the images and it will initialize a pop-up gallery slider. It currently does nothing when the image is clicked. I have 2 other locations that are going to have very similar set ups.

var locations = [
  ['<div class="header">Lower</div><img id="myImg" src="1.png" alt="Snow" style="width:100%;max-width:300px"><div id="myModal" class="modal"><span class="close">&times;</span><img class="modal-content" id="img01"><div id="caption"></div>', 37.77, -122.43, 4],
];

function initMap() {
  var map= new google.maps.Map(
    document.getElementById('map'), {
      zoom: 14,
      center: { lat:37.78, lng:-122.44 }
    });

  var infowindow = new google.maps.InfoWindow();

  var marker, i;

  var markers = new Array();

     for (i = 0; i < locations.length; i++) {
       marker = new google.maps.Marker({
         position: new google.maps.LatLng(locations[i][1], locations[i][2]),
         map: map,
       });

       google.maps.event.addListener(marker, 'click', (function(marker, i) {
      return function() {
        infowindow.setContent(locations[i][0], locations[i][6]);
        infowindow.open(map, marker);
      };
    })(marker, i));
    markers.push(marker);
     }

     // Get the modal
     var modal = document.getElementById("myModal");

     // Get the image and insert it inside the modal - use its "alt" text as a caption
     var img = document.getElementById("myImg");
     var modalImg = document.getElementById("img01");
     var captionText = document.getElementById("caption");
     img.onclick = function(){
       modal.style.display = "block";
       modalImg.src = this.src;
       captionText.innerHTML = this.alt;
     }

     // Get the <span> element that closes the modal
     var span = document.getElementsByClassName("close")[0];

     // When the user clicks on <span> (x), close the modal
     span.onclick = function() {
       modal.style.display = "none";
     }
}

Here is the HTML document to go with it

<html>
  <head>
    <title>Vigor Locations</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <style>
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
      #map {
        height: 100%;
      }
      #content {
        text-align: center;
        display: block;
        position: absolute;
        bottom: -8px;
        left: -20px;
        background-color: white;
        z-index: 10001;
      }
      
      .header {
        padding-right:2vw;
        font-weight: 600;
        font-size:26px;
        padding-bottom:15px;
        font-family:"IMB Plex Sans", sans-serif;
      }

     #myImg {
        border-radius: 5px;
        cursor: pointer;
        transition: 0.3s;
      }

      #myImg:hover {opacity: 0.7;}

      /* The Modal (background) */
      .modal {
        display: none; /* Hidden by default */
        position: fixed; /* Stay in place */
        z-index: 1; /* Sit on top */
        padding-top: 100px; /* Location of the box */
        left: 0;
        top: 0;
        width: 100%; /* Full width */
        height: 100%; /* Full height */
        overflow: auto; /* Enable scroll if needed */
        background-color: rgb(0,0,0); /* Fallback color */
        background-color: rgba(0,0,0,0.9); /* Black w/ opacity */
      }

      /* Modal Content (Image) */
      .modal-content {
        margin: auto;
        display: block;
        width: 80%;
        max-width: 700px;
      }

      /* Caption of Modal Image (Image Text) - Same Width as the Image */
      #caption {
        margin: auto;
        display: block;
        width: 80%;
        max-width: 700px;
        text-align: center;
        color: #ccc;
        padding: 10px 0;
        height: 150px;
      }

      /* Add Animation - Zoom in the Modal */
      .modal-content, #caption {
        animation-name: zoom;
        animation-duration: 0.6s;
      }

      @keyframes zoom {
        from {transform:scale(0)}
        to {transform:scale(1)}
      }

      /* The Close Button */
      .close {
        position: absolute;
        top: 15px;
        right: 35px;
        color: #f1f1f1;
        font-size: 40px;
        font-weight: bold;
        transition: 0.3s;
      }

      .close:hover,
      .close:focus {
        color: #bbb;
        text-decoration: none;
        cursor: pointer;
      }

      /* 100% Image Width on Smaller Screens */
      @media only screen and (max-width: 700px){
        .modal-content {
          width: 100%;
        }
      }

    </style>
  </head>

  <body>
    <div id="map"></div>
   <!--
   <script>
    </script>
    -->
    <script type="text/javascript" src="map_custom_2.js"></script>
    <!-- NOTE TO SELF: REVOKE API KEY AFTER ASSIGNMENT -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBQfkiMFrFWpGHmP7YMFtlfQM6YEDqslNU&callback=initMap"
        async defer></script>
  </body>
</html>

What am I doing wrong? I have read something about EventPropogation but I don’t know what that means and I don’t know how to disable it.

I have tried to make the onclick for the image a google event listener and that broke the whole map and made it a blank page.

Goal: Have an infowindow with clickable images in columns that when clicked open a popup with a gallery slider.

Current problem: On image click, nothing happens.

Answer

It looks like your issue is the HTML elements in the InfoWindow are not available in the DOM until after the InfoWindow is open. Your code is trying to access them before they exist in the DOM, which causes a javascript error: TypeError: Cannot set property 'onclick' of null

Related questions:

So add the code that needs to access the elements in the InfoWindow in an event listener for the domready event on the InfoWindow:

google.maps.event.addListener(infowindow, 'domready', function() {
  // Get the modal
  var modal = document.getElementById("myModal");

  // Get the image and insert it inside the modal - use its "alt" text as a caption
  var img = document.getElementById("myImg");
  var modalImg = document.getElementById("img01");
  var captionText = document.getElementById("caption");
  img.onclick = function() {
    modal.style.display = "block";
    modalImg.src = this.src;
    captionText.innerHTML = this.alt;
  }

  // Get the <span> element that closes the modal
  var span = document.getElementsByClassName("close")[0];

  // When the user clicks on <span> (x), close the modal
  span.onclick = function() {
    modal.style.display = "none";
  }
})

proof of concept fiddle

code snippet:

var locations = [
  ['<div class="header">Lower</div><img id="myImg" src="https://www.geocodezip.net/images/snow.png" alt="Snow" style="width:100%;max-width:300px"><div id="myModal" class="modal"><span class="close">&times;</span><img class="modal-content" id="img01"><div id="caption"></div>', 37.77, -122.43, 4],
];

function initMap() {
  var map = new google.maps.Map(
    document.getElementById('map'), {
      zoom: 14,
      center: {
        lat: 37.78,
        lng: -122.44
      }
    });

  var infowindow = new google.maps.InfoWindow();

  var marker, i;

  var markers = new Array();

  for (i = 0; i < locations.length; i++) {
    marker = new google.maps.Marker({
      position: new google.maps.LatLng(locations[i][1], locations[i][2]),
      map: map,
    });

    google.maps.event.addListener(marker, 'click', (function(marker, i) {
      return function() {
        infowindow.setContent(locations[i][0], locations[i][6]);
        google.maps.event.addListener(infowindow, 'domready', function() {
          // Get the modal
          var modal = document.getElementById("myModal");

          // Get the image and insert it inside the modal - use its "alt" text as a caption
          var img = document.getElementById("myImg");
          var modalImg = document.getElementById("img01");
          var captionText = document.getElementById("caption");
          img.onclick = function() {
            modal.style.display = "block";
            modalImg.src = this.src;
            captionText.innerHTML = this.alt;
          }

          // Get the <span> element that closes the modal
          var span = document.getElementsByClassName("close")[0];

          // When the user clicks on <span> (x), close the modal
          span.onclick = function() {
            modal.style.display = "none";
          }
        })

        infowindow.open(map, marker);
      };
    })(marker, i));
    markers.push(marker);
  }
}
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

#map {
  height: 100%;
}

#content {
  text-align: center;
  display: block;
  position: absolute;
  bottom: -8px;
  left: -20px;
  background-color: white;
  z-index: 10001;
}

.gm-style .gm-style-iw-c {
  padding-top: 1vw !important;
  padding-left: 1vw !important;
  padding-right: 1vw !important;
  padding-bottom: 0.5vw !important;
  border-color: white;
  border-radius: 0px !important;
}

.gm-ui-hover-effect {
  width: 60px !important;
  height: 30px !important;
}

.gm-ui-hover-effect img {
  padding-top: 0.5vw;
  width: 30px !important;
  height: 30px !important;
}

#bodyContent img {
  text-align: center;
}

#bodyContent p {
  text-align: left;
}

.header {
  padding-right: 2vw;
  font-weight: 600;
  font-size: 26px;
  padding-bottom: 15px;
  font-family: "IMB Plex Sans", sans-serif;
}

#address {
  font-size: 16px;
  line-height: 5px;
  font-family: "IMB Plex Sans", sans-serif;
}

#address-2 {
  font-size: 16px;
  line-height: 5px;
  font-family: "IMB Plex Sans", sans-serif;
  padding-bottom: 29px;
}

#hours {
  font-size: 12px;
  line-height: 20px;
  font-family: "IMB Plex Sans", sans-serif;
}

.row {
  display: flex;
  padding: 0 0px;
}


/* Create four equal columns that sits next to each other */

.column {
  flex: 25%;
  max-width: 25%;
  padding-top: 36px;
  padding-bottom: 0px;
  padding-left: 0px;
  padding-right: 18px;
}

.column img {
  margin-top: 8px;
  vertical-align: middle;
  height: 85px;
}

#myImg {
  border-radius: 5px;
  cursor: pointer;
  transition: 0.3s;
}

#myImg:hover {
  opacity: 0.7;
}


/* The Modal (background) */

.modal {
  display: none;
  /* Hidden by default */
  position: fixed;
  /* Stay in place */
  z-index: 1;
  /* Sit on top */
  padding-top: 100px;
  /* Location of the box */
  left: 0;
  top: 0;
  width: 100%;
  /* Full width */
  height: 100%;
  /* Full height */
  overflow: auto;
  /* Enable scroll if needed */
  background-color: rgb(0, 0, 0);
  /* Fallback color */
  background-color: rgba(0, 0, 0, 0.9);
  /* Black w/ opacity */
}


/* Modal Content (Image) */

.modal-content {
  margin: auto;
  display: block;
  width: 80%;
  max-width: 700px;
}


/* Caption of Modal Image (Image Text) - Same Width as the Image */

#caption {
  margin: auto;
  display: block;
  width: 80%;
  max-width: 700px;
  text-align: center;
  color: #ccc;
  padding: 10px 0;
  height: 150px;
}


/* Add Animation - Zoom in the Modal */

.modal-content,
#caption {
  animation-name: zoom;
  animation-duration: 0.6s;
}

@keyframes zoom {
  from {
    transform: scale(0)
  }
  to {
    transform: scale(1)
  }
}


/* The Close Button */

.close {
  position: absolute;
  top: 15px;
  right: 35px;
  color: #f1f1f1;
  font-size: 40px;
  font-weight: bold;
  transition: 0.3s;
}

.close:hover,
.close:focus {
  color: #bbb;
  text-decoration: none;
  cursor: pointer;
}


/* 100% Image Width on Smaller Screens */

@media only screen and (max-width: 700px) {
  .modal-content {
    width: 100%;
  }
}
<!DOCTYPE html>
<html>

<head>
  <title>Vigor Locations</title>
  <meta name="viewport" content="initial-scale=1.0">
  <meta charset="utf-8">
</head>

<body>
  <div id="map"></div>
  <!--
   <script>
    </script>
    -->
  <script type="text/javascript" src="map_custom_2.js"></script>
  <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBQfkiMFrFWpGHmP7YMFtlfQM6YEDqslNU&callback=initMap" async defer></script>
</body>

</html>


Source: stackoverflow