Object Reference Within Listener?

19 views
Skip to first unread message

Iam Anonymous

unread,
Jan 16, 2011, 9:53:26 PM1/16/11
to google-map...@googlegroups.com
I have a marker array that needs to be re-set after I load a new map.  I also want to be able to double-click markers to erase them.  Simplified code looks like:

for(i=0;i<allPins.length;i++){if(allPins[i]!=null){
    allPins[i].setMap(griddedMap);
    google.maps.event.addListener(allPins[i], 'dblclick', function(obj) {
        allPins[i].setMap(null);
        allPins[i] = null;
    });
}};

When I double-click a marker, it is kind of random what happens.  Sometimes the map zooms, indicating no listener.  Sometimes more than one marker will disappear.  Sometimes it works.  Very strange.

I think the problem is the two references to allPins[i] inside the listener function are getting evaluated at run time with some random value of i.  What I really am trying to refer to is the marker that is being clicked, passed to the listener from the array: allPins[i].  Said another way, I need something lilke:

markerbeingclicked.setMap(null);
markerbeingclicked = null;

but I don't think that's what I am getting when I use allPins[i].  Any suggestions?

geoco...@gmail.com

unread,
Jan 16, 2011, 10:02:04 PM1/16/11
to Google Maps JavaScript API v3
On Jan 16, 6:53 pm, Iam Anonymous <commercialpilo...@gmail.com> wrote:
> I have a marker array that needs to be re-set after I load a new
> map.  I also want to be able to double-click markers to erase them.
> Simplified code
> looks like:
>
> for(i=0;i<allPins.length;i++){if(allPins[i]!=null){
>     allPins[i].setMap(griddedMap);
>     google.maps.event.addListener(allPins[i], 'dblclick',
> function(obj) {
>         allPins[i].setMap(null);
>         allPins[i] = null;
>     });
>
> }};
>
> When I double-click a marker, it is kind of random what happens.
>  Sometimes the map zooms, indicating no listener.  Sometimes more
> than one marker will disappear.  Sometimes it works.  Very strange.
>
> I think the problem is the two references to allPins[i] inside the
> listener
> function are getting evaluated at run time with some random value
> of i.  
> What I really am trying to refer to is the marker that is being
> clicked, passed to the listener from the array: allPins[i].  

Try using function closure.

That looks a lot like pitfall #3.
http://groups.google.com/group/google-maps-js-api-v3/search?group=google-maps-js-api-v3&q=pitfall+%233&qt_g=Search+this+group


> Said
> another way, I need something lilke:
>
> markerbeingclicked.setMap(null);
> markerbeingclicked = null;
>
> but I don't think that's what I am getting when I use allPins[i].
>  Any suggestions?

Post a link to your map that exhibits the problem.
http://groups.google.com/group/google-maps-js-api-v3/t/2b3f101fd509919e

-- Larry

Myopia

unread,
Jan 17, 2011, 12:12:28 PM1/17/11
to Google Maps JavaScript API v3


On Jan 16, 9:02 pm, "geocode...@gmail.com" <geocode...@gmail.com>
wrote:
>
> Try using function closure.
>

Doesn't help. Or at least I don't think it helps. The problem is
that when the dblclick event is fired I need some way to identify the
marker that was clicked. Calling an outside function is fine, but I
still need to know who got the dblclick.

> That looks a lot like pitfall #3.http://groups.google.com/group/google-maps-js-api-v3/search?group=goo...
>

I think so.

So .. here is a workaround that could be described as clever or
kludgy. I tend toward the latter.

I found that the object "this" is in fact the MarkerOptions of the
marker that was clicked. Not the marker object itself. So I have
used the zIndex of the MarkerOptions (which I was not previously
using) to store an index into the marker array allPins.

for(i=0;i<allPins.length;i++){if(allPins[i]!=null){
allPins[i].setMap(griddedMap);
google.maps.event.addListener(allPins[i], 'dblclick', function(obj)
{
if(allPins[this.zIndex]!=null){ //bug? i+1 listeners are created
when allPins[i] is passed.
allPins[this.zIndex].setMap(null);
allPins[this.zIndex] = null;
}
});
}};

But there is one other thing going on here. I think it is a bug at
Google. When I pass allPins[i] as the marker for listening, there are
i+1 watchers created. One for each element of allPins with an index =
i or smaller. So, what happens is if, say, there are four markers
then I end up with four watchers on allPins[0], three on allPins[1],
and so forth. That is why I have to test for null on the third line
of the code snippet. Fortunately, my users will never have more than
a few markers of this type so I can take the overhead.

>Post a link to your map that exhibits the problem.

It's not on the internet plus there is a lot of user interaction
required before someone could get to the point of seeing the issue.
That's why I just posted a simplified snippet.

geoco...@gmail.com

unread,
Jan 17, 2011, 12:58:46 PM1/17/11
to Google Maps JavaScript API v3
On Jan 17, 9:12 am, Myopia <commercialpilo...@gmail.com> wrote:
> On Jan 16, 9:02 pm, "geocode...@gmail.com" <geocode...@gmail.com>
> wrote:
>
>
>
> > Try using function closure.
>
> Doesn't help.  Or at least I don't think it helps.  

