0

I have a Collection, where each item in the Collection could itself be a Collection. I can render each item in the Collection, and indeed can render any items which themselves are Collections. The problem I have is how to render this structure where the HTML reflects the hierarchical nature of the data structure. At the moment, the hierarchy is flattened and I end up with one long list of <div> elements.

I have a View for each item in a Collection which renders a single item and also checks to see if any nested items exist require rendering:

ItemView = Backbone.View.extend({
    el: $("div#ItemView"),

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

    render: function() {
        // Render a single item from the Collection
        $(this.el).append('<div id=' + this.model.id + '></div>');
        // Create a View to render the nested Collection
        var collectionView = new CollectionView({ collection: this.model.nestedCollection });
        collectionView.render();
        return this;
    }
});

Now this is perhaps where my problem is, but the CollectionView will create an ItemView for each Item it needs to render. This is how the recursive nature of the hierarchy is handled, however the flattening occurs because an ItemView always has the same $("div#ItemView") element it appends everything to.

CollectionsView = Backbone.View.extend({
    initialize:function() {
        _.bindAll(this, 'render');
    },

    render: function() {
        var self = this;

        // Iterate over collection, rendering each item
        _(this.collection.models).each( function( item ) {
            var itemView = new ItemView({model: item});
            itemView.render();
        }, this);

        return this;
    }
});

I would like to be able to append Items to a 'parent' element which is not $("div#ItemView"). The HTML structure I would like to end-up with would be something like:

<div>
    <div>...</div>
    <div>
        <div>...</div>
        ...
    </div>
    ...
</div>

Have I painted myself into a corner here?

2 Answers 2

1

In my Backbone.Marionette framework, I have a view type called a "CompositeView" which works this way.

The basic idea of a CompositeView is that it can render a model and a collection within the same view.

It can render a single model with a template. It can also take a collection from that model and for each model in that collection, render a view. By default it uses the same composite view type that you've defined, to render each of the models in the collection. All you have to do is tell the view instance where the collection is, via the initialize method, and you'll get a recursive hierarchy rendered.

I have a working demo in a JSFiddle, here: http://jsfiddle.net/derickbailey/AdWjU/

And you can get the source code and documentation for Marionette, here: https://github.com/derickbailey/backbone.marionette

I know I'm not directly answering your question, but there's a lot more to this than you might think. Hopefully the demo and the plugin will be helpful to you, though.

Sign up to request clarification or add additional context in comments.

Comments

0

I have a found a solution...it doesn't feel that 'framework-like', but it's simple and seems to work.

I have two Views:

  1. ItemView
  2. CollectionView

The general flow is as follows:

ItemView.render() renders itself by appending a <div> element to a known HTML element in the page. It's next job is to create a CollectionView for the Collection it contains. The CollectionView then creates an ItemView for each item in the collection.

The solution was:

Just after ItemView has appended itself and in doing so created a new <div>, I set the el attribute of the CollectionView to that newly appended <div>. The CollectionView then uses it's updated el attribute to set the el attribute of the ItemView it is creating for each Item in the collection. Then when each ItemView renders itself, it is doing so to its 'parent' <div>.

Comments

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.