Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone.Marionette: Add header to collection view

Using Backbone.Marionette, I would like to render a collection of items along with a header.

I'm aware that Marionette.CollectionView does not have a template, as it only renders ItemViews.

I'm currently using Marionette.LayoutView, but have to define an extra DOM element for the 'list' region.

Is there any other way to do this? Possibly without the extra DOM element?

Maybe I could change open() for this particular region?


Current Result:

<div class='collection'>
  <h3>Featured</h3>
  <div class="list"></div>
</div>

Desired Result:

<div class='collection'>
  <h3>List Name</h3>
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
   </ul>
</div>

Render Code:

var col = new LCollection([{name: "foo"}, {name: "bar"}]); // Defined earlier, not relevant here
var list = new ListView({collection: col});
var layout = new MyLayout({model: new Backbone.Model({name: "Featured"})});

app.featured.show(layout);
layout.list.show(list);

Views:

var ListItemView = Backbone.Marionette.ItemView.extend({
  template: '#list-item',
  tagName: 'li'
});

var LessonListView = Backbone.Marionette.CollectionView.extend({
  tagName: 'ul',
  itemView: ListItemView
});

var MyLayout = Backbone.Marionette.Layout.extend({
  template: "list-layout",

  regions: {
    list: '.list'
  }
});

Templates:

<script type="text/template" id="list-item">
  <%= name %>
</script>

<script type="text/template" id="list-layout">
  <h3><%= name %></h3>
  <div class="list"></div>
</script>
like image 601
Will M Avatar asked Aug 01 '13 03:08

Will M


2 Answers

https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.compositeview.md

Applied for you :

Templates

<script id="list-item" type="text/html">
  <%= name %>
</script>

<script id="list-layout" type="text/html">
    <div class='collection'>
        <h3><%= name %></h3>
        <ul></ul>
    </div>
</script>

JS

RowView = Backbone.Marionette.ItemView.extend({
  tagName: "li",
  template: "#list-item"
});

TableView = Backbone.Marionette.CompositeView.extend({
  itemView: RowView,
  // specify a jQuery selector to put the itemView instances in to
  itemViewContainer: "ul",
  template: "#list-layout"
});
like image 78
MarkKGreenway Avatar answered Oct 07 '22 00:10

MarkKGreenway


Marionette 3 doesn't use CompositeView any more, so if we want to get something like this:

<div class='collection'>
  <h3>List Name</h3>
  <ul>
    <li>FOO - BAR</li>
    <li>FOO - BAR</li>
    <li>FOO - BAR</li>
    ...
 </ul>
</div>

We have to use CollectionView & View with regions.

1 - Templates

We are going to define two templates, a first one that is the 'parent' and another one for each 'child' that the parent has.

parentTemplate.html

<div class='collection'>
    <h3>List Name</h3>
    <ul></ul>
</div>

childTemplate.html

<p>Item <%= value%></p>

2 - Backbone Model and Collection

Lets define a default model and its collection to fill the list.

const Item = Backbone.Model.extend({});
const Items = Backbone.Collection.extend({
    model: Item
});

3 - Views

First, we have to create a View for our child representation, so:

import ItemViewTemplate from './childTemplate.html';    

const ItemChildView = Marionette.View.extend({
    template: _.template(ItemViewTemplate),
    className: 'item-child-view',
    tagName: 'li' // <-- The element where we will wrap our item template (it is not defined in the HTML file)
});

Second, we have to create a CollectionView that manages each child, so:

const ItemsCollectionView = Marionette.CollectionView.extend({
    tagName: 'ul', // <-- The element where we will wrap our collection of items (it is already in the parent HTML file)
    childView: ItemChildView,
    className: 'items-collection-view'
});

Finally, we have to create the main View, that contains the parentTemplate.html and in this one we define the region where we will load the collection of elements, so:

import ItemsViewTemplate './parentTemplate.html';    

const ItemsView = Marionette.View.extend({
    tagName: 'div',
    className: 'items-view',
    template: _.template(ItemsViewTemplate),
    regions: {
        body: {
            el: 'ul', // <-- This is the HTML tag where we want to load our CollectionView
            replaceElement: true // <-- With this option, we overwrite the HTML tag with our CollectionView tag
        }
    }
});

4- Rest of the Code

Now we create the instances needed to make this works:

const app = new Marionette.Application({
    region: '#main'
});

// Three simple Items
let item1 = new Item({value: 1});
let item2 = new Item({value: 2});
let item3 = new Item({value: 3});

// Put this Items into a Collection of Items
let items = new Items([item1, item2, item3]);

// Create the main View
let itemsView = new ItemsView();

app.showView(itemsView);

// Create the CollectionView for the Items
let itemsCollectionView = new ItemsCollectionView({
    collection: items
});

// Load the CollectionView of Items into the region that we specified in the main View
itemsView.showChildView('body', itemsCollectionView);

app.start();

5- Result

If we run this, we get:

<div class="collection">
    <h3>List Name</h3>
    <ul class="items-collection-view">
        <li class="item-child-view"><p>Item1</p></li>
        <li class="item-child-view"><p>Item2</p></li>
        <li class="item-child-view"><p>Item3</p></li>
    </ul>
</div>

Hope it helps! Reference

like image 21
David Corral Avatar answered Oct 06 '22 23:10

David Corral