I have the following code:
var GoalPanelView = Backbone.View.extend({
// Bind to the goal panel DOM element
el: $("#sidebar-goals"),
// Initialize the collection
initialize: function() {
this.collection = Goals;
this.collection.bind('add', this.appendItem);
},
// Create a new goal when a user presses enter in the enter goal input
createOnEnter: function(e) {
if (e.keyCode != 13) return;
this.addItem();
//Goals.create(this.newAttributes());
},
// Add the goal item to the goal list
addItem: function() {
var goal = new Goal();
goal.set(this.newAttributes());
var goalsElem = this.el;
this.collection.add(goal);
$(this.el).children("#enter-goal").val('');
},
// Append DOM element to the parent el
appendItem: function(item) {
var goalView = new GoalView({
model: item,
});
$(this.elem).append(goalView.render().el);
}
});
My problem is inside of the appendItem
function. When I use this
inside of the appendItem
function, I believe that it thinks that the this
refers to the this.collection
rather than the GoalPanelView
. How would I get the this
to refer to the GoalPanelView
rather than the collection
? I tried to pass another variable into the appendItem
function which held the contents of this.elem
, but it didn't seem to work.
One thing that worked was when I moved the appendItem
function into the collection
and changed the initialization to bind to this.collection.bind('add', appendItem);
but I do not want to put the view
stuff into the collection
logic.
I have the following code:
var GoalPanelView = Backbone.View.extend({
// Bind to the goal panel DOM element
el: $("#sidebar-goals"),
// Initialize the collection
initialize: function() {
this.collection = Goals;
this.collection.bind('add', this.appendItem);
},
// Create a new goal when a user presses enter in the enter goal input
createOnEnter: function(e) {
if (e.keyCode != 13) return;
this.addItem();
//Goals.create(this.newAttributes());
},
// Add the goal item to the goal list
addItem: function() {
var goal = new Goal();
goal.set(this.newAttributes());
var goalsElem = this.el;
this.collection.add(goal);
$(this.el).children("#enter-goal").val('');
},
// Append DOM element to the parent el
appendItem: function(item) {
var goalView = new GoalView({
model: item,
});
$(this.elem).append(goalView.render().el);
}
});
My problem is inside of the appendItem
function. When I use this
inside of the appendItem
function, I believe that it thinks that the this
refers to the this.collection
rather than the GoalPanelView
. How would I get the this
to refer to the GoalPanelView
rather than the collection
? I tried to pass another variable into the appendItem
function which held the contents of this.elem
, but it didn't seem to work.
One thing that worked was when I moved the appendItem
function into the collection
and changed the initialization to bind to this.collection.bind('add', appendItem);
but I do not want to put the view
stuff into the collection
logic.
-
2
An alternative is putting
_.bindAll(this)
in your initialize function. That ensures that any function called within the object will be applied with the value ofthis
bound properly to the object itself. Useful if you're writing lots of callbacks. – rybosome Commented Jul 30, 2012 at 6:02
3 Answers
Reset to default 6You can add a scope when binding an event handler, like so:
this.collection.bind('add', this.appendItem, this);
The scope sets the value of this
inside the handler. In you case, the current object.
Edit: Javascript Garden has a great explaination why this.appendItem
does not actually carry the scope of the function itself, it's just a function pointer, not a method pointer. One of the quirks of Javascript..
Edit 2 Backbone Reference - Events / on
Just to update (as of Backbone 0.9.2), the proper way to do this is:
initialize: function() {
this.collection.on("add", this.appendItem, this);
...
}
Depending on your use case, you may also want to consider:
initialize: function() {
this.listenTo(this.collection, "add", this.appendItem);
...
}
You can also use underscore's _.bindAll
function in your initialize
method:
initialize: function() {
_.bindAll(this);
this.collection = Goals;
this.collection.bind('add', this.appendItem);
}
Now any call to any method on GoalPanelView
(e.g. appendItem
) will be scoped such that references to this
refer to the GoalPanelView
instance.
You can also pass in a list of method names as strings if you don't want to scope all the methods of GoalPanelView
See here: http://underscorejs/#bindAll