Search code examples
javascriptreactjsmapsmarker

Google maps marker delete function not invoked in ReactJS


I am trying to implement custom markers on google maps in my ReactJS application. Now that I got the markers, I would like to have an option to delete them. This is the code for placing and deleting markers. However, when I click on the delete button in the info window, nothing seems to happen.

  addInfoWindow(marker, message, map) {
    var infoWindow = new google.maps.InfoWindow({
      content: message
    });

    google.maps.event.addListener(marker, "click", function() {
      infoWindow.open(map, marker);
    });
  }

  deleteMarker() {
    console.log('Delete');
  }

  placeMarker = (map, location) => {
    let marker = new google.maps.Marker({
      position: location,
      map: map,
      icon: red_flag
    });

    var contentString =
      '<button type="button" class="btn btn-danger" onClick="' +
      this.deleteMarker +
      '">Delete</button>';

    this.addInfoWindow(marker, contentString, map);
  };

I also tried with;

deleteMarker = () => {
    console.log('Delete');
}

When I click on the button, the method is not getting invoked and no errors on console. What could be wrong with this code? The generated HTML code for this content string is;

<button type="button" class="btn btn-danger" onclick="function () {
      console.log('Delete');
    }">Delete</button>

To clarify further, I would like to have the string for delete button behave like this;

<button type="button" class="btn btn-danger" onClick={() => this.deleteMarker("param")}>
    Delete
</button>

deleteMarker = param => {
    console.log("Delete", param);
};

Solution

  • You're trying to use the code as if it's going to execute using JSX in React, but Google Maps and HTML doesn't work that way. Google Maps itself doesn't use React and as such, the Google Maps library works without any knowledge of how React works and React works independently of how Google Maps works. Because of this, every React Google Maps package has to work with the raw DOM or wrap the Google Maps library so that it can prevent memory leaks, bugs, or other breakages. When you create an InfoWindow object with content, that content will create HTML independent of React which means that to get it working the way that you want it to, you must work with DOM listeners yourself.

    What you have written will create a function when clicking it, but it doesn't execute. Inside of the onclick attribute of HTML, it contains a JavaScript expression scoped globally. If it's just a function expression like what you will get with either of those options, it will only create the function as an expression but not execute it.

    Instead, you will have to either use a global function to delete the marker (not in any way advisable) or manually add an event listener (hacky, but may be necessary).

    I'd suggest creating a unique ID for the button so that you can get it once it's been appended. From there, you will have to get a reference to that button once it's appended and then add an event listener to it that deletes the marker.

    Using your example, it might look like this:

      addInfoWindow(marker, message, map, uniqueId) {
        var infoWindow = new google.maps.InfoWindow({
          content: message
        });
    
        google.maps.event.addListener(marker, "click", function() {
          infoWindow.open(map, marker);
        });
    
        google.maps.event.addListener(infoWindow, 'domready', () => {
            document.getElementById(uniqueId)
                .addEventListener('click', this.deleteMarker.bind(this));
        });
      }
    
      deleteMarker() {
        console.log('Delete');
      }
    
      placeMarker = (map, location) => {
        let marker = new google.maps.Marker({
          position: location,
          map: map,
          icon: red_flag
        });
    
        var uniqueId = 'delete-marker-'+ getAUniqueId();
    
        var contentString =
          '<button type="button" class="btn btn-danger" id="' + uniqueId + '">Delete</button>';
    
        this.addInfoWindow(marker, contentString, map, uniqueId);
      };
    

    And that should get you going.

    But since you're dealing with the raw DOM elements, you should make sure you can clean up that event listener when you delete the marker and info window. That would require you also capturing that function you create when binding the deleteMarker function (though you don't have to capture it extra if you use an arrow function or binding the method to your instance in your component constructor).

    Some notable references: