Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle nested CompositeView using Backbone.Marionette?

I'm getting into larger-scale data structures with Backbone, and coming across occasions where data would be well-represented via CompositeViews; that is, CollectionViews with the addition of "added fluff" around them, such as headers, buttons, and so on.

However, I'm having a lot of difficulty nesting CompositeViews inside one another. Using the standard itemView property on a CompositeView to render another CompositeView doesn't seem to be firing at all.

Assume I have a parent ItemView, instantiated as such (following Derick Bailey's example; assume this top level is where the initial fetch() on the collection would be called):

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

var UserCollection = Backbone.Collection.extend({
    model: User
});

var userList = new UserCollection(userData);

var schedulerCompositeView = new SchedulerCompositeView({
    collection: userList
});

schedulerCompositeView.render();

this.ui.schedulerWidget.html(schedulerCompositeView.el);

And SchedulerCompositeView looks as such:

return Backbone.Marionette.CompositeView.extend({
    template: Handlebars.compile(schedulerCompositeViewTemplate),
    itemView: SchedulerDetailCompositeView,
    appendHtml: function (collectionView, itemView) {
        collectionView.$("#schedulerGroups").append(itemView.el);
    }
});

And finally, SchedulerDetailCompositeView:

return Backbone.Marionette.CompositeView.extend({
    template: Handlebars.compile(schedulerDetailCompositeViewTemplate),
    itemView: SchedulerDetailItemView,
    appendHtml: function (collectionView, itemView) {
        collectionView.$("#schedulerDetailStops").append(itemView.el);
    }
});

SchedulerDetailCompositeView never gets instantiated; in fact, its appendHtml() method never seems to fire at all.

Clearly there's some other information missing here; obviously the intent is to pass a collection/model to SchedulerDetailCompositeView, but I'm not really sure what the proper technique for doing so is, due to the nested CompositeViews.

For reference, here's a rough mockup of the structure I'm trying to achieve; if there might be a better manner for reaching this goal than nested CompositeViews, I'm certainly all ears:

http://jsfiddle.net/KAWB8/

like image 992
J. Ky Marsh Avatar asked Nov 26 '12 23:11

J. Ky Marsh


1 Answers

Eureka! I was set upon the correct path by deven98602.

The key to remember is that, if you're nesting multiple CompositeViews (or CollectionViews), each cascading level down will represent one unit of the set from its parent; that is, my SchedulerDetailCompositeView from before represents a single model from the collection in SchedulerCompositeView. Therefore, if I'm constructing nested CompositeViews (presumably based on deeply-nested data), I must redefine a collection on these cascaded children, as they only have a single model associated with them, and not a proper collection to render.

That said, the updated SchedulerDetailCompositeView looks as such:

return Backbone.Marionette.CompositeView.extend({
    template: Handlebars.compile(schedulerDetailCompositeViewTemplate),
    itemView: SchedulerDetailItemView,
    initialize: function () {
        var Load = Backbone.Model.extend();

        var LoadCollection = Backbone.Collection.extend({
            model: Load
        });

        // this array of loads, nested within my JSON data, represents
        //  a new collection to be rendered as models using SchedulerDetailItemView
        var loadList = new LoadCollection(this.model.get("loads"));

        this.collection = loadList;
    },
    appendHtml: function (collectionView, itemView) {
        collectionView.$("#schedulerDetailStops").append(itemView.el);
    }
});

Once the collection is set, appendHtml() fires as expected and renders each new model in this newly-set collection.

like image 133
J. Ky Marsh Avatar answered Oct 18 '22 10:10

J. Ky Marsh