KJW
KJW

Reputation: 15251

backbone: render this collection

var Text = Backbone.Model.extend({});   

Texts = Backbone.Collection.extend({
    model: Text,
    url: '/data.json',
});

var TextsView = Backbone.View.extend({
    initialize: function() {
        _.bindAll(this);
        this.render();
    },
    el: "#Texts",
    template: _.template($('#TextTemplate').html()),
    render: function(e){
        _.each(this.model.models, function(Text){
            var TextTemplate = this.template(Text.toJSON());
            $(this.el).append(TextTemplate);
        }, this);
        return this;
    }
})

var Texts = new Texts();
Texts.fetch();
var TextView = new TextsView({collection: Texts});

this gives me Uncaught TypeError: Cannot read property 'models' of undefined and does not display anything on the page.

Upvotes: 2

Views: 82

Answers (1)

Gohn67
Gohn67

Reputation: 10638

This this.model.models should be this.collection

In your render method in your view, you should use this.collection.each instead of _.each function.

render: function(e){
    this.collection.each(function(Text){
        var TextTemplate = this.template(Text.toJSON());
        $(this.el).append(TextTemplate);
    }, this);
    return this;
}

If you want to use _.each function, then you will need to access the models array directly in your collection as @dfsq pointed out. This can be done by using this.collection.models.

render: function(e){
    _.each(this.collection.models, function(Text){
        var TextTemplate = this.template(Text.toJSON());
        $(this.el).append(TextTemplate);
    }, this);
    return this;
}

EDIT 2

Here are some reasons your fetch call may not be working. First check that you are using a web server, since ajax requests may be blocked for security reasons using file system. I know this is blocked in Chrome unless you change a certain setting. Not sure about Firefox.

The second reason is that the fetch call is asynchronous. This means that mostly likely your data will not be loaded when you run initialize

This means you'll need to make the following adjustments. First you need to add a listener to the add event of your collection so that anytime an item is added, your view will be notified.

initialize: function() {
    _.bindAll(this);
    this.render();
    // Listen to the `add` event in your collection
    this.listenTo(this.collection,"add", this.renderText);  
},

Next we need to add a function to your view that will render a single item

renderText: function(Text) {
    var TextTemplate = this.template(Text.toJSON());
    this.$el.append(TextTemplate);        
}

Also to answer your other question about the user of this in the each loop. The last parameter in the each function is the scope you want to use in the inside the callback function that executes. So if you use this as the second parameter, it allows you to access your viewing using this.

    this.collection.each(function(Text){
        var TextTemplate = this.template(Text.toJSON());
        $(this.el).append(TextTemplate);
    }, this);

If you don't add this, then you'd need to do this:

    var view = this;
    this.collection.each(function(Text){
        var TextTemplate = view.template(Text.toJSON());
        $(view.el).append(TextTemplate);
    });

Upvotes: 2

Related Questions