views:

447

answers:

4

Hi there, please have a look at the following code. When the value of i == 0 the alert 1 prints variable values as per logic. But if I try to print values (alert 2), it just says "undefined, undefined". My question is what changes I'll have to make to get the values printed in second alert (Alert 2) same as per alert 1?

var testPoint = [];

function load() {
  if (GBrowserIsCompatible()) {
    map = new GMap2(document.getElementById("map_canvas"));
    map.addControl(new GSmallMapControl());
    map.addControl(new GMapTypeControl());
    map.setCenter(new GLatLng(52.5271463402545, -1.50573921491311), 8, G_HYBRID_MAP);

    GDownloadUrl("controllers/gmap_genxml2.php", function(data) {
      var xml = GXml.parse(data);
      var markers = xml.documentElement.getElementsByTagName("marker");
      for (var i = 0; i < markers.length; i++) {
        if(i == 0) {
         testPoint["lat"] = parseFloat(markers[i].getAttribute("lat"));
         testPoint["lng"] = parseFloat(markers[i].getAttribute("lng"));

         /********* ALERT 1 ***********/
         alert(testPoint["lat"]+" "+testPoint["lng"]);
         /********* ALERT 1 End ***********/
        }
        var name = markers[i].getAttribute("name");
        var address = markers[i].getAttribute("address");
        var type = markers[i].getAttribute("type");
        var point = new GLatLng(parseFloat(markers[i].getAttribute("lat")),
                                parseFloat(markers[i].getAttribute("lng")));
        var marker = createMarker(point, name, address, type);
        map.addOverlay(marker);
      }
    });

    /********* ALERT 2 ******************/
    alert(testPoint["lat"]+" "+testPoint["lng"]);
    /********* ALERT 2 Start ***********/
  }
}

Thank you for your help. DeeJay

+1  A: 

The two object keys lat and lng are valued only in the callback function called by GDownloadUrl.

You have to wait for it to have executed once, and then you'll have the right values.

I suggest you to move the alert 2 at the end of this callback function.

Fabien Ménager
+1  A: 

You're passing in a function pointer to another function call. That doesn't necessarily make the code execute. It's possible that the timing is off. Your ALERT 1 is happening when the function is called (great), but ALERT 2 is actually being executed before the function is called!

Try putting in a 1 second delay before printing the contents of testPoint.

Kieveli
+3  A: 

You have to realize that a lot of JavaScript is event based. Here is what is happening:

GDownloadUrl takes a callback. The second argument is a function that will be called when the request is complete. It will not be called right away. This is important. After you close the call to GDownloadUrl, Javascript keeps on going. It doesn't wait for the request to complete. As a matter of fact, if you leave both alerts in you will see that the alert 2 will fire before alert 1. As such, if you want to do a particular thing with these variables once they are fetched, you should move that code to a function and call it from within the GDownloadUrl callback. This is just the way JavaScript works and you'll get used to it.

Paolo Bergantino
Yes .. "Svitlana Maksymchuk"'s answer helped me. Thanks for your reply as well.
Wbdvlpr
A: 
    testPoint = [];

    // This global var is introduced to mark that testPoint values are not yet loaded.
    var isLoaded = false;

    function load() {

    if (GBrowserIsCompatible()) {
        map = new GMap2(document.getElementById("map_canvas"));
        map.addControl(new GSmallMapControl());
        map.addControl(new GMapTypeControl());
        map.setCenter(new GLatLng(52.5271463402545, -1.50573921491311), 8, G_HYBRID_MAP);

    GDownloadUrl("controllers/gmap_genxml2.php", function(data) {
      var xml = GXml.parse(data);
      var markers = xml.documentElement.getElementsByTagName("marker");
      for (var i = 0; i < markers.length; i++) {
        if(i == 0) {
                testPoint["lat"] = parseFloat(markers[i].getAttribute("lat"));
                testPoint["lng"] = parseFloat(markers[i].getAttribute("lng"));

                /********* ALERT 1 ***********/
                alert(testPoint["lat"]+" "+testPoint["lng"]);
                /********* ALERT 1 End ***********/

                // Set it to true to indicate that testPoint array is already loaded.
                isLoaded = true;
        }
        var name = markers[i].getAttribute("name");
        var address = markers[i].getAttribute("address");
        var type = markers[i].getAttribute("type");
        var point = new GLatLng(parseFloat(markers[i].getAttribute("lat")),
                                parseFloat(markers[i].getAttribute("lng")));
        var marker = createMarker(point, name, address, type);
        map.addOverlay(marker);
      }
    });

    /********* ALERT 2 ******************/
     // Try to alert testPoint each 0.5 sec until we can successfully do it.
     function alert2() {
         // if testPoint is loaded - then alert it, if not then try in 0.5 sec.
         if (isLoaded) {
              alert(testPoint["lat"]+" "+testPoint["lng"])
         } else {
              setTimeout(alert2, 500);
         }
     };

     alert2();
    /********* ALERT 2 Start ***********/
  }
}
Svitlana Maksymchuk
This works!! Cool. Thanks.
Wbdvlpr
why wouldn't you just do the actual work of alert2 at the end of the anonymous callback function? polling loops are really weak. Also setInterval would be more appropriate.
annakata
@"annakata" Can you provide any example please?? Thanks.
Wbdvlpr
@wbdvlpr: I think annakata is saying "instead of setting isLoaded = true, just call alert2() directly at that line". This is a more straightforward approach.
Mr. Shiny and New