Reputation: 1677
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
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
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
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
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
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