4

I'm trying to make a function details() that looks up the details of certain events (getdetails) based on the available events. In the example below, details are asked for the events with IDs ZRGZZ, RGHER and GRFDZ. These details should be placed inside one array (credits to Theodore's answer). The result should be that when I call details(), the resulting array is stored so I can use it later on.

The problem is that I don't know how I can return this final array. console.log(JSON.stringify(res)); is executed before the construction of the array is completed. I know this probably has something to do with asynchronous js, but I just can't wrap my head around it...

function details()
{
    var res = {
    "Result": "success",
    "Key": "12345",
    "Data": [{
        "ID": "ZRGZZ",
        "lastChangedDate": "2015-12-03 11:14:27"
    }, {
        "ID": "RGHER",
        "lastChangedDate": "2015-12-03 15:17:47"
    }, {
        "ID": "GRFDZ",
        "lastChangedDate": "2015-12-03 05:25:11"
    }]
};

    var i = 0;
    var tmp;
    res.Data.map(function(val,i){

        getdetails(val.ID).then(function(data){
            tmp = JSON.parse(data);
            console.log(tmp);
            Object.keys(tmp.Data[0]).map(function(v,j){
                val[v] = tmp.Data[0][v];
                console.log(JSON.stringify(res)); //(*)the last res gives me the result I'm looking for
            });

        }, function(error){ //error callback
            console.log(error)
        });


    });
console.log(JSON.stringify(res)); //this is executed before (*)
}
Community
  • 1
  • 1
binoculars
  • 2,226
  • 5
  • 33
  • 61
  • Try this: https://jsfiddle.net/rayon_1990/ks3vxomu/ – Rayon Dec 29 '15 at 09:24
  • I see angular in your tags, if you are able to use angular it is very easy to make asynchronous calls with $http.get which gives you a promise(the object you need) – luk492 Dec 29 '15 at 09:42
  • @RayonDabre that seems to change the structure of my data – binoculars Dec 29 '15 at 10:34
  • @luk492 I'm using this inside an Ionic app, so indeed there's angular, but I'm very new to angular... Could you maybe point me in the right direction how this could work? – binoculars Dec 29 '15 at 10:36
  • @binoculars Try looking at this link: https://docs.angularjs.org/api/ng/service/$http – luk492 Dec 29 '15 at 10:38

2 Answers2

1

One way is to use the async library, in particular the async.each or async.eachSeries function. (You could use async.map, but in your case you are actually not mapping, but modifying the underlying array items directly.)

In particular, your code would look like this:

async.each(res.Data, function(val,callback){
    getdetails(val.ID).then(function(data){
        tmp = JSON.parse(data);
        Object.keys(tmp.Data[0]).map(function(v,j){
            val[v] = tmp.Data[0][v];
        });
        callback(null); // Asynchronous code has finished without error
    }, function(error){ //error callback
        callback(error); // Asynchronous code has finished with error
    });
}, function(error) {
    // All asynchronous calls have finished
    if(error)
        console.log("Error", error);
    else
        console.log("Success", res);
});

async.each will run many iterations at the same time, while async.eachSeries will run only one iteration at the same time.

cdauth
  • 6,171
  • 3
  • 41
  • 49
0

Well you already use promise - see then in your code and if it's angular then then itself return deferred promise so you can do:

res.Data.map(function (val, i) {
    getdetails(val.ID).then(function (data) {
        tmp = JSON.parse(data);
        Object.keys(tmp.Data[0]).map(function (v, j) {
            val[v] = tmp.Data[0][v];
        });
    }, function (error) { //error callback
        console.log(error)
    }).then(function () {
        console.log(JSON.stringify(res));
    })
});

EDIT: inject service $q into your controller or service

promises = [];
res.Data.map(function (val) {
    promises.push(getdetails(val.ID).then(function (data) {
        tmp = JSON.parse(data);
        Object.keys(tmp.Data[0]).map(function (v, j) {
            val[v] = tmp.Data[0][v];
        });
    }, function (error) { //error callback
        console.log(error)
    }));
});
$q.all(promises).then(function () {
    console.log(JSON.stringify(res));
});

now when all the getdetails are resolved you can console.log or do whatever you want with the data

maurycy
  • 8,455
  • 1
  • 27
  • 44
  • Thanks for your reply! This seems to work! The only thing that isn't ideal is that it `console.log(JSON.stringify(res));` is executed x times (x being the number of IDs it has to search). – binoculars Dec 29 '15 at 10:33
  • 1
    I'll update my answer with a bit more complicated solution to address this problem – maurycy Dec 29 '15 at 10:47
  • I tried your updated answer, but now `res` only holds the details for the first event. – binoculars Dec 29 '15 at 12:11
  • 1
    I've changed inside of your code when I was checking it, try now, i've put the original logic inside – maurycy Dec 29 '15 at 13:11
  • Exactly what I was looking for! Thanks a lot (!), couldn't have done this myself. – binoculars Dec 29 '15 at 21:35