egidra
egidra

Reputation: 9087

Backbone this confusion

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.

Upvotes: 5

Views: 2970

Answers (3)

Kabir Sarin
Kabir Sarin

Reputation: 18526

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);
    ...
}

Upvotes: 2

jonotron
jonotron

Reputation: 83

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.org/#bindAll

Upvotes: 0

Ben
Ben

Reputation: 21249

You 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

Upvotes: 6

Related Questions