简体   繁体   中英

Scope error using Backbone.js?

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() 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 .

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) {
            // ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM