Fabio Marzocca
Fabio Marzocca

Reputation: 1677

Callback inside a for loop

I am trying to loop over an array of devices and correctly fill a web page. But...

for (var i=0; i<t_devices.length; i++) {
            data_final = data.replace("%Title%",t_devices[i][1] );
            data_final = data_final.replace("%IP%", t_devices[i][0]);
            console.log(i);
            getStatus(t_devices[i][0], function(status) {
                console.log(i);
                data_final = data_final.replace("%Status%","<b>"+status+"</b>");
                $('#t-container').append(data_final);
            });
        }

Of course, this function is not working, as the for loop is completed before the callback function inside it, so data is messed up. Probably I am missing a trivial solution, but I am still struggling with this.

Upvotes: 2

Views: 118

Answers (5)

AlbertVanHalen
AlbertVanHalen

Reputation: 672

Since you're using jquery, you can use each utility. Your logic will run inside a closure. See https://api.jquery.com/jquery.each/

Have a look at this fiddle and see it working: https://jsfiddle.net/evm39o1s/

Upvotes: 0

Gvz
Gvz

Reputation: 11

If you use ES6, just replace var i with let i in your cycle declaration.

Otherwise modify your callback function

        for (var i=0; i<t_devices.length; i++) {
            data_final = data.replace("%Title%",t_devices[i][1] );
            data_final = data_final.replace("%IP%", t_devices[i][0]);
            console.log(i);
            getStatus(t_devices[i][0], function(index, status) {
                console.log(index);
                data_final = data_final.replace("%Status%","<b>"+status+"</b>");
                $('#t-container').append(data_final);
            }.bind(null, i));
              //first argument (null) is what would be 'this' 
              //inside function when it is called, but we don't need it
              //second (i) is what will be passed into callback as first argument
              //all other arguments will be passed as second, third and so on
        }

Upvotes: 1

Jeremy Thille
Jeremy Thille

Reputation: 26360

I guess, if getStatus() returns a Promise, you can use async/await :

const myFunc = async () => {
    for (var i=0; i<t_devices.length; i++) {
        data_final = data.replace("%Title%",t_devices[i][1] );
        data_final = data_final.replace("%IP%", t_devices[i][0]);
        console.log(i);
        let status = await getStatus(t_devices[i][0]);
        console.log(i);
        data_final = data_final.replace("%Status%","<b>"+status+"</b>");
        $('#t-container').append(data_final);
    }
}

const getStatus = arg => new Promise( (resolve,reject) => {
    /*do stuff with arg*/
    resolve(status);
} );

myFunc();

Upvotes: 0

Rory McCrossan
Rory McCrossan

Reputation: 337560

The simplest solution to this would be to create a closure around the callback, which you can do with an IIFE:

for (var i = 0; i < t_devices.length; i++) {
  data_final = data.replace("%Title%", t_devices[i][1]);
  data_final = data_final.replace("%IP%", t_devices[i][0]);
  console.log(i);
  
  (function(i, data_final) {
    getStatus(t_devices[i][0], function(status) {
      console.log(i);
      data_final = data_final.replace("%Status%", "<b>" + status + "</b>");
      $('#t-container').append(data_final);
    });
  }(i, data_final));
}

Upvotes: 4

Mos&#232; Raguzzini
Mos&#232; Raguzzini

Reputation: 15821

Why don't you store the result of the first loop and work it after first loop has finished ?

let deviceStatusToWork = [];
for (let i=0; i<t_devices.length; i++) {
            data_final = data.replace("%Title%",t_devices[i][1] );
            data_final = data_final.replace("%IP%", t_devices[i][0]);
            console.log(i);
            deviceStatusToWork.push(t_devices[i][0])            
        }

for (let i = 0; i < deviceStatusWork; i++) {
getStatus(deviceStatusWork[i], function(status) {                
                data_final = data_final.replace("%Status%","<b>"+status+"</b>");
                $('#t-container').append(data_final);
            });
}

Upvotes: 0

Related Questions