htmlangulargoogle-mapsgoogle-maps-api-3google-maps-advanced-marker-element

Can I fetch the element clicked inside my google maps advanced marker element?


(EDIT) - I've created a workable code sample as per requested jsfiddle code sample

I switched over to Google maps advanced markers and inside each marker if the user clicks on the marker it expands and displays Yoga class details. If the user clicks again on the expanded marker it routes them to the class event page where they can register.

This works fine!

But now I need to display multiple class events in a single marker in case the Yoga studio has multiple events coming up at the same location. (pics at very bottom).

Problem - I can't embed a routerlink or click event into the innerHtml that gets set to the marker's content (I've tried), so I need another way to determine what event was selected by the user inside the marker and then route that way, I'm just not sure how to do this?

Question - I was thinking there might be a way to get the element clicked on in the AdvancedMarkerElement callback? If I could get the HTML element that was clicked on inside the marker I could get an id or something relevant to the event, then route accordingly, otherwise I'm lost for how to do this.

Here is what I'm doing so far.

for (const eventMarker of eventMarkers) {

  const AdvancedMarkerElement = new google.maps.marker.AdvancedMarkerElement({
    map,
    // this check determines if there is 1 event or multiple at a single location (lat/lng) on the map
    content: eventMarker.length === 1 ? this.buildContent(eventMarker) : this.buildContentMultiple(eventMarker),
    position: {
      lat: eventMarker[0].yogaband.latitude,
      lng: eventMarker[0].yogaband.longitude
    }
  });

  AdvancedMarkerElement.addListener("click", () => {
    this.toggleHighlight(AdvancedMarkerElement, id);
  });


}

toggleHighlight(markerView, id) {
  if (markerView.content.classList.contains("highlight")) {
    markerView.content.classList.remove("highlight");
    this.router.navigate(['/events/' + id]);
  } else {
    this.removeHighlight();
    for (const advMarker of this.advancedMarkerElementArray) {
      advMarker.zIndex = 0;
    }
    markerView.content.classList.add("highlight");
    markerView.zIndex = 1;
  }
}

// build marker for a single event at specific lat/lng
buildContent(eMarker) {
  const content = document.createElement("div");
  content.setAttribute("id", "marker-yogaband-" + eMarker[0].yogaband.name);
  content.classList.add("property");
  content.innerHTML = `
      <div class="icon">
          <div class="title">${eMarker[0].yogaStyle}</div>
          <div class="image"><img style="max-width: 100px; border-radius: 0.275rem" src="${eMarker[0].yogaband.photoUrl}"></div>
      </div>
      <div class="details" style="height: 66px;">
          <div class="text-secondary" style="font-weight: 450 !important; line-height: 1em; font-size: .9rem !important;">
            <span>${formatDate(eMarker[0].date,'M/d/y','en-US')}</span>
          </div>
          <div class="mb-1" style="font-size: 1.25rem!important; font-weight: 450 !important;">
            <span>${eMarker[0].yogaLevel + ' ' + eMarker[0].yogaStyle}</span>
          </div>
          <div class="features">
            <div>
              <i aria-hidden="true" class="fa fa-clock fa-lg feature"></i>
              <span>${formatDate(eMarker[0].date,'h:mm a','en-US')}</span>
            </div>
            <div>
              <i aria-hidden="true" class="fa fa-hourglass-start fa-lg feature"></i>
              <span class="float-end">${eMarker[0].eventLength + ' min'}</span>
            </div>
            <div>
              <i aria-hidden="true" class="fa fa-person fa-lg feature"></i>
              <span>${eMarker[0].maxSize === 0 ? eMarker[0].registrantCount : eMarker[0].registrantCount + '/' + eMarker[0].maxSize}</span>
            </div>
          </div>
      </div>
      `;
  return content;
}

// build marker for multiple events at a specific lat/lng
buildContentMultiple(eMarker) {
  const content = document.createElement("div");
  content.setAttribute("id", "marker-yogaband-" + eMarker[0].yogaband.name);
  content.classList.add("property");
  content.classList.add("auto-height");

  let html = `
      <div class="icon">
          <div class="title">${eMarker.length + ' Events'}</div>
          <div class="image"><img style="max-width: 100px; border-radius: 0.275rem" src="${eMarker[0].yogaband.photoUrl}"></div>
      </div>
      <div class="details">`;
  let count = 0;
  for (const marker of eMarker) {
    count >= 1 ? html += `<hr>` : '';
    const multMarker =
      `<div class="multi-marker-container" (click)="routeToEvent(${marker.id})">
          <div class="text-secondary" style="font-weight: 450 !important; line-height: 1em; font-size: .9rem !important;">
            <span>${formatDate(marker.date,'M/d/y','en-US')}</span>
          </div>
          <div class="mb-1" style="font-size: 1.25rem!important; font-weight: 450 !important;">
            <span>${marker.yogaLevel + ' ' + marker.yogaStyle}</span>
          </div>
          <div class="features">
            <div>
              <i aria-hidden="true" class="fa fa-clock fa-lg feature"></i>
              <span>${formatDate(marker.date,'h:mm a','en-US')}</span>
            </div>
            <div>
              <i aria-hidden="true" class="fa fa-hourglass-start fa-lg feature"></i>
              <span class="float-end">${marker.eventLength + ' min'}</span>
            </div>
            <div>
              <i aria-hidden="true" class="fa fa-person fa-lg feature"></i>
              <span>${marker.maxSize === 0 ? marker.registrantCount : marker.registrantCount + '/' + marker.maxSize}</span>
            </div>
          </div>
        </div>`;
    html += multMarker;
    count++;
  }

  html += `</div>`;
  content.innerHTML = html;
  return content;
}

Events on map

enter image description here

Single event inside a marker after it's clicked (expanded)

enter image description here

Multiple events inside a marker after it's clicked (expanded)

enter image description here


Solution

  • You can access whatever data you need within the click event handler.

    You could for example create your events HTML content that way:

    <div class="event" data-event-id="1">
      Beginner Bikram
    </div>
    
    <div class="event" data-event-id="2">
      Beginner Ashtanga
    </div>
    

    Here I use data-event-id="1" and data-event-id="2" to identify the 2 events.

    Now in your click event handler, you can get the clicked event id:

    AdvancedMarkerElement.addListener("click", (e) => {
      console.log(e.domEvent.target.dataset.eventId) // logs "1" or "2"
    });
    

    e.domEvent.target is the HTML element that was clicked. dataset.eventId is the value of data-event-id.

    If your HTML contains child elements, you can add the data-event-id to the child elements as well, or use JS to find the parent element that has the event id when a child element is clicked.