1

I'm building a small reporting tool with Node.js and I am facing some scoping problems with Javascript. I am calling a function and it should return a array with cities from a database query. Here the function.

function queryBuilderZone () {
  var includedCities = new Array();
  q = heredoc(function(){/*
        SELECT majlis.MajlisId
        FROM majlis
        WHERE majlis.ZoneId = -ZONE-
  */});
  q = q.replace(/-ZONE-/g, inZone);

  connection.query(q, function(err, rows, fields) {
        if (err) throw err;
        var rowsLentgh = rows.length;
        for (var i = 0; i < rowsLentgh; i++) {
              includedCities.unshift(rows[i].MajlisId);
        };
        console.log(includedCities); // <-- output correct: ['...', '....']
  });
  connection.end();
  console.log(includedCities); // <-- output wrong: []
  return includedCities;

}

This is my call from the main program

 includedCities = queryBuilderZone();
 console.log(includedCities); // <-- output wrong: []

Where is the problem and why is this function not returning the elements in the array includedCities?
And in the scope of connection.query it shows the correct and expected value.

By the way I am using the mysql module for building the query and replacing the placeholder in the query.

imalik8088
  • 1,501
  • 5
  • 21
  • 39
  • Standard async case. Your "faulty" console log occurs before the callback is done? And "includeCities" is a variable local to your function. – npup Dec 21 '13 at 21:33
  • It seems to me this is a scoping problem. I am not a node.js person, but includeCities is defined within the queryBuilderZone function, which is not in the global scope. Move it above the function into the global scope. – ron tornambe Dec 21 '13 at 21:38
  • @rontornambe this is a very typical problem of a node.js beginner who haven't found the time to read a small tutorial. – hgoebl Dec 21 '13 at 21:42

1 Answers1

3

What's going on here is the difference between a return and a callback. Due to the fact that the connection.query() function is having to reach out to get its information, the queryBuilderZone() function will continue on after it initiates it, and then reach the conclusion that includedCities is and empty Array, because it is at that time.

What you want to do is pass in a callback to queryBuilderZone, something like this

function queryBuilderZone(callback) {
    var includedCities = new Array();
    q = heredoc(function () {
        /*
        SELECT majlis.MajlisId
        FROM majlis
        WHERE majlis.ZoneId = -ZONE-
  */
    });
    q = q.replace(/-ZONE-/g, inZone);

    connection.query(q, function (err, rows, fields) {
        if (err) throw err;
        var rowsLentgh = rows.length;
        for (var i = 0; i < rowsLentgh; i++) {
            includedCities.unshift(rows[i].MajlisId);
        };
        console.log(includedCities); // <-- output correct: ['...', '....']
        callback(includedCities);
    });
    connection.end();
    console.log(includedCities); // <-- output wrong: []
    // return includedCities; Not needed
}

Then when you want to utilize it, you'd do so like this.

queryBuilderZone(function(includedCities) {
    // Do what you'd like here
    console.log(includedCities); // <-- output correct: ['...', '....']
});

Whatever's in the callback function will be executed after connection.query runs its course, and spits out the array.

Robert
  • 21,110
  • 9
  • 55
  • 65
  • 1
    thanks! I didn't know about callbacks. Therefore I am just trying to learn and solve the problem at the same time. Although I could solve it with other languages. I you have any good tutorial for callback then don't hesitate to share it :) – imalik8088 Dec 21 '13 at 22:17