Should I use binding or lexical closure with Ember.run?


#1

I have this functions, that I’ve adapted from some sample code.

var getJSON = function(path, query) {
  return new Ember.RSVP.Promise(function(resolve, reject) {
    Ember.$.ajax({
      type: 'GET',
      url: apiRoot + path,
      dataType: 'json',
      data: query
    }).then(function(data) {
      Ember.run(null, resolve, data);
    }, function(jqXHR) {
      jqXHR.then = null; // tame jQuery's ill mannered promises
      Ember.run(null, reject, jqXHR);
    });
  });
};

And I call it from a route:

events: {
  login: function () {
    var model = this.modelFor('sessions/login'); // <App.LoginCreds>
    this.getJSON('/authuser', model.serialize()).then(function(data) {
      this.store.pushPayload("user", data);
    }, function(jqXHR) {
      console.log(jqXHR);
      alert("Error!");
    });
  }
}

And this results in -> TypeError: Cannot read property 'store' of undefined

What’s the (coining the rails term) ember way of solving this? Should I use just regular lexical closure var that = this; ... that.store(... or should I instead bind the context already in the getJSON method, by doing Ember.run.bind(this, resolve, data); or something entirely different?

EDIT: Oops the second idea does not actually work, how could this be achieved?


#2

Yes, exactly that. Within the .then() callback you lost the scope, so store the value of this outside of it in a separate variable and use it there.


#3

Incidentally, if you’re using Ember CLI and you’re up to date, you can now do this:

this.getJSON('/authuser', model.serialize()).then( (data) => {
  this.store.pushPayload("user", data);
}, ...

#4

Thank’s guys. @totallymike that’s so cool. Exactly something I was looking for! :smile:


#5

Um, I need some help. My understanding of Ember.run.bind is that “the invocation of that method be safely handled and executed by the Ember run loop.” With the comments on this it seems we are attempting to do the same thing that Ember.run.bind does but manually in two different steps! Please correct me if I’m wrong but wouldn’t using Ember.run.bind to return the call back function eliminate the need for var _this = this; or () => {} and allow the function definition to be part of the event object instead of an inline anonymous function (which are notoriously hard to read)?

Sorry to revive an old thread but I just can’t wrap my head around the idea that Ember.run.bind doesn’t work as expected.