Search code examples
twitter-bootstrapbackbone.jsmarionettecomposite-view

Marionette CompositeView - change in template each nth items


I'm using Marionette for a while, but I'm not sure how I can do what I want, in a simple manner.

I have a composite view, which renders something like this:

<div class="row">
  <div class="col-xs-12">
    <div id="items"></div>
  </div>
</div>

Each of my item is being rendered as a:

<div class="col-xs-3">foo</div>

The problem here is, is that every 4 items, I want to render a new row, so things are pretty and do not screw up bootstrap's grid spacing.

In sum, if I just render them as they are, this will happen:

<div class="row">
  <div class="col-xs-12">
    <div id="items">
       <div class="col-xs-3">foo</div>
       <div class="col-xs-3">foo</div>
       <div class="col-xs-3">foo</div>
       <div class="col-xs-3">foo</div>
       <div class="col-xs-3">foo</div>
       <div class="col-xs-3">foo</div>
       <div class="col-xs-3">foo</div>
       <div class="col-xs-3">foo</div>
    </div>
  </div>
</div>

As you can see, this breaks up bootstrap, because we have a lot more then 12 grid space in those item divs.

What I want is:

<div class="row">
  <div class="col-xs-12">
    <div id="items">
       <div class="col-xs-3">foo</div>
       <div class="col-xs-3">foo</div>
       <div class="col-xs-3">foo</div>
       <div class="col-xs-3">foo</div>
    </div>
  </div>
</div>
<div class="row">
  <div class="col-xs-12">
    <div id="items">
       <div class="col-xs-3">foo</div>
       <div class="col-xs-3">foo</div>
       <div class="col-xs-3">foo</div>
       <div class="col-xs-3">foo</div>
    </div>
  </div>
</div>

What is an wasy way to achieve that effect? I should have a view for rows, and view for a collection of rows and a view for each item? That just seems too much trouble.


Solution

  • You can exploit Collection/CompositeView's childViewOptions which accepts a function. From the CompositeView you can pass the template you need. So for example:

    childViewOptions: function () {
       var template = defaultTemplate;
       if (++this.childCount % 4 == 0) 
          // 3 children have been rendered, this one is the 4th
          template = fourthTemplate;
       return {
          template: template
       } 
    }
    

    where this.childCount is a property of your CompositeView, and should be initialized somewhere.

    initialize: function () {
       this.childCount = 0;
    }
    

    If you're loath to pollute your view with extra props, you can count the number of children with Marionette's hard dep Babysitter, which manages a Collection/CompositeView's children:

    childViewOptions: function () {
       var template = defaultTemplate;
       if ((this.children.length + 1) % 4 == 0) 
          // 3 children have been rendered, this one is the 4th
          template = fourthTemplate;
       return {
          template: template
       } 
    }