Search code examples
backbone.jsmarionettebackbone-views

Backbone Marionette: Rendering Collection in ItemView


I was unable to find any posts relevant to this error. I am attempting to render a Backbone Collection in a Marionette ItemView. The template is rendered, however, the data related to the collection is not rendered in the template. I am getting no errors or other indicators. For reasons I do not understand, using setTimeout() on App.mainRegion.show(overView). However, I know that that is not an acceptable solution. Could someone give me some insight on how to make an ItemView for a Collection properly render in this case? Here is my simplified code:

My Collection to be rendered:

About.Collection = Backbone.Collection.extend({
    url: '/api/about',
    idAttribute: '_id',
});

Involved View definitions:

About.ListView = Marionette.CollectionView.extend({
    tagName: 'ul',
    itemView: App.About.ListItemView,   
});

About.OverView = Marionette.ItemView.extend({
    tagName: 'div',
    className: 'inner',
    template: _.template('<h2>About Overview</h2><p><%= items %></p>'),
});

My relevant execution code:

var API = {
    getAbouts: function() {
        var abouts = new App.About.Collection();
        abouts.fetch();
    return abouts;
    },
    ...
}

var abouts = API.getAbouts();

var aboutsListView = new App.About.ListView({collection: abouts }),
aboutsOverView = new App.About.OverView({collection: abouts});

// Correctly renders collection data
App.listRegion.show(aboutsListView);

// Does not render collection data
App.mainRegion.show(aboutsOverView);

// unless
setTimeout(function() {App.mainRegion.show(aboutsOverView)}, 50);

For those who are interested, I am using an ItemView with the eventual intent to display aggregate data of About.Collection. I will be happy to provide additional information, if needed.


Solution

  • It's an issue with the asynchronous nature of the fetch call on your collection. The data for the collection has not returned when you show the two views. If you update the execution part of your code something like the following (untested), you should be on the right tracks:

    var API = {
        getAbouts: function() {
            // Just return the new collection here
            return new App.About.Collection();
        },
        ...
    }
    
    // Fetch the collection here and show views on success
    var abouts = API.getAbouts().fetch({
        success: function() {
            var aboutsListView = new App.About.ListView({collection: abouts }),
            aboutsOverView = new App.About.OverView({collection: abouts});
    
            // Should render collection data now
            App.listRegion.show(aboutsListView);
    
            // Should render collection data now
            App.mainRegion.show(aboutsOverView);
        }
    });