Search code examples
javascriptleaflethandler

Adding Click Event Handler to Marker in Leafletjs


I'm trying to add a click event to markers on a map in LeafletJS, but the click events don't seem to be firing. Here's the code:

// jshint esversion: 10

// Keep this out of global scope
jQuery(document).ready(function() {

/**
 * Since singleton classes don't really work in JS, we're just using a variable
 * with properties and functions. This acts like a Singleton.
 *
 * This class's purpose is to handle user interaction with a map
 * of property listings on the page. There should be a div on the page
 * with ID rel-listing-map, which the map will be displayed inside.
 * @author Nate Lanza
 * @type {Object}
 */
var MapManager = {

  /**
   * Stores the Leaflet map object
   * @type {L.Map}
   */
  map: null,

  /**
   * All listings displayed on the map, as Listing objects
   * @type {array}
   */
  listings: null,

  /**
   * Whether this object's init function has been called. If false, no other functions can run
   * @type {Boolean}
   */
  initialized: false,

  /**
   * @throws Error if init has not been called
   * @return {void}
   */
  checkInit: function() {
    if (!this.initialized)
      throw new Error("Must call init first");
  },

  /**
   * Gets listings to be displayed on the map
   * and stores them in the listings field
   * Currently retrieves listings from a custom element with id 'rel-listing-data'
   */
  getListings: function() {
    this.checkInit();
    this.listings = JSON.parse( document.getElementById("rel-listing-data").dataset.listings );
  },

  /**
   * Retrieves a listing by ID
   * @param  {int} ID ID of the listing to retrieve
   * @return {Object || bool}    Listing object, or false if not found
   */
  getListing: function(ID) {
    for (var listing of this.listings)
      if (listing.listingId == ID)
        return listing;

    return false;
  },

  /**
   * Places a marker on the map for each listing to be displayed
   * Fields map and listings should both be initialized
   * @return {void}
   */
  populateMap: function() {
    this.checkInit();
    if (this.listings == null)
      throw new Error("getListings must be called before populateMap");

    // Create onclick function for markers
    function onClick(e) {
      console.log("Clicked");
      // Get listing
      var listing = MapManager.getListing(this.ID);
      if (!listing)
        throw new Error("Listing " + this.ID + " not found");

      // Display info
      jQuery('#rel-listing-map-info').innerHTML = "<p>" + listing.privateRemarks + "</p>";
    }

    // Add each listing to map
    for (var listing of this.listings) {
      // Create marker
      var marker = new L.Marker(
        new L.LatLng(listing.lat, listing.lng)
      );
      marker.ID = listing.listingId;
      // Add to map & add onclick action
      marker.addTo(this.map).on('click', onClick);
      console.log(marker);
    }

  },

  /**
   * Initializes the Map field, retrieves listings from a global variable,
   * fills the listings field, and populates the map with listing markers.
   * Must be executed before any other functions in this 'class',
   * otherwise an error will be thrown
   * @return {void}
   */
  init: function() {
    // Init map
    this.map = L.map('rel-listing-map', {
      center: [43.6177, -116.1997],
      zoom: 8,
      // Canvas doesn't work on IE,
      // but the other option, SVG, doesn't work on Android
      preferCanvas: true,
      attributionControl: true,
    });

    // Create map background
    L.tileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
      attribution: '&copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors',
      maxZoom: 18,
    }).addTo(this.map);

    // Center map
    var houston = new L.LatLng(29.97, -95.35);
    this.map.setView(houston, 13);

    //this.map.on('click', function(e) {
    //  console.log(e);
    //});

    this.initialized = true;

    // Init listings
    this.getListings();
    // Populate map
    this.populateMap();
  }
};

// Code to run when page is loaded
MapManager.init();
});

The onClick function never fires when I try to click a marker. This occurs in multiple browsers. When I print the marker objects to console, they seem to have a click event in the _leaflet_events field, but when I inspect the marker objects on the map in HTML, they don't seem to have my onClick function added as an event. This is reproducible on an empty page with a single div, ID rel-listing-map, with this script, jQuery, and leaflet.js included in the header.


Solution

  • For anyone else who has this problem, I figured out the solution: this map is on a WordPress website. Some other script on the website was including a file called Bundle.css, which breaks the map. I was able to exclude this css file from the site with the following code (only works in Wordpress):

    add_filter( 'style_loader_src', function($href) {
          if ($href == 'http://www.idxhome.com/service/resources/dist/wordpress/bundle.css?1627639643157') {
            return false;
          }
    
          return $href;
        });
    

    Even if this specific css file isn't your problem, I'd recommend right-clicking on the markers and using your browser's inspect element to verify that they are on top of all other elements. If inspect element doesn't pull up the <img> element that's represents the marker, you have a CSS issue.

    The troubleshooting step that lead me here was trying to replicate the problem in a blank HTML file- I'd also recommend doing that, even if you're not using Wordpress, to see if any other scripts/styles are breaking your code.