Author Topic: Javascript problems  (Read 2136 times)

0 Members and 1 Guest are viewing this topic.

Offline Ghostavo

  • 210
  • Let it be glue!
    • Skype
    • Steam
    • Twitter
I'll apologize for what you may see here, and try to excuse myself by saying I've only self-learnt this less than two days ago.

I'm trying to make a website that uses the center of a Google Maps map, does a search in Twitter about posts in the area, and then populates the map with markers.

The code I'm having problems with is the following:

Code: [Select]
       function createMarker(location, name, title, link) {
            var marker = new google.maps.Marker({ position: location, map: map });
            var infowindow = new google.maps.InfoWindow({ content: "<b>" + name + "</b><br/>" + title + "<br/><a href=\"" + link + "\">Follow more here</a>" });

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

            return marker;
        }

        function update() {
        
            if (request.readyState == 4) // 0 = uninitialized -- 1 = loading -- 2 = loaded -- 3 = interactive -- 4 = complete
            {
                if (request.status == 200) // 200 = OK
                {
                    try {
                        var xmlDoc = request.responseXML;
                        var x = xmlDoc.getElementsByTagName("entry");

                        for (i = 0; i < x.length; i++) {
                            var name = x[i].getElementsByTagName("name")[0].childNodes[0].nodeValue;
                            var title = x[i].getElementsByTagName("title")[0].childNodes[0].nodeValue;
                            var link = x[i].getElementsByTagName("uri")[0].childNodes[0].nodeValue;
                            var locationStr = x[i].getElementsByTagName("location")[0].childNodes[0].nodeValue;
                            
                            if (locationStr.indexOf("T:") == -1) {

                                if (geocoder) {
                                    geocoder.geocode({ 'address': locationStr }, function (results, status) {
                                        if (status == google.maps.GeocoderStatus.OK) {
                                            // coloca um marcador e um comentário associado
                                            var location = new google.maps.LatLng(results[0].geometry.location.lat() + (0.004 - 0.008 * Math.random()), results[0].geometry.location.lng() + (0.004 - 0.008 * Math.random())); // espalha os pontos por uma localidade
                                            createMarker(location, name, title, link);
                                        } else {
                                            alert("Geocode was not successful for the following reason: " + status);
                                        }
                                    });
                                }
                            }
                            else {
                                var location = new google.maps.LatLng(locationStr.slice(locationStr.indexOf(":") + 1, locationStr.indexOf(",")), locationStr.substr(locationStr.indexOf(",") + 1));

                                // coloca um marcador e um comentário associado
                                createMarker(location, name, title, link);
                            }
                        }
                    }
                    catch (e) {
                        alert("Problem parsing XML");
                    }
                }
                else {
                    alert("Twitter hates you!");
                }
            }
        }

The below function calls the above function each time it needs to create a marker and infowindow and passes the necessary arguments. What happens is when the infowindow is created, the arguments passed are the last value of the variables name, title, etc... The end result of this is that the map is populated by various markers (meaning the location argument was diferent each time), each with identical infowindows (and all the other arguments seem to be the same). What I can't see is why and how to deal with this.

Any help?

[attachment deleted by admin]
« Last Edit: January 12, 2010, 02:12:23 am by Ghostavo »
"Closing the Box" - a campaign in the making :nervous:

Shrike is a dirty dirty admin, he's the destroyer of souls... oh god, let it be glue...

 
Got a link to it active somewhere?  It's infinitely easier to debug these things if I can trace with firebug.

 

Offline Ghostavo

  • 210
  • Let it be glue!
    • Skype
    • Steam
    • Twitter
I'm afraid I'm testing it locally. I haven't got a server or anything of the sort.
"Closing the Box" - a campaign in the making :nervous:

Shrike is a dirty dirty admin, he's the destroyer of souls... oh god, let it be glue...

 

Offline Bobboau

  • Just a MODern kinda guy
    Just MODerately cool
    And MODest too
  • 213
you could attach it
Bobboau, bringing you products that work... in theory
learn to use PCS
creator of the ProXimus Procedural Texture and Effect Generator
My latest build of PCS2, get it while it's hot!
PCS 2.0.3


DEUTERONOMY 22:11
Thou shalt not wear a garment of diverse sorts, [as] of woollen and linen together

 

Offline Ghostavo

  • 210
  • Let it be glue!
    • Skype
    • Steam
    • Twitter
I've posted the complete code. Faint-hearted beware.
"Closing the Box" - a campaign in the making :nervous:

Shrike is a dirty dirty admin, he's the destroyer of souls... oh god, let it be glue...

 
Final Edit:  Fix Attached.

Please note changes:
code = 200 changed to code = 200 or code = 0, as local files return status 0.
location changed to google:location to match xml file supplied.

Geocode creation and callback enclosure.  moved into a seperate function



Here's what was going on:  In your update function, you had a tight loop (for (i = 0; i < x.length; i++)).  The geocoder call back enclosure was being created in this loop, and the
variables used in the callback were local in scope to the loop.  This means that the callback uses the value of the variable in the loop at the time it gets called back.  Since geocoder is
asynchronous, in each iteration of the loop, it would create the callback, send the request, and move on - changing all the variables.  It's a tight loop, and doesn't do much else, so it
would be moved through very, very fast.  By the time the first geocoder request finished and called back, the loop was finished - which means the variables had been changed to the final
value they would've had in the loop.  Those variables were used to create the infowindow - the location was determined by the request, which was sent at the appropriate time.

The end result - every marker's callback was using the final values of name, title, link and locationStr.

By moving the creation of the callback to a seperate function, the scope of the enclosure is changed.  The variables used are the ones passed into the function, and those do not change after
the function is called.

Lesson:  Javascript closure scopes are complicated, especially when matched up with Asynchronous code.

[attachment deleted by admin]
« Last Edit: January 13, 2010, 06:59:25 pm by phatosealpha »

 

Offline Ghostavo

  • 210
  • Let it be glue!
    • Skype
    • Steam
    • Twitter
Thanks.

I see I need to pay more attention to when the callback functions are actually called back.  :D
"Closing the Box" - a campaign in the making :nervous:

Shrike is a dirty dirty admin, he's the destroyer of souls... oh god, let it be glue...