0

I believe my problem relates to scope somehow, as I'm a js newbie. I have a tiny backbone.js example where all I am trying to do is print out a list of items fetched from the server.

$(function(){
    // = Models =
    // Video
    window.Video = Backbone.Model.extend({
        defaults: function() {
            return {
                title: 'No title',
                description: 'No description'
            };
        },
        urlRoot: 'api/v1/video/'
    });

    // VideoList Collection
    // To be extended for Asset Manager and Search later...
    window.VideoList = Backbone.Collection.extend({
        model: Video,
        url: 'api/v1/video/'
    });

    // = Views =
    window.VideoListView = Backbone.View.extend({
        tagName: 'ul',

        render: function(eventName) {
            $(this.el).html("");
            _.each(this.model.models, function(video) {
                $(this.el).append(new VideoListRowView({model:video}).render().el);
                }, this);
            return this;
        }
    });

    // VideoRow
    window.VideoListRowView = Backbone.View.extend({
        tagName: "li",

        template: _.template("id: <%= id %>; title: <%= title %>"),

        className: "asset-video-row",

        render: function() {
            $(this.el).html(this.template(this.model.toJSON()));
            return this;
        }
    });

    // Router
    var AppRouter = Backbone.Router.extend({

        routes:{
            "":"assetManager"
        },

        assetManager:function() {
            this.assetList = new VideoList();
            this.assetListView = new VideoListView({model:this.assetList});
            this.assetList.fetch();
            $('#content').html(this.assetListView.render().el);
        }
    });

    var app = new AppRouter();
    Backbone.history.start();

    // The following works fine:
    window.mylist = new VideoList();
    window.mylistview =  new VideoListView({model:window.mylist});
});

If I access mylist.fetch(); mylist.toJSON() from the console, mylist populates fine. I can tell that this.assetList.fetch() is accurately fetching the data from the backend, but it doesn't appear to be adding the objects to this.assetList.

1 Answer 1

1

The fetch method on Backbone collections is asynchronous:

Fetch the default set of models for this collection from the server, resetting the collection when they arrive. [...] Delegates to Backbone.sync under the covers, for custom persistence strategies.

And Backbone.sync says:

Backbone.sync is the function that Backbone calls every time it attempts to read or save a model to the server. By default, it uses (jQuery/Zepto).ajax to make a RESTful JSON request.

So fetch involves an (asynchronous) AJAX call and that means that you're trying to use the collection before fetch has retrieved the data from the server. Note that fetch supports success and error callbacks so you can do this instead:

var self = this;
this.assetList.fetch({
    success: function(collection, response) {
        $('#content').html(self.assetListView.render().el);
    }
});

Or you could bind a callback to the collection's reset event as fetch will reset the collection. Then render your assetListView when the collection's reset event is triggered.

Also, your assetList is a collection so you should be doing:

this.assetListView = new VideoListView({collection: this.assetList});

and:

window.VideoListView = Backbone.View.extend({
    tagName: 'ul',

    render: function(eventName) {
        $(this.el).html("");
        _.each(this.collection.models, function(video) {
            // ...
Sign up to request clarification or add additional context in comments.

3 Comments

So you make good suggestions for how to organize binding the event, etc., but if you explained what my problem is I'm afraid I've missed it. *** Nevermind, it clicked. It's asynchronous so that the rendering event that follows is not waiting for fetch() to complete. Thank you! I'll test it and come back to mark correct if it works out.
Spot on. From here on out I'll be using the event bindings.
@akoumjian: Right, the root of your problem is that you're trying to use the collection before fetch has fetched it from the server. I've clarified that for posterity. Doing as much as possible through the events system will save you a lot of trouble.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.