1

I am loading a geoJSON file using ajax so that I can push the coordinates of the geoJSON MultiPoint feature that is in the file into a (global) array for use in another function. I am having a problem with my callback function, I think. In the code below, I intend to load the data file and push the data pertaining to certain whales into the multipointCoords array. This works fine, but multipointCoords array is not available globally while whales is available. This is confusing me.

This code is also using OpenLayers.

    var whales = {};
    var multipointCoords = [];

    $.getJSON('data/BW2205005.geojson', function(data) {
        data.features.forEach(function(feature) {
            if (!whales.hasOwnProperty(feature.properties.name)) {
                whales[feature.properties.name] = {
                    "type": "FeatureCollection",
                    "features": []
                };
            }
            whales[feature.properties.name].features.push(feature);

            whales["Free Willy"].features.forEach(function(feature) {
                multipointCoords.push(feature.geometry.coordinates);
            });
                console.log(multipointCoords[0][0]);  // gives the right coordinate
        });
    });

    console.log(whales);  // is defined
    console.log(multipointCoords[0][0]); // is undefined

I have studied the following and still can't fix it:

How to load Open layers 3 geojson vector layer with bbox?

How do I return the response from an asynchronous call?

Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference

http://api.jquery.com/jQuery.getJSON/

Thanks for any help.

Community
  • 1
  • 1
interwebjill
  • 920
  • 13
  • 38
  • Have you tried `$.getJSON('data/BW2205005.geojson').done(function(data){your success function code});` ?? – Indrasinh Bihola Oct 06 '15 at 06:27
  • You should understand that your `console.log` may be fired before JSON is actually loaded and executed. `$.getJSON` is an **asynchronous** function. – Yeldar Kurmangaliyev Oct 06 '15 at 06:28
  • Just tried it. Same result, though. – interwebjill Oct 06 '15 at 06:33
  • Yes, I know it is an asynchronous function. That's why I wrote the callback. I must be doing something wrong, though. Do I need to preface console.log with something to make sure that multipointCoords is populated first? I don't typically write Javascript code. – interwebjill Oct 06 '15 at 06:35

3 Answers3

0

While making ajax calls, we are uncertain about when the success callback will fire, hence we user callbacks in such situations. And pass function as an argument to the called function. In callback function we can pass the data retrieved in ajax response. I could see you are using global-variable in your snippet but you are using them synchronously, in that case value of global-variable is not updated(Values used before ajax success callback)

Try this:

function geoJSON(callback) {
  var whales = {};
  var multipointCoords = [];
  $.getJSON('data/BW2205005.geojson', function(data) {
    data.features.forEach(function(feature) {
      if (!whales.hasOwnProperty(feature.properties.name)) {
        whales[feature.properties.name] = {
          "type": "FeatureCollection",
          "features": []
        };
      }
      whales[feature.properties.name].features.push(feature);

      whales["Free Willy"].features.forEach(function(feature) {
        multipointCoords.push(feature.geometry.coordinates);
      });
      if (typeof callback === 'function') {
        callback(whales, multipointCoords);
      }
    });
  });
}
geoJSON(function(whales, multipointCoords) {
  console.log(whales);
  console.log(multipointCoords);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Rayon
  • 36,219
  • 4
  • 49
  • 76
  • Same result. The browser console returns "multipointCoords is not defined" – interwebjill Oct 06 '15 at 06:43
  • 1
    My mistake. Your code worked wonderfully. I had repeated the console.log(multipointCoords) line elsewhere in my code. – interwebjill Oct 06 '15 at 06:57
  • So, to continue with the whale object and/or the multipointCoords array, must I always put them inside the geoJSON function? – interwebjill Oct 06 '15 at 06:57
  • Can you explain what you mean by "its better to use callback inside function"? – interwebjill Oct 06 '15 at 07:04
  • Not really! You can write your further logic here(`callback(whales, multipointCoords);`) But to avoid pyramid-like code structure, its better to use `callback` as an argument in the `function`. Meaning is explained in the answer.. – Rayon Oct 06 '15 at 07:06
  • I see what you mean now. Thank you very much. – interwebjill Oct 06 '15 at 07:16
0

You array is defined as an empty array, but its first member - not yet. You are trying to access your array members before your callback fetches the data and process it. To fix it you may use promises.

var whales = {};
var multipointCoords = [];

$.getJSON('data/BW2205005.geojson')
.then( function(data) {
    data.features.forEach(function(feature) {
        if (!whales.hasOwnProperty(feature.properties.name)) {
            whales[feature.properties.name] = {
                "type": "FeatureCollection",
                "features": []
            };
        }
        whales[feature.properties.name].features.push(feature);

        whales["Free Willy"].features.forEach(function(feature) {
            multipointCoords.push(feature.geometry.coordinates);
            console.log(multipointCoords[0][0]);  // gives the right coordinate
        });
    });
})
.then( function() {
   console.log(whales);  // is defined
   console.log(multipointCoords[0][0]); // is undefined
});
zamuka
  • 796
  • 2
  • 9
  • 21
0

multipointCoords[0][0]) will be always undefined because you're trying to access a value which is not even initialized by the time your console.log() executes.

Even though it looks like the statements in your code are executed in top-bottom fashion, $.getJSON() is an Asynchronous operation, so JS interpreter will fire your AJAX call (via $.getJSON) and continue to execute the remaining statements in your script. The callback that you're passing to $.getJSON() is invoked only when your AJAX call is success and some response is available.

I've attached a screenshot trying to depict the way in which your statements are executed. As shown below, by the time step 5 is executed, multipointCoords is not populated with your expected data as $.getJSON's callback is not invoked yet. Once the AJAX call is done, callback is invoked (Step 6) and multipointCoords is populated with your expected values. Hence the console.log() inside your callback prints some valid value.

JS execution

If you intend to use multipointCoords in some other function, you can either invoke that other function in the success callback of $.getJSON or use Promises.

$.getJSON('data/BW2205005.geojson', function(data) {
    data.features.forEach(function(feature) {
        /* do your logic here
           populate multipointCoords*/
         multipointCoords.push(feature.geometry.coordinates);
    });
}).done(function(){ // done is called only for success scenarios
   anotherFunction(multipointCoords);
}).fail(function{
   // AJAX call failed, multipointCoords is not populated, handle it
});

Hope this helps :)

Arkantos
  • 6,530
  • 2
  • 16
  • 36