3

So I need some help I've been stuck on this for a couple of hours now..

The problem is I'm creating this object called Rank. Rank needs to do some DB calls in mongodb to get data to fill a matrix, then needs to perform even more nested function calls on this matrix which I haven't written yet. The problem is that when I'm calling doRank() its gets the companies and transactions and seems to put them in Rank but then when I call createMatrix it can't access 'this'

I have tried using .bind(this) on each of the functions in doRank() which prevents the error that the method doesn't exist but then when I do the console.log at the end of doRank() the results for matrix are undefined.

function Rank(dampingfactor){
  this.damping_factor = dampingfactor;
  this.companies = null;
  this.transactions = null;
  this.matrix = null;

  this.doRank(function(){
    //companies returns valid
    console.log(this.companies);
    //transactions return valid
    console.log(this.transactions);
    //matrix returns as undefined... help here please
    console.log(this.matrix);
  });
};

Rank.prototype.doRank = function(callback) {
  this.getTransactions(function() {
    this.getCompanies(function () {
        this.createMatrix(function(){
            callback();
        }.bind(this));
    }.bind(this));
  }.bind(this));
};

Rank.prototype.getTransactions = function(callback){
  Transaction.find({}, function(err, transactions) {
    //blah blah blah
    this.transaction = transactions;
    callback();
  });
};

Rank.prototype.getCompanies = function(callback){
  Company.find({}, function(err, comps) {
    //blah blah blah
    this.transaction = comps;
    callback();
  });
};

Rank.prototype.createMatrix = function(callback){
  console.log(this.companies)
  //this returns "null"
  var matrix = new Array(_.size(this.companies));
  for(var i = 0; i < _.size(this.companies); i++){
      matrix[i] = new Array(_.size(this.companies));
      for(var j=0; j < _.size(this.companies); j++){
        matrix[i][j] = 0;
      }
  }
  this.matrix = matrix;
  callback();
};
Siebz
  • 361
  • 2
  • 12
  • 2
    Your use of `.bind()` is a fine approach. If your `console.log()` at the end of `.doRank()` is at the very end of the function and not immediately after the call to `callback()`, then the result is `undefined` because you're working with asynchronous APIs. – Pointy Oct 04 '14 at 13:09
  • everything seems to be null when I try to access the original object inside of doRank getCompanies or createMatrix, something with the bind is not working – Siebz Oct 04 '14 at 13:29

2 Answers2

4

You are losing context in AJAX callback functions inside getTransactions and getCompanies too. Try this:

Rank.prototype.getTransactions = function(callback) {
    Transaction.find({}, function(err, transactions) {
        //blah blah blah
        this.transaction = transactions;
        callback();
    }.bind(this));
};

Rank.prototype.getCompanies = function(callback) {
    Company.find({}, function(err, comps) {
        //blah blah blah
        this.transaction = comps;
        callback();
    }.bind(this));
};
dfsq
  • 191,768
  • 25
  • 236
  • 258
3

this no longer refers to an object when used inside nested function calls, as the function does not have a parent object. If you assign this to a variable e.g. var self = this, you can access it like normal inside nested function calls.

Arvoreniad
  • 510
  • 5
  • 10
  • This is true, but the use of `.bind()` in the code posted will work too. – Pointy Oct 04 '14 at 13:09
  • It's confusing and misleading to say "the scope of `this` is redefined". First, I guess you meant "value", not "scope". And it is not "redefined" from anything, it has the same meaning it has anywhere else, which is the object of which the function in which it is used is a member. In this case, there is no object of which the function is a member, so it's value is the global object (or null, depending on strictness). –  Oct 04 '14 at 14:58