JSFiddle - React, Tailwind, and code Playground
by homer2
HTML
<script src="http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-2.1.0beta.js"></script>
<hr/>
<table border='1' style="border-collapse: collapse;">
<thead>
<tr><th></th>
<th>Jan</th><th>%</th>
<th>Feb</th><th>%</th>
<th>Mar</th><th>%</th>
<th>Apr</th><th>%</th>
<th>May</th><th>%</th>
<th>Jun</th><th>%</th>
<th>Jul</th><th>%</th>
<th>Aug</th><th>%</th>
<th>Sep</th><th>%</th>
<th>Oct</th><th>%</th>
<th>Nov</th><th>%</th>
<th>Dec</th><th>%</th>
<th>Year End<br />Actuals/Forecast</th><th>%</th>
</tr>
</thead>
<tbody data-bind="foreach: resourceCategories">
<tr>
<td data-bind="text: name"></td>
<!-- ko foreach: monthAmounts -->
<td data-bind="css: { negative: amount() < 0}">
<span type="text" data-bind="text: amount"></span>
<!-- ko if: monthNumber > $root.currentMonthNumber -->
<input type="text" data-bind="value: amount, valueUpdate: 'afterkeydown'"></input>
<!-- /ko -->
</td>
<td data-bind="text: (amount()/$root.laborBasis[$index()].value()).toFixed(2) + '%'">% of Labor basis</td>
<!-- /ko -->
<td data-bind="text: totalAmount">totalExpenses</td>
<td></td>
</tr>
</tbody>
<tbody>
<tr>
<td>Month Total</td>
<!-- ko foreach: monthTotals -->
<td>
<span type="text" data-bind="text: value"></span>
</td>
<td></td>
<!-- /ko -->
<td>totalAmount</td>
<td>averageAmount</td>
</tr>
<tr>
<td>Labor Basis</td>
<!-- ko foreach: laborBasis -->
<td>
<span type="text" data-bind="text: value"></span>
</td>
<td></td>
<!-- /ko -->
...
JavaScript
function MonthAmount(id, amount, monthNumber) {
var self = this;
self.id = id;
self.amount = ko.observable(amount);
self.monthNumber = monthNumber;
}
function ResourceCategory(id, name, monthAmounts) {
var self = this;
self.id = id;
self.name = name;
self.monthAmounts = ko.utils.arrayMap(monthAmounts, function(monthAmount) {
return new MonthAmount(monthAmount.Id, monthAmount.Amount, monthAmount.MonthNumber);
});
self.totalAmount = ko.computed(function() {
var sum = 0;
for (var i = 0; i < self.monthAmounts.length; i++) {
sum += parseFloat(self.monthAmounts[i].amount());
}
return sum;
});
self.averageAmount = ko.computed(function() {
return self.totalAmount()/self.monthAmounts.length;
});
}
function OverheadViewModel(json) {
var self = this;
self.resourceCategories = ko.utils.arrayMap(json.ResourceCategories, function(resourceCategory) {
return new ResourceCategory(resourceCategory.Id, resourceCategory.Name, resourceCategory.MonthAmounts);
});
self.laborBasis = new Array();
for (var i = 0; i < 12; i++) {
self.laborBasis.push({"value": ko.observable(100000)});
}
self.monthTotals = new Array();
for (var monthNumber = 0; monthNumber < 11; monthNumber++) {
self.monthTotals.push({"value": ko.computed(function() {
var val = 0;
for (var i = 0; i < self.resourceCategories.length; i++) {
val += parseFloat(self.resourceCategories[i].monthAmounts[monthNumber].amount());
}
return val;
})});
}
self.monthTotal4 = ko.computed(function() {
var val = 0;
for (var i = 0; i < self.resourceCategories.length; i++) {
val += parseFloat(self.resourceCategories[i].monthAmounts[4].amount());
}
return val;
});
...