Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing context with bind in backbone.js

I want my panels to re-render themselves when they are clicked.

However, when I perform a click I get the following:

Uncaught TypeError: Cannot call method 'get' of undefined

It appears that the "this" that I'm logging is in fact the model itself:

_callbacks: Object
_changed: true
_escapedAttributes: Object
_previousAttributes: Object
attributes: Object
cid: "c0"
collection: r.d
id: "f5589ba4-a0aa-dd86-9697-30e532e0f975"
__proto__: n

I'm having trouble figuring out why the appropriate "this" isn't preserved by passing my context into model.bind.

Here's my code:

// Models
window.Panel = Backbone.Model.extend({

    defaults: function(){
        return {
            flipped: false,
        };
    },

    toggle: function(){
        this.save({flipped: !this.get("flipped")});
    },

});


// Collections

window.PanelList = Backbone.Collection.extend({

    model:Panel,

    localStorage: new Store("panels"),    

    flipped: function(){
        return this.filter(function(panel){ return panel.get("flipped"); })
    }   
});


// Global collection of Panels
window.Panels = new PanelList;

// Panel View

window.PanelView = Backbone.View.extend({ 

    tagName: 'div',

    template: _.template($("#panel-template").html()),  

    events: {
        "click" : "toggle"
    },

    initialize: function(){
        this.model.bind("change", this.render, this) 
        $(this.el).html(this.template(this.model.toJSON()));
    },     

    render: function(){    
        console.log(this);
        var flipped = this.model.get("flipped")
        if (flipped){
           $(this.el).addClass("flip"); 
        } else{
           $(this.el).removeClass("flip"); 
        }           
        return this   
    },

    toggle: function(){
        this.model.toggle(); 
    }
});   
like image 630
nottombrown Avatar asked Aug 31 '11 08:08

nottombrown


2 Answers

The backbone-y way of doing this is to use the _.bindAll(...) function provided by underscore:

initialize: function(){
    _.bindAll(this, "render");
    this.model.bind("change", this.render) 
    $(this.el).html(this.template(this.model.toJSON()));
}

What _.bindAll does is documented here, but it is essentially built exactly for this purpose. If you want to have this properly set in all functions of the object, you can call _.bindAll(this) with no list of functions. I tend to have this global bind function in most of my views.

like image 170
idbentley Avatar answered Nov 17 '22 01:11

idbentley


I ran into the same issue and ended up using underscore.js's _.bind() method instead. I queried SO for a response, and it was the reply I got.

Try changing: this.model.bind("change", this.render, this)

To: this.model.bind("change", _.bind(this.render, this))

like image 45
rkw Avatar answered Nov 17 '22 02:11

rkw