0

I've been stuck in this quandary for far too long now and need to hunt for outside expertise. I need to write a simple data transform function in JS to convert an external .geojson file to a format that I can use to build listed elements in the view. The output of the function is 'correct', but it will change based on whether it is inside the $.getJSON() or outside of it (see plunker below). When I say "change I mean that they way my console.log() output looks is different based on whether I am inside or outside the $.getJSON() function. What's completely blowing my mind is that the typeof is the same for both outputs, but the result inside the $.getJson() is iterable, while the other is NOT. The reason why this is important is that I need the final result to be passed to another function to create the list of elements on the page, therefore it has to be an iterable object. Here's a simplified code snippet of the functions that I am using:

        $(document).ready(callTransformData);

        var refinedData = [];

        function callTransformData() {
          var transformedData = transformData();
          // build list elements from returned data here
          $.each(transformedData, function(index, value) {
          console.log(index, value); // because the result returned from transformData() is not iterable, this console.log is never read

          });
        }

        function transformData() {
          var prepData = {};
          $.getJSON('data.geojson', function(allLibraries) {

            $.each(allLibraries['features'], function(index, val1) {
              $.each(val1, function(key2, val2) {
                if (key2 === 'properties') {
                  if (!prepData[val2.inst_name_long]) {
                    var inst_properties = {};
                    inst_properties.properties = {};
                    prepData[val2.inst_name_long] = inst_properties;
                    prepData[val2.inst_name_long].properties.group = val2.group_name;
                    prepData[val2.inst_name_long].properties.shared_size = val2.holdings_retained_category;
                    prepData[val2.inst_name_long].properties.all_size = val2.all_titles_considered_retention_category;
                  }
                }
              });
            });
        console.log('prepData INSIDE getJSON()');console.log(prepData); // notice that it is iterable 
            $.each(prepData, function(key, val) {
              refinedData.push({
                library: key,
                properties: val.properties
              });
        console.log('refinedData INSIDE the getJSON()');console.log(refinedData);  // notice that it is iterable  
            });
          });
        console.log('prepData OUTSIDE the getJson()');console.log(prepData); // not iterable
          $.each(prepData, function(key, val) {
            refinedData.push({
              library: key,
              properties: val.properties
            });
          });
        console.log('refinedData OUTSIDE the getJSON()');console.log(refinedData); // not iterable

          return refinedData;
    }

and here's a sample of the data.geojson data:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "group_name": "ALI",
        "inst_name_long": "Indiana University Purdue University at Indianapolis",
        "holdings_retained_category": "100,000+",
        "all_titles_considered_retention_category": "500,000+"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          -86.1762,
          39.7742
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "group_name": "ALI",
        "inst_name_long": "Indiana State University",
        "holdings_retained_category": "100,000+",
        "all_titles_considered_retention_category": "500,000+"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          -87.4106,
          39.4705
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "group_name": "ALI",
        "inst_name_long": "DePauw University",
        "holdings_retained_category": "<100,000",
        "all_titles_considered_retention_category": "250,000+"
      },
      "geometry": {
        "type": "Point",
        "coordinates": [
          -86.8616,
          39.6404
        ]
      }
    }
  ]
}

I've been stuck on the fact that this must be a scope issue, but I can't for the life of me figure out where I'm floundering here. I've tried moving my two key variables prepData and refinedData as internal and global variables but to no avail. The thing that is most bizarre to me is the fact that my chrome console log gives me different outputs based on whether I am inside the $.getJSON() function or not. Clearly, I am missing a key thing here that the JS is doing. Please see my plunker for a quick review of the console.log() outputs to see what I'm talking about here: https://plnkr.co/edit/340oshw78kEAOdFwZpH9?p=info Thanks in advance for any and all assistance, I feel like I'm losing my mind over here!

  • 1
    This is not a scope issue, but a timing issue: you cannot expect to successfully access data synchronously (after `$.getJSON`) when it only become available asynchronously (inside the `$.getJSON` callback). – trincot Aug 31 '17 at 20:28
  • Ahhhh, thank you @trincot. I had wondered if something was happening with the $.getJSON() function that I wasn't considering. So how would I go about resolving the timing issue? –  Aug 31 '17 at 20:31
  • Woops, I just saw that you marked this as a dupe @trincot, I'm investigating the other question now. Again, THANK YOU! –  Aug 31 '17 at 20:33
  • @trincot After reading more on the ubiquitous nature of asynchronous requests, I wonder if you think that it's more appropriate in this use case to use $.ajax() over $.getJSON()? –  Aug 31 '17 at 22:12
  • No, that does not make a difference. I would use the promise that both functions return: `return $.getJSON( .......).then(function (response) { .... });` Anyway, you have to stick to an asynchronous method somehow. By returning it, also the calling code can chain a `then` to it, ...etc. – trincot Aug 31 '17 at 22:19
  • @trincot Unfortunately returning the entire $.getJson() does not work either :( sigh. –  Aug 31 '17 at 23:32
  • Sure it works, but you have to call `then` on it. Whatever you do, you cannot expect a synchronously available result. It will always be with an asynchronous construct, such as `then` or `await` – trincot Aug 31 '17 at 23:32
  • @trincot I'm probably misunderstanding you, but here is my Plunker with a variety of approaches I have attempted but without victory in sight: http://plnkr.co/edit/OZsMdFhi59P73sP7yJf5 The one that is not commented out is the one that I attempted to include your suggestion in your previous comment. –  Sep 01 '17 at 00:10
  • You're still trying to output the result with synchronous code. The return value of `asynchronousWitchcraft()` is a promise, it is *not* the result. You need to output it *within* a `then` callback: `asynchronousWitchcraft().then(function (result) { .... etc. });` – trincot Sep 01 '17 at 00:21
  • If anyone else makes it to the end of this comment thread here's the solution that I finally found thanks to numerous coding rocks stars. Thank you again @trincot for patiently working to keep me on track! This exercise in callbacks and asynchronicity really tied my brain in knots (and will keep me pondering for some time): http://plnkr.co/edit/pIbHafeZgJfU7Iy9cINF –  Sep 01 '17 at 01:48

0 Answers0