It is not an easy topic, you need to understand how it works.

> The problem is
> that when the dblclick event is fired I need some way to identify the
> marker that was clicked.  

Function closure can keep a reference to the marker.

> Calling an outside function is fine, but I
> still need to know who got the dblclick.
>
> > That looks a lot like pitfall #3.http://groups.google.com/group/google-maps-js-api-v3/search?group=goo...
>
> I think so.
>
> So .. here is a workaround that could be described as clever or
> kludgy.  I tend toward the latter.
>
> I found that the object "this" is in fact the MarkerOptions of the
> marker that was clicked.  Not the marker object itself.  So I have
> used the zIndex of the MarkerOptions (which I was not previously
> using) to store an index into the marker array allPins.
>
>         for(i=0;i<allPins.length;i++){if(allPins[i]!=null){
>                 allPins[i].setMap(griddedMap);
>                 google.maps.event.addListener(allPins[i], 'dblclick', function(obj)
> {
>                         if(allPins[this.zIndex]!=null){  //bug?  i+1 listeners are created
> when allPins[i] is passed.
>                                 allPins[this.zIndex].setMap(null);
>                                 allPins[this.zIndex] = null;
>                         }
>                 });
>         }};
>
> But there is one other thing going on here.  I think it is a bug at
> Google.  

I doubt it. Post a link to your map that demostrates the "bug", it is
most likely a problem in your code.

> When I pass allPins[i] as the marker for listening, there are
> i+1 watchers created.  One for each element of allPins with an index =
> i or smaller.  So, what happens is if, say, there are four markers
> then I end up with four watchers on allPins[0], three on allPins[1],
> and so forth.  That is why I have to test for null on the third line
> of the code snippet.  Fortunately, my users will never have more than
> a few markers of this type so I can take the overhead.
>
> >Post a link to your map that exhibits the problem.
>
> It's not on the internet plus there is a lot of user interaction
> required before someone could get to the point of seeing the issue.
> That's why I just posted a simplified snippet.

From the v2 group, but still appropriate:
http://groups.google.com/group/google-maps-api/web/why-including-a-link-is-critical

If you can't post a link to a sanitized map that exhibits the problem,
you will have to fix it yourself (although from the sounds of things,
correctly using function closure will fix it).

-- Larry

JKurtock

unread,
Jan 17, 2011, 2:38:53 PM1/17/11
to Google Maps JavaScript API v3
Actually, function closure does (for me) exactly what you're trying to
do. Hard to understand, but not hard to do.

Something like:
var no6 = 6;
google.maps.event.addListener(Marker[no6],
'click',clickCallbackClosure(no6));

function clickCallBackClosure(MarkerNo) {
return function (mouseevent) {
//inside this anonymous function, MarkerNo has the value no6 had
when the listener was added!
//now handle the click event, using MarkerNo to identify which
marker was clicked
}
}

clickCallbackClosure is NOT the function handling the click event,
rather it returns the (anonymous) function that does. But through the
magic of closure, the click handling function can identify (through
variable MarkerNo) which Marker through the event.

Note that using a global variable inside an ordinary event handling
function won't work, because the global variable will be evaluated at
the time the function is invoked (the event fired), not the time that
the function was attached to the event.

good luck!


On Jan 17, 9:12 am, Myopia <commercialpilo...@gmail.com> wrote:

Myopia

unread,
Jan 17, 2011, 7:20:24 PM1/17/11
to Google Maps JavaScript API v3


On Jan 17, 1:38 pm, JKurtock <jkurt...@gmail.com> wrote:
> Actually, function closure does (for me) exactly what you're trying to
> do.  Hard to understand, but not hard to do.

Yes. A little monkey-see, monkey-do programming based on your example
got the job done. No more kludgy workaround!

> clickCallbackClosure is NOT the function handling the click event,
> rather it returns the (anonymous) function that does.  But through the
> magic of closure, the click handling function can identify (through
> variable MarkerNo) which Marker through the event.

Yes. I see that. clickCallbackClosure is actually called when the
listener is being set up. I'll have to think about the whole concept
and do some reading.

>
> Note that using a global variable inside an ordinary event handling
> function won't work, because the global variable will be evaluated at
> the time the function is invoked (the event fired), not the time that
> the function was attached to the event.

Yes. That's what I started with -- allPins[i] was getting evaluated
when the event fired (and i had some quasi-random value). Very
confusing to sort out.

Re the "bug" where a stack of listeners seemed to be getting created
by addListener I have now determined that they are getting added in
another way. When a pin is created (hence allPins gets one element
bigger) I recreate the whole map for reasons outside the scope of this
thread. I had assumed that everything associated with the old map was
blown away (I even set the map variable griddedMap to null) but that
seems to not be the case. Hence my stack of listeners. So now I am
using clearListeners to make sure that the old lsteners are gone when
I put the pins and listeners onto the new map. I am also going to re-
look the need to recreate the map. It might be overkill for what I am
trying to do.

Anyway, thanks a lot gents. You were a big help on what was a tough
problem for me.
Reply all
Reply to author
Forward
0 new messages