Search code examples
marionettebackbone-viewscollectionview

Inject html between Marionette ItemViews inside a CollectionView


I have a collection view (MyCollView below), and want to (conditionally) inject html between the different itemViews (MyItemView below) without modifying MyItemView. I know there are lots of different options that CollectionViews can have, but didn't see anything for this particular use.

More specifics: I want to inject a <br> tag after each MyItemView in the MyCollView as long as the instance of MyItemView is not the last in the collection. Here's my desired output for what my collection view would render:

<div>name1</div>
<br>
<div>name2</div>
<br>
<div>name3</div>

Here's my code:

MyItemView = Backbone.Marionette.ItemView.extend({
    template: _.template('<div><%= name %></div>')
});

MyCollView = Backbone.Marionette.CollectionView.extend({
    childView: MyItemView
    //ideally, I would like to provide some other property to accomplish my goal here, like...
    //separatorHtml: '<br>'
});

var myColl = new Backbone.Collection([
    {name: 'name1'},
    {name: 'name2'},
    {name: 'name3'}
]);

thisCollView = new MyCollView({
    collection: myColl
});

thisCollView.render();

My thoughts now are to extend the MyItemView into MyModifiedItemView and put in this optional <br> tag, but I didn't know if there was more of a "marionette-y" way to do it. Any thoughts? Thanks!


Solution

  • Normally, you can use Marionette view events to hook an html element to that view's template. That's ok, if the element you want to attach will exists inside that view's el. Your case is a bit tricky because, you want to add a <br/> outside each item view. (If you want to know exactly why this is an issue, ask me in the comments).Instead, what we'll do is listen in the parent CollectionView to when a child is added.

    You, also want the <br> element you add to be conditional. We can take advantage of an internal property of Marionette views, view._index, along with the reference to the collection Backbone adds to each model, to test whether the current item view rendered is the last one.

    Putting it all together all you have to do is add this property to MyCollView:

    onAddChild : function (childview) {
        if (this.collection.length !== childview._index + 1)
            childview.$el.after('<br/>');
    }
    

    which checks if the child view that was just added is the last view in the collection, or not.