Reputation: 9087
I have an event that binds a function to a click. The click calls another function in the same view. Unfortunately, the scope is not the correct scope. When I try to do this.otherFunction(), the function that is assigned to the click is not in the same scope as this.otherFunction(). Is there a way to pass in the scope of otherFunction()?
initialize: function() {
this.render();
if (joinedGoalList.get(this.model.id) != null) {
this.renderLeaveGoal();
} else {
this.renderJoinGoal();
}
},
events: {
"keypress #goal-update": "createOnEnter",
"click #join-goal": "joinGoal",
"click #leave-goal": "leaveGoal",
},
joinGoal: function() {
matches = joinedGoalList.where({id: this.model.get("id")});
if (matches.length == 0) {
joinedGoalList.create({goal_id: this.model.get("id")}, {wait: true, success: function() {
var self = this;
self.renderLeaveGoal();
}, error: function() {
console.log("error");
}});
}
},
renderLeaveGoal: function() {
console.log("render leave goal");
var template = _.template($("#leave-goal-template").html());
console.log(template);
$("#toggle-goal-join").html(template());
},
These are all under the same view.
Edit: Hmm, now the problem is that I get this error: Uncaught TypeError: Object [object DOMWindow] has no method 'renderLeaveGoal'. Does this seem that I saved the wrong scope?
Upvotes: 3
Views: 1457
Reputation: 1751
You can also use Underscore's bindAll function like so:
initialize: function() {
_.bindAll(this);
}
Behind the scenes, Underscore will replace all function calls in the object with proxied versions that set "this" to be the same "this" as your original object. Of course, if one of your methods has its own anonymous callback functions inside it, then you'll need to do the whole "self = this" dance; bindAll only fixes the context of your "outer" methods on the object.
I've gotten into the habit of using _.bindAll as the first line in each of my View's initialize() methods.
Upvotes: 2
Reputation: 1785
deltanovember's answer is correct, but he didn't explain why it's correct, and I feel that's important:
Scope is messy in Javascript. I've found the easiest way to keep track of it is to think about when something will execute. If a block of code executes right away, it's probably running in the same scope as "this". If a function is going to be called later, it's probably running in a completely different scope, with its own concept of "this".
In your example, the anonymous function you're providing as that success callback is going to run later, and it won't be scoped to the same "this" as the code that's running when said callback is defined. This is why you're getting an error: renderLeaveGoal was defined in the scope where the callback was defined, but not the scope where the callback will be executed.
Now, to make this more confusing, variables defined when a callback is defined will be available within that callback's scope. This is why deltanovember's answer works. By disguising "this" in a variable when the success callback is defined, the callback can still access it when it runs later, despite the completely different scope.
I hope that makes sense. Comment if it doesn't, and I'll try again :)
Upvotes: 2
Reputation: 161457
The function is attached to the view, so you need to call it off of the View object.
success: this.renderLeaveGoal
In this case, you don't need the anonymous function because the view functions are automatically bound to the view's context.
Upvotes: 1
Reputation: 44051
Standard technique is to do something like
var self = this;
Then you can do
self.otherFunction();
In place of
this.otherFunction();
Upvotes: 5