NightWatchman
NightWatchman

Reputation: 1248

How to create a closure for a Bing Maps event?

I have a javascript problem that I believe is related to closures in loops similar to:

How to copy a variable in JavaScript? JavaScript closure inside loops – simple practical example

I'm plotting a list of pins on a Bing map and attaching an event to each pin so that an infobox can be displayed for each pin. Each pin is supposed to have a different info box. The problem is that when the event fires it always displays the very last info box from the last iteration of the loop, not the info box that goes with the pin firing the event. Here is the method with the looping construct and my failed attempt to create a closure

monumentMap.plotData = function() {
        monumentMap.theMap.entities.clear();

        var monument = null
        var loc = null;
        for (var i = monumentMap.theData.length - 1; i >= 0; i--) {
            monument = monumentMap.theData[i];
            loc = new Microsoft.Maps.Location(monument.lat, monument.lon);

            // construct a bing pushpin and add it to the item data
            monument.pin = new Microsoft.Maps.Pushpin(loc, {
                icon: 'http://media.maps101.com/' + monument.pinImg
            });

            // construct a bing infobox and add it to the item data
            monument.infobox = new Microsoft.Maps.Infobox(loc, { // breakpoint 1
                title: monument.title,
                offset: new Microsoft.Maps.Point(-3, monument.pin.getHeight() - 5),
                zIndex: 999,
                visible: true
            });

            // add event listeners
            // doesn't work
            Microsoft.Maps.Events.addHandler(monument.pin, 'mouseover', function() {
                return function(infobox) {
                    monumentMap.displayInfobox(infobox);
                }(monument.infobox); // breakpoint 2: by the time this is executed monument.infobox is already "last not current"
            });

            // add the entities to the map view for this item
            monumentMap.theMap.entities.push(monument.pin);
        }
}

I'm having trouble getting my head around why it doesn't work. I set monument.infobox right there in the loop and if I put a breakpoint on the line marked "breakpoint 1" I can see that monument.infobox changes on every loop iteration, yet when I get to "breakpoint 2" (which doesn't get executed until the event fires) it references the last infobox i created, not the infobox that I attached to that pin when attaching the event handler.

By this point I half-expect the line monumentMap.theMap.entities.push(monument.pin); to add a bunch of copies of the last pin in the loop, but it doesn't. It works just as it should and adds a different pin each loop iteration.

Upvotes: 1

Views: 674

Answers (1)

Gerben
Gerben

Reputation: 16825

You need to put the parameter in the outer anominous function. If I'm correct:

Microsoft.Maps.Events.addHandler(monument.pin, 'mouseover', 
(function(infobox) {
  return function() {
    monumentMap.displayInfobox(infobox);
  }     
 })(monument.infobox));

Upvotes: 1

Related Questions