Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Marionette-Backbone how do I make a grid table with a dynamic row and column headers

I am trying to make a table grid with dynamic number of rows and column with headers using marionette.

I want a grid that looks like: http://jsfiddle.net/zaphod013/c3w61gf6/

So there are

columns = ['breakfast', 'lunch', 'dinner']

rows = ['carbs', 'proteins', 'fats']

and rest of the grid is checkboxes.

I have made the Views for column and row, but I am fairly lost at how to put them in the table, and then how to add the checkbox views.

Code I have is at http://jsfiddle.net/zaphod013/qkctrLxn/

html:

<div id="main-region"></div>

<script id="food-table" type="text/template">
    <thead id="column-id">
    </thead>
    <tbody id="row-id">
    </tbody>
</script>

<script id="food-col-item" type="text/template">
    <th><%= col %></th>
</script>

<script id="food-row-item" type="text/template">
    <td><%= row %></td>
</script>

script:

FoodManager = new Backbone.Marionette.Application();

FoodManager.addRegions({
    mainRegion: "#main-region",
});

FoodManager.FoodLayout = Backbone.Marionette.Layout.extend({
    template: "#food-table",

    regions: {
       colRegion:"#column-id",
       rowRegion:"#row-id"
    }
});

FoodManager.Col = Backbone.Model.extend({});

FoodManager.ColCollection = Backbone.Collection.extend({
                                    model: FoodManager.Col
                                });

FoodManager.Row = Backbone.Model.extend({});

FoodManager.RowCollection = Backbone.Collection.extend({
                                    model: FoodManager.Row
                                });

FoodManager.ColItemView = Marionette.ItemView.extend({
    template: "#food-col-item",
    tagName: "th",
});

FoodManager.ColView = Marionette.CompositeView.extend({
    template: "#food-table",
    tagName: "thead",
    itemView: FoodManager.ColItemView
});

FoodManager.RowItemView = Marionette.ItemView.extend({
    template: "#food-row-item",
    tagName: "th",
});

FoodManager.RowView = Marionette.CompositeView.extend({
    template: "#food-table",
    tagName: "table",
    itemView: FoodManager.RowItemView
});

FoodManager.on("initialize:after", function(){
    var columns = new FoodManager.ColCollection([
                    {col: 'Breakfast'},
                    {col: 'Lunch'},
                    {col: 'Dinner'}
            ]);
    var rows = new FoodManager.RowCollection([
                    {row: 'Carbs'},
                    {row: 'Protein'},
                    {row: 'Fats'}
            ]);
    var colListView = new FoodManager.ColView({
                            collection: columns
                        });
    var rowListView = new FoodManager.RowView({
                            collection: rows
                        });
    var foodLayout = new FoodManager.FoodLayout();    
    foodLayout.render();
    FoodManager.colRegion.show(colListView);
    FoodManager.rowRegion.show(rowListView);

    FoodManager.mainRegion.show(foodLayout);

});

 FoodManager.start();

I will really appreciate some pointers on how to go about this.

Thanks for reading through.

like image 574
zaphod Avatar asked Nov 20 '25 00:11

zaphod


1 Answers

There are two parts to this answer. First, I recommed you use a LayoutView with CollectionViews, since you don't need a template for the collection itself (you'll still use the ItemView templates, though). Second, you'll have to let your Row view know how many check-mark columns you'll need (this will be trivial as you'll see) and we'll have to create those columns in the Row view.

Load up your LayoutView

Your FoodLayout view and template are perfect. You laid the foundation. What you need to populate it with is two CollectionView views:

FoodManager.ColItemView = Marionette.ItemView.extend({
    template: "#food-col-item",
    tagName: "th",
});

FoodManager.ColView = Marionette.CollectionView.extend({
    itemView: FoodManager.ColItemView
});

FoodManager.RowItemView = Marionette.ItemView.extend({
    template: "#food-row-item",
    tagName: "tr",
});

FoodManager.RowView = Marionette.CollectionView.extend({
    itemView: FoodManager.RowItemView
});

Note that I changed your CompositeView to CollectionView, and changed your the tagName in the ItemView to tr for the Row view. (Note: you're going to want to remove the <th> tags in #food-col-item, Backbone will generate them for you.)

Generating dynamic columns in Row view

Now here comes the fun part. We're going to use templateHelpers to make the check-mark rows in your Row views. If you'll look at the docs, templateHelpers is a hash that let's you add data to your template before rendering. That "data", or JavaScript objects, can be functions (since function are first class objects in JavaScript). So, we're going to use templateHelpers to pass the food columns we'll need check-marks for, and to put together a function that will take as a parameter the food columns, and will return with the html for those check-mark columns.

Put this templateHelpers property in your 'FoodManager.FoodLayout view:

templateHelpers: function () {
  return {
    foods: function () {
      return this.foodColumns
    },

    addColumns: function (foodcols) {
      var html = '';
       for (food in foodcols)
         html += "<td><input type="checkbox" class=" + 
                    food + "-check"></td>";

       return html;
    }
  }
} 

And your Row template will look like:

<script id="food-row-item" type="text/template">
    <td><%= row %></td><% addColumns(foods) %>
</script>

What you need to be aware of is that you need to give the FoodManager.FoodLayout the food columns you used for ColCollection, so that you can populate this.templateHelpers.foods. There are mutliple ways to get that in there. I just used this.foodColumns as dummy placeholder.

like image 159
seebiscuit Avatar answered Nov 22 '25 13:11

seebiscuit