0

I have a list of JSON files in a variable and I want to load the content of these files into a single object. The json files have two keys: metadata and outputs.

Once this is done, I want to call a function that generates a list of tables. I am able to do this if I have only one file. The code I use to do so is:

jQuery.getJSON(filePath, function(data) {
    jQuery.each(data, function(key, val){
        if ( key === "outputs"){
            new tableGenerator(val);
        };
    });
});

when I try to get the data from different files I obtain an empty variable. To load different files I use:

var fileList = ["dataFolder/data1.json",
                "dataFolder/data2.json",
                "dataFolder/data3.json"]

var jsonData = [];

jQuery.when(
    fileList.forEach( file => {
        jQuery.getJSON(file, function(data) {
            jQuery.each(data, function(key, val){
                if ( key === "outputs"){
                    jsonData = jsonData.concat(val);
                }; 
            });
        });
    })
).then(function(){

    console.log(jsonData);

    new tableGenerator(jsonData);
})

I don't work normally in javascript and I don't understand why normally the tableGenerator function is executed before the jsonData handler is filled.

Any comment in the code is welcome (style, deprecated...) as I am not a javascript developer and probably a lot of things will be done in an uncommon way.

Jfreixa
  • 81
  • 7
  • Consider [reading the docs](https://api.jquery.com/jQuery.when/)? You need to define the parameters of the `then` callback. Modifying `jsonData` isn't a good idea – evolutionxbox Oct 19 '22 at 12:42
  • Does this answer your question? [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](https://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) – evolutionxbox Oct 19 '22 at 12:42
  • @evolutionxbox not really, it is a bad use of `when` – epascarello Oct 19 '22 at 12:43

3 Answers3

2

When expects deferreds as arguments, you are giving it deferreds. You would need to return the deferred the getJSON call returns and set them to when

var fileList = [
  "https://jsonplaceholder.typicode.com/todos/1",
  "https://jsonplaceholder.typicode.com/todos/2",
  "https://jsonplaceholder.typicode.com/todos/3"
]

const calls = fileList.map(path => $.getJSON(path))

$.when(...calls).then((...responses) => {
  const yourData = responses.map(([json]) => json);
  console.log(yourData);
  // call table code
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

without jQuery

var fileList = [
  "https://jsonplaceholder.typicode.com/todos/1",
  "https://jsonplaceholder.typicode.com/todos/2",
  "https://jsonplaceholder.typicode.com/todos/3"
]

const calls = fileList.map(path => fetch(path).then(response => response.json()))

Promise.all(calls).then(yourData => {
  console.log(yourData);
  // call table code
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
epascarello
  • 204,599
  • 20
  • 195
  • 236
0

The get requests for json files are async. Meaning, you need to correctly await for it to happen.

I would suggest using async/await approach with vanilia JS, without jQuery (aka we live in 2022)

const fileList = ["dataFolder/data1.json", "dataFolder/data2.json", "dataFolder/data3.json"]


async function getData(url) {
    const request = await fetch(url)
    const response = await request.json()
    return response
}

async function generateTables(list){
  let tablesData = [];
  for (const url of list) {
    const data = await getData(url)
    tablesData.push(...data?.outputs) //get only "outputs"
  }
  return [...tablesData]
}

generateTables(fileList).then(result => {
  console.log(result);
  new tableGenerator(result);
})
  • 1
    only problem with this approach is you line up all three calls back to back so they are not running at the same time like Promise.all solution would be doing. – epascarello Oct 19 '22 at 13:02
0

It's an asynchronous issue. It's a typical behavior of JavaScript, you declare a function that will be launched when the data will be ready. And after declaration, JavaScript run the next statements.

See How to make the getJSON wait before running the rest of the code? to transform your code in a more classic synchronous mode.

await keyword was introudced with ECMAScript 2017, it permits to have code less JavaScrip specific.