Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML5

Knockout Data-binding to Table with rowspan

4.67/5 (2 votes)
15 Jun 2014CPOL1 min read 35.7K   320  
Knockout Data-binding to Table with rowspan

Introduction

Using foreach data binding in knockout, we can easily bind data to a table. But the trike part comes when we need to use rowspan in table. An example could be as simple as below or could be even more complex one, when we are using rowspans to make data more presentable to the user.

Image 1

Background

To accomplish our goal, we are going to use:

  1. Regular foreach data binding
  2. Container less data binding to bind additional data
  3. attr data binding to specify the rowspan

Using the Code

For a quick preview, checkout http://jsfiddle.net/y8Gzt/.

Let’s specify some models which we are going to use in the model binding.

C++
/*Models*/
function Subject(name, mark) {
    this.name = name;
    this.mark = parseFloat(mark).toFixed(2);       
}

function Student(name, regNo, subjects) {
    this.name = name;
    this.regNo = regNo;
    this.subjects = subjects;
    this.totalMark = function() {
        var total = parseFloat(0);
        $.each(subjects, function(i) {
            total += parseFloat(subjects[i].mark);
        });
        return parseFloat(total).toFixed(2);
    };
    this.average = function() {
        var avg = this.totalMark() / parseFloat(subjects.length);
        return parseFloat(avg).toFixed(2);
    };
    this.rowSpan = subjects.length + 1;             // + 1 is important
}

Here is our view model where self.init() is populating the binding data.

C++
/*View Model*/
function ViewModel() {
    var self = this;
    self.students = ko.observableArray([]);

    self.init = function () {
        var subjects = [
            new Subject('Math', 50),
            new Subject('Physics', 50),
            new Subject('Chemistry', 50)
        ];
        var students = [
            new Student('Alan', 'Std-01', subjects),
            new Student('Scott', 'Std-01', subjects),
            new Student('John', 'Std-01', subjects)
        ];
        self.students(students);
    };
}

Finally, we are going to apply binding for the view model:

C++
/*binding view model*/
$(document).ready(function() {
    var vm = new ViewModel();
    vm.init();            //populates the binding data
    ko.applyBindings(vm);
});

Now let’s hook this view model to HTML table.

  1. <tbody data-bind="foreach: students"> - is just the regular binding
  2. <!-- ko foreach: subjects --> <!-- /ko --> - is the important container less binding for row murching
  3. attr: { rowspan: rowSpan } - is the rowspan binding to use rowspan in the table
C++
<table>
    <thead>
        <tr>
            <th>Student Name</th>
            <th>Student Reg No.</th>
            <th>Subject Name</th>
            <th>Obtained Marks</th>
            <th>Total Marks</th>
            <th>Average Marks</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: students">
        <tr>
            <td data-bind="text: name, attr: { rowspan: rowSpan }"></td>
            <td data-bind="text: regNo, attr: { rowspan: rowSpan }"></td>
            <!--important to user class hidden to hide the cell-->
            <td class="hidden"></td>         
            <td class="hidden"></td>
            <td data-bind="text: totalMark(), attr: { rowspan: rowSpan }"></td>
            <td data-bind="text: average(), attr: { rowspan: rowSpan }"></td>
        </tr>

        <!--knockout Containerless Binding-->
        <!-- ko foreach: subjects -->               
        <tr>
            <!--important to user class hiddenTop to hide top border-->
            <td class="hiddenTop" data-bind="text: name"></td>
            <td class="hiddenTop" data-bind="text: mark"></td>
        </tr>
        <!-- /ko -->
    </tbody>
</table>

Now in the header section, let’s specify some styles so that our table may have a fresh and clean look. Here are some styles that are really important to use:

  1. td.hidden - hides unnecessary cells
  2. td.hiddenTop - hides unnecessary top border from cells
HTML
<style>
    table {
        border: 1px solid black;
        border-collapse: collapse;
        width: 700px;
    }
    thead {
        font-size: 15px;
        font-weight: bold
    }
    tbody {
        font-size: 15px;
        font-weight: normal
    }
    td, th {
        border: 1px solid black;
        text-align: center;
        padding: 10px;
    }
    td.hidden {
        border-width: 0px;
        padding: 0px;
    }
    td.hiddenTop {
        border-top-width: 0px;
    }
</style>

Find the VS 2010 solution in the attachment.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)