Search code examples
jquerygoogle-mapsinfobox

jquery click handler called multiple times when used inside google Maps InfoBox but not infoWindow


I am having a problem that I just cannot figure out. I took over an application that uses version 3 of the google maps API. I was not really familiar with it, but I was asked to adjust a few things. One of them entailed creating custom infoBubbles rather than using the default infoWindow's so that we could style them up nice. I found a class called infoBox that will do just this and followed some examples to get where I am now. However, my application requires that each overlay (polygon, polyline, or marker) have a delete button on the infoBox. The delete was working just fine with a jQuery click event when we were using the default infoWindow's but it is very peculiar now that I am using the infoBox instead. I have created a small test file that demonstrates the problem. The gist of it is that the first time you open an infoBox, the delete button routine is only run 1 time. But once you close the box, and open it again (or a different one), the routine runs multiple times. The more times you open infoBoxes, the more times the delete button is re-binding and in turn executing. I have things wrapped in a domready listener for the infoBox so that I can change the elements in the window to be specific to the properties of the object that's being clicked on. For some reason, the domready is firing multiple times (i thought it would only fire one time) and my delete click is being bound again. Before using the infoBox class, the regular infoWindow did not require a domready in order to use jQuery to change the title and description, and the click event was never bound over and over. I am at a total loss and have spent far too much time on this. Any help would be appreciated. A sample test file is as follows:

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?v=3&amp;sensor=false"></script>
<script type="text/javascript" src="infobox.js"></script>
<script type="text/javascript" src="jquery-1.9.0.min.js"></script>
 <script type="text/javascript">
  //global variables for the info box an for the map
  var ib = null;
  var theMap = null;
  var myOptions = null;
  var iw = null;


    function initialize() {

    //regular google maps setup crap, not important
    //
        var secheltLoc = new google.maps.LatLng(49.47216, -123.76307);

        var myMapOptions = {
             zoom: 7
            ,center: secheltLoc
            ,mapTypeId: google.maps.MapTypeId.ROADMAP
        };
        theMap = new google.maps.Map(document.getElementById("map_canvas"), myMapOptions);


        var marker = new google.maps.Marker({
            map: theMap,
            draggable: true,
            position: new google.maps.LatLng(49.47216, -123.76307),
            visible: true
        });

        var markertwo = new google.maps.Marker({
            map: theMap,
            draggable: true,
            position: new google.maps.LatLng(49.47216, -121.76307),
            visible: true
        });

        //this is how the info box work, create an element and add some styling to it, straight out of the example docs
        var boxText = document.createElement("div");
        boxText.style.cssText = "border: 1px solid black; margin-top: 8px; background: yellow; padding: 5px;";

        //here i am adding the HTML that i would want my infoBox to contain, test crap for now, but the important part is that
        // in the real site, it will have 2 buttons, one to delete the entity you are working with (polygons, polylines, markers) and one
        // to open up a new overlay in which you can make edits to information about that entity. Before changing from the default infoWindow
        // (which is hard to style) to the new infoBox (which can be styled however you like) the deletes worked fine. Over time and trial and 
        // error i have noticed that each time you open up an infoBox, the delete is re-binding and executing multiple times. 
        var infoContent = '';
        infoContent += "<div class='info-wrapper'>";
    infoContent += "<div class='title-wrapper'><p><strong>This is a great title</strong></p></div>";
    infoContent += "<div class='description-wrapper'><p>This is a phenomenal description</p></div>";
    infoContent += "<div class='buttons'><p><a class='openLink' href='#'>Open</a></p>"; //<input type='submit' value='Open' />";
    infoContent += "<p><a class='deleteLink' href='#'>Delete</a></p></div>";
      //close class = info wrapper
    infoContent += "</div>";

    //assign my new variable of html to the inneHTML of main box element
    boxText.innerHTML = infoContent;

    iw = new google.maps.InfoWindow({
      content: infoContent
    });

    //set the default options for infoBox, basically same as default example
        myOptions = {
             content: boxText
            ,disableAutoPan: false
            ,maxWidth: 0
            ,pixelOffset: new google.maps.Size(-140, 0)
            ,zIndex: null
            ,boxStyle: { 
              background: "url('tipbox.gif') no-repeat"
              ,opacity: 0.75
              ,width: "280px"
             }
            ,closeBoxMargin: "10px 2px 2px 2px"
            ,closeBoxURL: "http://www.google.com/intl/en_us/mapfiles/close.gif"
            ,infoBoxClearance: new google.maps.Size(1, 1)
            ,isHidden: false
            ,pane: "floatPane"
            ,enableEventPropagation: false
        };

        //click handlers for the markers
        google.maps.event.addListener(marker, "click", function (e) {
            openInfoBox(marker, e, 'this is the new title')
        });

        google.maps.event.addListener(markertwo, "click", function (e) {
            openInfoBox(markertwo, e, 'great title')
        });

        //the infobox itself
        ib = new InfoBox(myOptions);

    }


    //the open info Box function
    function openInfoBox(feature, e, text) {

      //open the damn thing
      ib.open(theMap, feature);

    //define a listnener for when the infoBox is ready for jquery to make changes, this is necessary if you want
    // to alter the values in the box which i will need to do on MLP, setting the title and description values to 
    // the node that is being altered
    google.maps.event.addListener(ib, 'domready', function() { 
      //chnage the title to hwatever is passed in for demo sake
      $('.title-wrapper p').html('<strong>'+text+'</strong>');
      //$('.description-wrapper p').html('i have change the description');


      /*******************************************************
      HERE IS WHERE THE MAIN PROBLEM LIES THAT IS KILLING ME!!!
      When this routine runs on MLP, i have a way to know which
      feature is being deleted, and the index is removed from the array,
      and the array is reordered. However, for some crazy reason, the more times
      you open up an infoWindow, the more times this event fires. And if you are say
      trying to delete index 0 of an array of 4 elements, at times this may run 4
      times on a single click which then wipes out all your mapping elemetns instead
      of just the one you wanted it to delete. NO ME GUSTA!
      *******************************************************/
      $('.deleteLink').click(function(event) {
        event.preventDefault();
        alert('you clicked me');
        alert('your tricky');
      });
    });
    }

    function notify(event) {
    event.preventDefault();
    alert('test');
    alert('test12');
    }
</script>

<title>Creating and Using an InfoBox</title>
</head>
<body onload="initialize()">
<div id="map_canvas" style="width: 100%; height: 400px"></div>
<p>
This example shows the "traditional" use of an InfoBox as a replacement for an InfoWindow.
</body>

</html>

It may be easier to see a live demo at http://midwestfish.djcase.com/infobox/test.html


Solution

  • Try changing this:

    $('.deleteLink').click(function(event) {})

    to:

    $('.deleteLink').off('click').on('click', function(event){});

    To clarify what the problem is and why this should work. openInfoBox() is being called everytime you click on the point. You can recreate the bug by spam clicking on the point and then clicking on delete. This is because every time you click on the point it is running that function and binding a click onto the delete button.

    To prevent it first unbind it (off) and then rebind it (on).