简体   繁体   中英

Problems with scoping in Nodejs module

I'm just starting with Node and I am getting stuck with managing the "callback hell." I have successfully managed to work with the Event emitter in order to fire an event in the main js file from a module, but I am unable to figure out how to work the scoping to fire an event from within a callback in the module. Furthermore, I am having issues calling a prototype function from within the call back in the module.

Specifically, here:

rows.forEach(function(thisRow, index, array) {
  myDb.query("SELECT COUNT(a.studentID) as total, m.fName, m.lName, m.id " +
        "from `absences` a join `members` m on a.studentID = m.id " + 
        "where a.aDate>=" + myDb.escape(thisRow['beginDate']) + " and " + 
        "a.aDate<=" + myDb.escape(thisRow['endDate']) + " and a.aDate<'" + today + "' and m.memGroup = " + myDb.escape(thisRow['orchName']) + 
        "GROUP BY a.studentID ORDER BY total DESC", function(error, row){
            if(row.length > 0) {
                retValues.push({"fullName": thisRow.fullName, "shortName": thisRow.shortName, "absences": row});
            }
            if (index === array.length - 1) {  
                //This call to this fails because, I believe, it is out of scope. 
                //How can I access this? OR how can I emit an event here that will
                //trigger the listener in the index.js?  
                this._alertServer;
                console.log(retValues);
                console.log("Done");  
            }
    });
});

The complete code can be found at: http://pastebin.com/Gw6kzugk

EDIT - The possible answers above are exactly what you should be looking for. Below is what I ended up doing in my situation. Thanks All!

As explained in the comments, you can't use this inside a callback. You need to capture it outside of the callback, like this:

rows.forEach(function(thisRow, index, array) {
    var self = this; // the critical line
    myDb.query("SELECT COUNT(a.studentID) as total, m.fName, m.lName, m.id " +
        "from `absences` a join `members` m on a.studentID = m.id " + 
        "where a.aDate>=" + myDb.escape(thisRow['beginDate']) + " and " + 
        "a.aDate<=" + myDb.escape(thisRow['endDate']) + " and a.aDate<'" + today + "' and m.memGroup = " + myDb.escape(thisRow['orchName']) + 
        "GROUP BY a.studentID ORDER BY total DESC", function(error, row){
            if(row.length > 0) {
                retValues.push({"fullName": thisRow.fullName, "shortName": thisRow.shortName, "absences": row});
            }
            if (index === array.length - 1) {  
                // Use self here, not this
                self._alertServer;
                console.log(retValues);
                console.log("Done");  
            }
    });
});

Although it may not be the most elegant want to approach this situation, what I ended up doing was passing this in a context function a la the short amount of time I spent programming Android programs.

_getAttendanceBySession = function(err, rows, retValue, context) {
    /*
    Gets attendance for each session given
    err -> Errors returned from last mySQL query
    rows -> JS Object of session list
    retValue -> string being passed to webserver
    context -> 'this'
    */

  var tmpHTML;
  tmpHTML = retValue;
  myDb.getConnection(function(err, conn) {
    rows.forEach(function(thisRow, index, array) {
      conn.query("SELECT COUNT(a.studentID) as total, m.fName, m.lName, m.id from `absences` a join `members` m on a.studentID = m.id where a.aDate>=" + (myDb.escape(thisRow.beginDate)) + " and a.aDate<=" + (myDb.escape(thisRow.endDate)) + " and a.aDate<'" + today + "' and m.memGroup = " + (myDb.escape(thisRow.orchName)) + " GROUP BY a.studentID ORDER BY total DESC", function(error, row) {
        if (row.length > 0) {
          tmpHTML = tmpHTML + ("<h3 class='text-center'>" + thisRow.fullName + "</h3><div class='panel-group' id='" + thisRow.shortName + "'>");
          row.forEach(function(studentRow, index2, array2) {
            var tmpLabel;
            if (studentRow.total === 1) {
              tmpLabel = 'label-default';
            } else if (studentRow.total === 2) {
              tmpLabel = 'label-warning';
            } else {
              tmpLabel = 'label-danger';
            }
            tmpHTML = tmpHTML + ("<div class='panel panel-default'><div class='panel-heading'><a class='attendance-link panel-title' data-toggle='collapse' data-parent='#" + thisRow.shortName + "' href='#" + studentRow.id + "-details'><span class='label pull-left " + tmpLabel + "'>" + studentRow.total + "</span>" + studentRow.fName + " " + studentRow.lName + "</a></div><div class='panel-body collapse' id='" + studentRow.id + "-details'></div></div>");
            if (index2 === array2.length - 1) {
              tmpHTML = tmpHTML + "</div>";
            }
          });
        }
        if (index === array.length - 1) {
          conn.release();
          context.emit("send-page", tmpHTML);
        }
      });
    });
  });
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM