0

I'm having some problems rendering headers in a composite or collection view. I tried both, but this simply won't render.

Let me show you a little bit of my code:

// composite view
define(function(require) {

    var BusinessTableTemplate = require("text!templates/BusinessTableTemplate.html");
    var BusinessRowView = require("views/BusinessRowView");
    var Marionette = require("marionette");

    return BusinessTableView = Marionette.CompositeView.extend({

        tagName: "table",
        className: "table table-hover",
        template: BusinessTableTemplate,
        itemView: BusinessRowView,
        appendHtml: function(collectionView, itemView){
            collectionView.$("tbody").append(itemView.el);
        }

    });

});

// BusinessTableTemplate
<script type="text/template">

    <thead>
        <tr>
            <th>Name</th>
            <th>Address</th>
            <th>Building</th>
            <th>Phone</th>
            <th>Website</th>
            <th>Categories</th>
        </tr>
    </thead>
    <tbody></tbody>

</script>

// itemview
define(function(require) {

    var BusinessRowTemplate = require("text!templates/BusinessRowTemplate.html");
    var Marionette = require("marionette");

    return BusinessRowView = Marionette.ItemView.extend({

        template: BusinessRowTemplate,
        tagName: "tr"

    });

});

// BusinessRowTemplate
<script type="text/template">

    <td>
        <%= name %>
    </td>
    <td>
        <% if (address) { %>
            <%= address %>
        <% } else { %>
            NA
        <% } %>
    </td>
    <td>
        <% if (building) { %>
            <%= building %>
        <% } else { %>
            NA
        <% } %>
    </td>
    <td>
    <td>
        <% _.each(phones, function(phone) { %>
            <span class="label label-default label-info"><%= phone %></span>
        <% }); %>
    </td>
    <td>
        <% if (website) { %>
            <%= website %>
        <% } else { %>
            NA
        <% } %>
    </td>
    <td>
        <% _.each(tags, function(category) { %>
            <span class="label label-default label-info"><%= category %></span>
        <% }); %>
    </td>
    <td>
        Ações
    </td>
</script>


// signal or event where I render the view
vent.on("search:seeAll", function(){
  if (self.results) {
    var businessDirectoryView = new BusinessDirectoryView();
    self.layout.modals.show(businessDirectoryView);
    var resultCollection = new Businesses(self.results, {renderInMap: false});
    var businessTableView = new BusinessTableView({
      collection: resultCollection
    });
    $("#businesses-container").html(businessTableView.render().$el);
  }
});

I followed a tutorial somewhere, but they did not specified headers for the table.

A little help here to render this?

Thanks!

George Silva
  • 3,454
  • 10
  • 39
  • 64

3 Answers3

2

What is the Marionette JS version you are using?

Here is a fiddle using the version 2.4.1 (latest available) and it is working:

https://jsfiddle.net/aokrhw1w/2/

There are some changes in the composite view with previous versions, the 'itemView' was changed to 'childView'.

var BusinessTableView = Marionette.CompositeView.extend({
   tagName: "table",
   className: "table table-hover",
   template: '#BusinessTableTpl',
   childView: BusinessRowView,
   childViewContainer: "tbody",
   appendHtml: function (collectionView, itemView) {
                console.log('append');
                 this.$("tbody").append(itemView.el);
   }
});

Hope this solves your problem.

Gabo
  • 206
  • 2
  • 4
2

CollectionView renders one child view per model in a collection. It doesn't give you any way to add extra HTML like a header.

CompositeView renders collection items too, but you can also add extra HTML. Your example uses CompositeView, so you have made the right choice.

Because you can have custom HTML around the rendered collection, you need to tell Marionette where to render the collection item views. The childViewContainer property does that:

Marionette.CompositeView.extend({
    tagName: "table",
    className: "table table-hover",
    template: BusinessTableTemplate,
    itemView: BusinessRowView,
    childViewContainer: 'tbody'
});

You don't need to use attachHtml for simple cases like this - it's for edge cases where you need to change Marionette's default behaviour.

See the CompositeView docs for more detail.

joews
  • 29,767
  • 10
  • 79
  • 91
0

Marionette 3 deprecated the CompositeView class. Instead, a region can now overwrite its el with the rendered contents of the inner View with the new replaceElement option.

See this example to render a table:

var RowView = Marionette.View.extend({
  tagName: 'tr',
  template: '#row-template'
});

var TableBody = Marionette.CollectionView.extend({
  tagName: 'tbody',
  childView: RowView
});

var TableView = Marionette.View.extend({
  tagName: 'table',
  className: 'table table-hover',
  template: '#table',

  regions: {
    body: {
      el: 'tbody',
      replaceElement: true
    }
  },

  onRender: function() {
    this.showChildView('body', new TableBody({
      collection: this.collection
    }));
  }
});

var list = new Backbone.Collection([
  {id: 1, text: 'My text'},
  {id: 2, text: 'Another Item'}
]);

var myTable = new TableView({
  collection: list
});

myTable.render();

Note to overzealous moderators: I gave the same answer here. Both questions are not duplicates but do refer to the same deprecated class. It makes no sense to spend time to "tailor the answer to both questions"; it's just a waste of time since the only important part is: "This class is deprecated, use that one instead. Here's an example and link to the doc".

Community
  • 1
  • 1
bernie
  • 9,820
  • 5
  • 62
  • 92