0

I seem to have an issue with the parameters I am trying to set from within the success callback function:

var CampModel = CampDataModel.extend({

    initialize : function(){

        this.fetchActiveAndPending();
        console.log(this.get('active'));
    },

    //Counts active and pending campaigns for front page.
    CountActiveAndPending : function(data){
      var active = 0;
      var pending = 0;

      $.each(data.returnValue,function(index,val){
        if (val.ApprovedOnSite){
          active++;
        }
        else
          pending++;       
      });
      this.set('active',active);
      this.set('pending',pending);
    },

    //fetches  data from server using campModel.
    fetchActiveAndPending : function(){
      console.log('fetching!');
      that = this;
     this.fetch({
        success:function(model,response){
          that.CountActiveAndPending(response);        
        }

      });
       }
    });

    return CampModel;
});

the result of this.get('active') is always the default number. If I try and use this.get('active') from within the success callback function it gives the right result. Is it possible to set a var from within the callback func and call it from outside, let's say the initialize function?

Yuval
  • 307
  • 3
  • 14

2 Answers2

1

It's not a problem of closures (meaning that your variable isn't accessible from your callback function or something weird like that), it's a problem of execution timing. Your success callback will be executed asynchronously when the client gets the response from the server. The only way to be sure that the response has arrived is to use the listeners (http://backbonejs.org/#Events) or the callbacks (as your success function). If you make sure that a part of your code is executed after the response was received, you'll have the right value for your active parameter.

Here when you do:

console.log(this.get('active'));

The request is still pending, therefore active is still equal to -1. So your problem is still that you're not considering the asynchronous side of your code.

Loamhoof
  • 8,293
  • 27
  • 30
  • bare with me here :) isn't running a function within the success callback make sure the response came back? – Yuval Jul 01 '13 at 14:01
  • @Yuval well, it makes sure that it came back successfully at least, but you're still running the `console.log` before. – Loamhoof Jul 01 '13 at 14:33
  • To be clear, you define the callback before the call, but it's still run after the response has been received. – Loamhoof Jul 01 '13 at 14:39
1

I agree with @Loamhoof, you have a timing issue, one solution is:

initialize : function(){
  this.fetchActiveAndPending(function() {
      console.log(this.get('active'));
  });
},

CountActiveAndPending : function(data){
  ...
},

fetchActiveAndPending : function(completeFn){
  console.log('fetching!');
  var _this = this;
  this.fetch({
    success:function(model,response){
      _this.CountActiveAndPending(response);
      completeFn();
    }

  });
}

p.s. Thanks to @Loamhoof for challenging my previous assumptions and providing an example.

buddyw
  • 43
  • 7
  • You don't pass the context, it's pretty ugly, instead you bind it: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind, http://underscorejs.org/#bind. Also, he's using `that` already, so the context isn't a problem. – Loamhoof Jul 01 '13 at 14:36
  • @Loamhoof I agree with you that passing the context is a bad idea, I just wanted to provide a second option by way of explanation (although that wasn't very clear). Bind works too, just a matter of syntactical preference. Of course, the problem remains, the value of this has changed (even in using that to call the function), so you need to use either .call() or .bind(). Therefore, this is not a timing issue. – buddyw Jul 01 '13 at 14:59
  • @Loamhoof, you are right about why his console.log() statement isn't working in initialize() (timing issue) which is a separate issue from what I was describing (the value of this in CountActiveAndPending()). Both changes are necessary. – buddyw Jul 01 '13 at 15:33
  • I recommend that you take a look at http://jsfiddle.net/j9mDF/. The situation is the same. The context is not the same in the callback, but it will be his object after calling a method of `that`. – Loamhoof Jul 01 '13 at 15:36
  • Furthermore, if he had a context problem, a `Object window does not have a method set` or something like that would be thrown. – Loamhoof Jul 01 '13 at 15:39
  • @Loamhoof thanks for the jsfiddle example. I'll get back with you in a bit (after lunch). – buddyw Jul 01 '13 at 15:49
  • @buddyw, thanks for the effort but the solution you proposed does not keep the value for the console.log(this.get('active')) outside the fetchActiveAndPending function (in initialize). Running console.log(this.get('active')) in the fetchActiveAndPending function is the same as running it in the success callback function. – Yuval Jul 02 '13 at 07:16
  • @Yuval thanks! I am confused by your statement above, "does not keep the value for...outside the featchActiveAndPending function". What are you trying to achieve? – buddyw Jul 02 '13 at 23:01
  • @buddyw, I need to use one of the parameters that I get back from the response but at a later time, this means that calling a function from within the success callback doesn't do the trick. – Yuval Jul 03 '13 at 08:20
  • Well, in the end I didn't use the params returned in the callback, I listened for changes in the model from a view ,and the minute the model changes (the active and pending parameters in this case) the view gets the updated values - it's not exactly what I wanted but it will do. Thanks again for the help! – Yuval Jul 03 '13 at 20:06