Reputation: 17142
var std;
......
...... // here I fill std with some data
......
I'm trying to access the 'std' array while handling this route:
app.post('/saveABS',function(req,res){
var fileName = "./public/"+f;
fs.writeFile(fileName, JSON.stringify(std, null, 4), function(err) {
if(err) {
console.log(err);
} else {
console.log("The file was saved !");
console.log(a);
for(var i = 0; i < std.length; i++)
{
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'admin' ,
database : 'pfe'
});
console.log('before hr_cours = ' + std[i].hr_cours); // <========= WORKS
Here it displays the value of std[i].hr_cours correctly.
if(std[i].hr_cours != a[i].hr_cours)
{
connection.connect(function(error){
console.log('after hr_cours = ' + std[i].hr_cours); // <============ undefined
Here it displays undefined.
if(error)
{
console.log('Unable to connect to database.');
}
else
{
console.log("i= " + i);
console.log("I'm in : hr_cours = " + std[i].hr_cours);
connection.query("INSERT INTO assiste VALUES (CURDATE(),(SELECT id_etud FROM Etudiant WHERE nom_etud = ?),(SELECT s.id_seanceFROM Seance s, aura_lieu a, jour j, fait_objet fWHERE s.id_seance = a.id_seanceAND CURTIME() BETWEEN a.heure_debut AND a.heure_fin AND a.id_jour = j.id_jour AND j.dat = CURDATE() AND f.id_seance = s.id_seance AND f.id_ens = ?), ?)", [std[i].nom_etud, idEns, std[i].hr_cours], function(er1, res1){
if(er1)
{
console.log('Query error: ');
}
else
{
console.log('success');
}
});
}
});
}
}
res.end("all");
}
});
});
I noticed that the issue is triggered once the execution flow enters the connection.connect block and that it's a scope issue; I searched everywhere for the answer but couldn't find a solution to my specific problem. How can I make this work?
Upvotes: 0
Views: 115
Reputation: 12089
The execution of connection.connect
is delayed and therefore when it fires i
is not the same value as when a reference to i
was passed in to it by the for
loop. So, to lock in the value of i
in that particular loop execution, wrap the connection.connect
method and callback in an IIFE and pass i
as it's parameter:
~function(i) {
connection.connect(function(error){
console.log('after hr_cours = ' + std[i].hr_cours);
// other stuff
})
}(i)
A more detailed explanation of IIFE's and scope closure in my answer here: Odd javascript code execution order
And a JSFiddle playground to explore the technique: IIFE Scope Closure With Pre-Existing Parameters.
Upvotes: 1
Reputation: 34677
Here's your problem:
app.post('/saveABS', function(req, res) {
// ...
for (var i = 0; i < std.length; i++) {
// ...
// This is SYNC. Here i = 0,1,2...
connection.connect(function(error) {
// This is A-SYNC.
// Here i = std.length + 1
// always!
// No matter even if it syntactically looks like i should be 1,2,3 according to the loop
// but all of this is executed way after the loop has long been completed
// ...
// Here it displays undefined.
console.log('after hr_cours = ' + std[i].hr_cours); // <============ undefined
A solution: Have a self executing anonymous function (function(){})()
inside the loop and pass it the arguments (i
) so that they will stay the same
for (var i = 0; i < std.length; i++) (function(i){
connection.connect(function(error) {
// ...
// Here, since i is an argument passed to outer function
// i will be i,2,3...
})(i);
Another solution: forEach
loop, which already has a callback function
std.forEach(function(currentValue, i, std){
connection.connect(function(error) {
// ...
// Same here, since i is an argument passed to outer function
// i will be i,2,3...
// Also currentValue = std[i] so you can use that
});
Upvotes: 1