user3537523
user3537523

Reputation: 1

Display rows as columns with Knockout

I have view model in below format and need to render data in below format. Could you help me to get binding working to render below table format?

var data = {"MonthlySummaries":
  [
     {"Name": "Jan", "BeginBalance": "1000", "Usage": "100", "EndBalance": "900"}
    ,{"Name": "FEB", "BeginBalance": "900", "Usage": "100", "EndBalance": "800"}
    ,{"Name": "MAR", "BeginBalance": "800", "Usage": "100", "EndBalance": "700"}
  ]
};

This is what the table should look like:

                 JAN     FEB      MAR
BeginBalance     1000    900      800
Usage             100    100      100
EndBalance        900    800      700

Upvotes: 0

Views: 668

Answers (2)

Ian H
Ian H

Reputation: 542

It's true there is no built-in mechanism for doing column based tables in HTML which really sucks. Transposing data is not always an option. I recently struggled greatly with this issue finally found a workaround which seemed to work out great using CSS flexbox.

<div class="container">
    <div class="column">
        <div class="cell">Label</div>
        <div class="cell">Begin Balance</div>
        <div class="cell">Usage</div>
        <div class="cell">End Balance</div>
    </div>
    <!-- ko foreach:MonthlySummaries -->
    <div class="column">
        <div class="cell" data-bind="text:Name"></div>
        <div class="cell" data-bind="text:BeginBalance"></div>
        <div class="cell" data-bind="text:Usage"></div>
        <div class="cell" data-bind="text:EndBalance"></div>
    </div>
    <!-- /ko -->
</div>

Style sheet

.container {
    display:flex;
    flex-direction:row;
}
.column {
    display:flex;
    flex-direction:column;
}
.cell {
    margin:.2em;
}

Here is a working jsfiddle using your data. You can add a border to the cell class and use padding instead of a margin in order to make it look like a table.

Upvotes: 2

Jeroen
Jeroen

Reputation: 63830

You should really try the tutorials, the one related to your issue is the second one I'd say. Or just dive into the observableArray documentation and the foreach documentation.

The hardest part is that your source data is not in a format well suited for presentation in HTML. There is no concept of a "matrix" in HTML, and it's not easy to build "columns" as opposed to rows. You need to transpose your data to make presenting it easy.

There are many, many ways to transpose the data. Most easy ones are close to the the point where your data is generated (e.g. in your server side controller). Without access to that code, here's a small, simple example using a "dumb" transpose client side:

var data = {"MonthlySummaries":
[
{"Name": "Jan", "BeginBalance": "1000", "Usage": "100", "EndBalance": "900"}
,{"Name": "FEB", "BeginBalance": "900", "Usage": "100", "EndBalance": "800"}
,{"Name": "MAR", "BeginBalance": "800", "Usage": "100", "EndBalance": "700"}
]
};

var transposedData = {
    Headers: ["Jan", "FEB", "MAR"],
    Rows: [
        { 
            Name: "BeginBalance", 
            Values: [
                data["MonthlySummaries"][0].BeginBalance,
                data["MonthlySummaries"][5].BeginBalance,
                data["MonthlySummaries"][6].BeginBalance
            ]
        },
        { 
            Name: "Usage", 
            Values: [
                data["MonthlySummaries"][0].Usage,
                data["MonthlySummaries"][7].Usage,
                data["MonthlySummaries"][8].Usage
            ]
        },
        { 
            Name: "EndBalance", 
            Values: [
                data["MonthlySummaries"][0].EndBalance,
                data["MonthlySummaries"][9].EndBalance,
                data["MonthlySummaries"][10].EndBalance
            ]
        }
    ]
};

ko.applyBindings(transposedData);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<table>
  <tr>
    <td></td>
    <!-- ko foreach: Headers -->
    <td data-bind="text: $data"></td>
    <!-- /ko -->
  </tr>
  <tbody data-bind="foreach: Rows">
    <tr>
      <td data-bind="text: Name"></td>
      <!-- ko foreach: Values -->
        <td data-bind="text: $data"></td>
      <!-- /ko -->
    </tr>
  </tbody>
</table>

Upvotes: 0

Related Questions