1

I know this questions is asked several times but most answers are in plain javascript.

I have a function that creates an array with product data. That array is used in an other function to get new data via JSON.

$(function(){
  var product_info = []
  $('.prod').each(function(){
    product_info.push({ 
      id: $(this).data('pid'), amt: $(this).data('qty'), vid: $(this).data('vid'), url: 'some-url/'+$(this).data('pid')+'?secret=secret&quantity='+$(this).data('qty')
    })
  });
  getId(product_info)
});

function getId(product){
  var matched_variant = []
  $.each(product, function(index, item) {
    var vid = item['vid']
    $.getJSON(item['url'], function(data){
      $.each(data.variants, function(i, variant){
         if(variant.id == vid){
           matched_variant.push({
                id: variant.id, dt: Number(variant.deliveryTimeInDays), dtt: variant.deliveryTime, co: variant.cutOffTime, sid: variant.supplier_id 
          })
         }
      });
    }); 
  });
  console.log(matched_variant.length, matched_variant)
}

When I do a console.log matched_variant.length it always shows 0. But there are elemets in it as seen below (copied from console.log)

[
  {
    "id": 79380296,
    "dt": 3,
    "dtt": "in three days",
    "co": "15:00",
    "sid": 5
  },
  {
    "id": 79380299,
    "dt": 1,
    "dtt": "same day",
    "co": "17:00",
    "sid": 5
  }
] 

Why does the length always equals zero then? I've read that this could have something to do with asynchronyous(??). But what should be done then? Creating some sort of success function?

Any help greatly appreciated!

Updated with data response

 {
  "id": 41853029,
  "variants": {
    "79380290": {
      "id": 79380290,
      "supplier_id": 5,
      "on_stock": "no",
      "levelLocal": 0,
      "levelSupplier": 0,
      "deliveryTime": "niet leverbaar",
      "cutOffTime": "15:00",
      "deliveryTimeInDays": -1
    },
    "79380293": {
      "id": 79380293,
      "supplier_id": 5,
      "on_stock": "no",
      "levelLocal": 0,
      "levelSupplier": 0,
      "deliveryTime": "niet leverbaar",
      "cutOffTime": "15:00",
      "deliveryTimeInDays": -1
    },
    "79380296": {
      "id": 79380296,
      "supplier_id": 5,
      "on_stock": "supplier",
      "levelLocal": 1,
      "levelSupplier": 250,
      "deliveryTime": "Voor 15:00 uur besteld, over 3 werkdagen in huis",
      "cutOffTime": "15:00",
      "deliveryTimeInDays": 3
    },
    "79380299": {
      "id": 79380299,
      "supplier_id": 5,
      "on_stock": "supplier",
      "levelLocal": 2,
      "levelSupplier": 250,
      "deliveryTime": "Voor 15:00 uur besteld, over 3 werkdagen in huis",
      "cutOffTime": "15:00",
      "deliveryTimeInDays": 3
    }
  }
}
Meules
  • 1,349
  • 4
  • 24
  • 71
  • Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Louys Patrice Bessette Apr 06 '19 at 15:05
  • [`$.getJSON()`](https://api.jquery.com/jquery.getjson/) is asynchonous... So the `.each()` lopp ends and the `console.log()` is executed before any result is fetched... – Louys Patrice Bessette Apr 06 '19 at 15:07

1 Answers1

2

Yes...$.getJSON() is asynchronous ... and also returns a Promise

When you have multiple requests that are all needed to populate one final array start with an array of promises and use Promise.all() to process the results of all those promises

Something along the lines of:

// usage
getAllItems().then(function(res){
   // all requests have completed and res is combined results
   console.log(res);
}).catch(function(){
   console.log("One of the requests failed")
});



function getItemData(item) {
  // return single item request promise
  return $.getJSON(item.url).then(function(data) {
    // filter and map the response data required
    return Object.values(data.variants).filter(function(variant) {
      variant.id == item.vid
    }).map(function(variant) {
      return {
        id: variant.id,
        dt: Number(variant.deliveryTimeInDays),
        dtt: variant.deliveryTime,
        co: variant.cutOffTime,
        sid: variant.supplier_id
      }    
    });
  });

}

function getAllItems() {    
  var promiseArray = $('.prod').map(function() {    
    var item = {
      id: $(this).data('pid'),
      amt: $(this).data('qty'),
      vid: $(this).data('vid'),
      url: 'some-url/' + $(this).data('pid') + '?secret=secret&quantity=' + $(this).data('qty')
    };
    // return promise from getItemData()
    return getItemData(item);

  }).get();

  // return promise
  return Promise.all(promiseArray).then(function(res){
     // flatten all the sub arrays produced in getItemData()
     return [].concat.apply([], res)
  })

}
Miroslav Glamuzina
  • 4,472
  • 2
  • 19
  • 33
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • Ohh man that is a better approach!! One question... I get an error saying `Typerror: data.filter is not a function`. I'm still learning, but is this because of `variant` not excisting? – Meules Apr 06 '19 at 15:42
  • Would mean that `data` isn't an array since `filter` is an array method. I see it...I missed the `variants` property of your response. Change that to `data.variants.filter`. Assumes that data.variants will ALWAYS be an array also – charlietfl Apr 06 '19 at 15:49
  • Ok I don't fully understand I guess :( I've added the data response in my question. This is not an array indeed. But that can be converted with `makearray` I guess. However can it be that there must be some sort `foreach` function to iterata over the various variants inside `variants`? – Meules Apr 06 '19 at 16:34
  • Yes try filtering `Object.values(data.variants)` which returns array – charlietfl Apr 06 '19 at 16:36
  • Ok `Object.values(data.variants)` seems to work. I'm trying to understand what is happening with your code and what does what. Doing now `console.log(res)` is an empty array. Any idea why? – Meules Apr 06 '19 at 17:52
  • see what's in the promise.all `res` – charlietfl Apr 06 '19 at 18:14
  • When i do `console.log(promiseArray)` I get 2 objects with state, always, then etc... When I do console.log `res` I get an array with two empty arrays in it. The 2 arrays are good (selected two products), but offcourse the data is missing. In the meantime I've read about promises but I don't get the hang of it :) – Meules Apr 06 '19 at 23:28