Backbone collection fetches data, but doesn't set models
Asked Answered
L

2

13

I'm trying to populate my Backbone collection from a local API and change the view to show the data. The fetch() call in my collection seems to succeed, and grabs the data, but the fetch operation doesn't update the models in the collection.

This is what I've got for my model and collection:

var Book = Backbone.Model.extend();

var BookList = Backbone.Collection.extend({

    model: Book,
    url: 'http://local5/api/books',

    initialize: function(){
        this.fetch({
            success: this.fetchSuccess,
            error: this.fetchError
        });
    },

    fetchSuccess: function (collection, response) {
        console.log('Collection fetch success', response);
        console.log('Collection models: ', this.models);
    },

    fetchError: function (collection, response) {
        throw new Error("Books fetch error");
    }

});

and I've done my views like this:

var BookView = Backbone.View.extend({

    tagname: 'li',

    initialize: function(){
        _.bindAll(this, 'render');
        this.model.bind('change', this.render);
    },

    render: function(){
        this.$el.html(this.model.get('author') + ': ' + this.model.get('title'));
        return this;
    }

});

var BookListView = Backbone.View.extend({

    el: $('body'),

    initialize: function(){
        _.bindAll(this, 'render');

        this.collection = new BookList();
        this.collection.bind('reset', this.render)
        this.collection.fetch();

        this.render();
    },

    render: function(){
        console.log('BookListView.render()');
        var self = this;
        this.$el.append('<ul></ul>');
        _(this.collection.models).each(function(item){
            console.log('model: ', item)
            self.appendItem(item);
        }, this);
    }

});

var listView = new BookListView();

and my API returns JSON data like this:

[
    {
        "id": "1",
        "title": "Ice Station Zebra",
        "author": "Alistair MacLaine"
    },
    {
        "id": "2",
        "title": "The Spy Who Came In From The Cold",
        "author": "John le Carré"
    }
]

When I run this code I get this in the console:

BookListView.render() app.js:67
Collection fetch success Array[5]
Collection models:  undefined 

which indicates to me that the fetch call is getting the data OK, but that it's not populating the models with it. Can anyone tell me what I'm doing wrong here?

Laudable answered 20/10, 2013 at 10:27 Comment(0)
R
12

Your fetchSuccess function should have collection.models not this.models.

console.log('Collection models: ', collection.models);

and please consider suggestions given by @Pappa.

Retain answered 20/10, 2013 at 13:21 Comment(3)
Thanks a lot user10, that was the answer! I'm still finding my way and didn't realise that "this" has the global scope inside fetchSuccess - I'm still not 100% sure why, but I find when I bind "this" to fetchSuccess on initializing the collection it has the collection's scope.Laudable
fetchSuccess is a callback called by Backbone.sync which is executed in global scope by Backbone.js.Retain
Ohhhh so that's why! Thanks user10.Laudable
Z
8

You are calling fetch on your BookList collection twice, once when it is initialized and again when your BookListView is initialized. It's considered bad practice to have a collection populate itself at the moment it's instantiated. You're also rendering your view twice inside its initialize call, once in response to the 'reset' event and then you're also calling it directly.

I would suggest removing the initialize function completely from your BookList collection, and removing the call to this.render(); at the end of your BookListView's initialize call.

Zoniazoning answered 20/10, 2013 at 11:56 Comment(2)
if a view has an initialize method it automatically calls this.render()?Assets
@AlexMills No, you have to call the render function manually.Roundly

© 2022 - 2024 — McMap. All rights reserved.