HTML Table - Nested Table Row using Knockout - json

I have a JSON object where EntityCode, EntityName, TagName, and TaskName (from TagList) are to be table column headers.
StatusFlagName in TaskRecordList is then to be in a nested row under it's related TaskName. The StatusFlagName values should be directly below the TaskName.
How do I get this working? The StatusFlagName will not display.
var ViewModel = function() {
this.taskRecords = ko.observableArray([
{
EntityCode: "name",
EntityName: "name desc23",
TagName: "L1",
TaskList: [
{
TaskName: "TaskABC",
TaskRecordList: [
{
StatusFlagName: "OK"
},
{
StatusFlagName: "TEST"
}
]
},
{
TaskName: "TaskDEF",
TaskRecordList: [
{
StatusFlagName: "Error"
}
]
}
]
}
]);
};
ko.applyBindings(new ViewModel());
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table class="table table-bordered">
<tbody data-bind="foreach: taskRecords">
<tr>
<td data-bind="text: EntityCode"></td>
<td data-bind="text: EntityName"></td>
<td data-bind="text: TagName"></td>
<td></td>
<!--ko foreach: TaskList-->
<td data-bind="text: TaskName">
<table>
<tbody>
<!--ko foreach: TaskRecordList-->
<tr>
<td data-bind="text: StatusFlagName"></td>
</tr>
<!--/ko-->
</tbody>
</table>
</td>
<!--/ko-->
</tr>
</tbody>
</table>

When you use <td data-bind="text: TaskName"> knockout will replace whatever you have inside this tag with the value of TaskName as a text that's why your last nested table is being replaced with TaskName value.
You can add a div or span for TaskName something like below :
<table class="table table-bordered">
<tbody data-bind="foreach: taskRecords">
<tr>
<td data-bind="text: EntityCode"></td>
<td data-bind="text: EntityName"></td>
<td data-bind="text: TagName"></td>
<td></td>
<!--ko foreach: TaskList-->
<td>
<div data-bind="text: TaskName"></div>
<table>
<tbody>
<!--ko foreach: TaskRecordList-->
<tr>
<td data-bind="text: StatusFlagName"></td>
</tr>
<!--/ko-->
</tbody>
</table>
</td>
<!--/ko-->
</tr>
</tbody>
</table>

Related

Reset count for each table

I have multiple tables in my html. The tables have the columns with class "valuation" and valuation_all".
If one of the two cells in "valuation" contains FAIL, than the cell with "valuation_all" should change the text from "status" to "FAIL". Otherwise it should show PASS.
This works for one table, but I don't know how to get this for each table. I tried it with jQuery .each(".taglist") but its not working. I think I have to reset the variable count. For each table the variable should be resetted to zero and than start counting. Now the it keeps counting and does not change the status cell properly.
One of the tables: (other tables are identical just other ID)
<p>
<table id="results1" class="taglist">
<th>Name</th><th>result</th>
<tr>
<td class="valuation">FAIL</td><td class="valuation_all" rowspan=2>status</td>
</tr>
<tr>
<td class="valuation">PASS</td>
</tr>
</table>
</p>
jQuery:
$(document).ready(function() {
var count= 0;
$('table.taglist').each(
function() {
var count= $(".valuation:contains('FAIL')").length
if(count> 0) {
$(".taglist td:contains('status')").html("FAIL");
}else{
$(".taglist td:contains('status')").html("PASS");
}
});
});
Every help is appreciated!
You can use this to solve it.
$(document).ready(function() {
var count = 0;
$('table.taglist').each(
function() {
var count = $(".valuation:contains('FAIL')",this).length
$("td:contains('status')", this).html(count > 0 ? "FAIL" : "PASS");
});
});
The main problem is that your selectors is not referring to the table your are "inside". By doing $(".valuation:contains('FAIL')",this) you tell the selector (".valuation:contains('FAIL')") to search for this inside your table
Demo
$(document).ready(function() {
var count = 0;
$('table.taglist').each(
function() {
var count = $(".valuation:contains('FAIL')",this).length
$("td:contains('status')", this).html(count > 0 ? "FAIL" : "PASS");
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="results1" class="taglist">
<th>Name</th>
<th>result</th>
<tr>
<td class="valuation">FAIL</td>
<td class="valuation_all" rowspan=2>status</td>
</tr>
<tr>
<td class="valuation">PASS</td>
</tr>
</table>
<table id="results2" class="taglist">
<th>Name</th>
<th>result</th>
<tr>
<td class="valuation">PASS</td>
<td class="valuation_all" rowspan=2>status</td>
</tr>
<tr>
<td class="valuation">PASS</td>
</tr>
</table>
$(document).ready(function() {
$('table.taglist').each(function() {
let count= $(this).find(".valuation:contains('FAIL')").length;
$(this).find("td:contains('status')").html(count> 0 ? "FAIL" : "PASS");
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="results1" class="taglist">
<th>Name</th><th>result</th>
<tr>
<td class="valuation">FAIL</td><td class="valuation_all" rowspan=2>status</td>
</tr>
<tr>
<td class="valuation">PASS</td>
</tr>
</table>
<table id="results2" class="taglist">
<th>Name</th><th>result</th>
<tr>
<td class="valuation">PASS</td><td class="valuation_all" rowspan=2>status</td>
</tr>
<tr>
<td class="valuation">PASS</td>
</tr>
</table>
<table id="results3" class="taglist">
<th>Name</th><th>result</th>
<tr>
<td class="valuation">FAIL</td><td class="valuation_all" rowspan=2>status</td>
</tr>
<tr>
<td class="valuation">FAIL</td>
</tr>
</table>

DataTables - how to get the percentage of a column in html table

I am having a difficult time in calculating in getting the percentage for a column in my html table for datatables.
In the table above, I have figured out how to get the sum of each column, but for "Column D" totals, I need to get the percentage which will be "(total of column B / total of column C) * 100. Also column F will be (total of column E / total of column A) instead of the sum which is shows now.
The total for column D is blank because the javascript code that I used, could not sum up column D because I am using a percent sign. So with my current code, I want to sum for column A,B,C,E,G and the percent for column D, and column F would be column E divide by column A.
How can I go about to calculate these totals using Datatables and javascript? Any help will be appreciated. Thank you.
$(document).ready(function() {
// DataTable initialisation
$('table.off-table1').DataTable({
"searching": false,
"info": false,
"paging": false,
"autoWidth": true,
"footerCallback": function ( row, data, start, end, display ) {
var api = this.api();
nb_cols = api.columns().nodes().length;
var j = 1;
while(j < nb_cols){
var pageTotal = api
.column( j, { page: 'current'} )
.data()
.reduce( function (a, b) {
return Number(a) + Number(b);
}, 0 );
// Update footer
$( api.column( j ).footer() ).html(pageTotal);
j++;
}
}
});
});
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/dt/jszip-2.5.0/dt-1.10.21/b-1.6.2/b-colvis-1.6.2/b-html5-1.6.2/b-print-1.6.2/cr-1.5.2/fc-3.3.1/kt-2.5.2/r-2.2.5/rg-1.1.2/rr-1.2.7/sp-1.1.1/sl-1.3.1/datatables.min.css"/>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/pdfmake.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/vfs_fonts.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/v/dt/jszip-2.5.0/dt-1.10.21/b-1.6.2/b-colvis-1.6.2/b-html5-1.6.2/b-print-1.6.2/cr-1.5.2/fc-3.3.1/kt-2.5.2/r-2.2.5/rg-1.1.2/rr-1.2.7/sp-1.1.1/sl-1.3.1/datatables.min.js"></script>
<style>
</style>
</head>
<table id="def-table1" class="def-table1" cellspacing="0" width="100%">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">A</th>
<th scope="col">B</th>
<th scope="col">C</th>
<th scope="col">D%</th>
<th scope="col">E</th>
<th scope="col">F</th>
<th scope="col">G</th>
</tr>
</thead>
<tfoot>
<tr>
<td>Totals</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tfoot>
<tbody>
<tr>
<td>1</td>
<td class="minutes">41</td>
<td class="minutes">14</td>
<td class="minutes">33</td>
<td class="minutes">42.4 %</td>
<td class="minutes">42</td>
<td class="minutes">1.02</td>
<td class="minutes">8</td>
</tr>
<tr>
<td>2</td>
<td class="minutes">8</td>
<td class="minutes">2</td>
<td class="minutes">6</td>
<td class="minutes">33.3 %</td>
<td class="minutes">5</td>
<td class="minutes">0.63</td>
<td class="minutes">1</td>
</tr>
<tr>
<td>3</td>
<td class="minutes">29</td>
<td class="minutes">11</td>
<td class="minutes">25</td>
<td class="minutes">44.0 %</td>
<td class="minutes">33</td>
<td class="minutes">1.14</td>
<td class="minutes">5</td>
</tr>
<tr>
<td>4</td>
<td class="minutes">7</td>
<td class="minutes">1</td>
<td class="minutes">5</td>
<td class="minutes">20.0 %</td>
<td class="minutes">5</td>
<td class="minutes">0.71</td>
<td class="minutes">1</td>
</tr>
</tbody>
</table>
I simplified this down by not using this.api() and only using the arguments passed to the callback and some basic array methods. Should be easier to work with now
function tfootTotals(tfRow, data, start, end, display) {
// display is array of data indices that are included in this view
const pageData = data.filter((arr, i) => display.includes(i));
// create array of column totals
const totals = Array.from(pageData[0]).fill(0);
pageData.forEach(arr => arr.forEach((e, i) => totals[i] += (+e) || 0));
// calculate the special ones
totals[4] = (100 * totals[2] / totals[3]).toFixed(1) + '%';
totals[6] = totals[5] / totals[1];
// set the tfoot cell text. slice ignores first one
// so indexing is one less than totals array
$(tfRow.cells).slice(1).text(i => totals[i+1])
// console.log(totals)
}
// DataTable initialisation
$('#def-table1').DataTable({
"searching": false,
"info": false,
"paging": false,
"autoWidth": true,
"footerCallback": tfootTotals
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.24/css/jquery.dataTables.css">
<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.24/js/jquery.dataTables.js"></script>
<table id="def-table1" class="def-table1" cellspacing="0" width="100%">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">A</th>
<th scope="col">B</th>
<th scope="col">C</th>
<th scope="col" class="col-d">D%</th>
<th scope="col">E</th>
<th scope="col" class="col-f">F</th>
<th scope="col">G</th>
</tr>
</thead>
<tfoot>
<tr>
<td>Totals</td>
<td></td>
<td></td>
<td></td>
<td>ff</td>
<td></td>
<td></td>
<td></td>
</tr>
</tfoot>
<tbody>
<tr>
<td>1</td>
<td class="minutes">41</td>
<td class="minutes">14</td>
<td class="minutes">33</td>
<td class="minutes">42.4 %</td>
<td class="minutes">42</td>
<td class="minutes">1.02</td>
<td class="minutes">8</td>
</tr>
<tr>
<td>2</td>
<td class="minutes">8</td>
<td class="minutes">2</td>
<td class="minutes">6</td>
<td class="minutes">33.3 %</td>
<td class="minutes">5</td>
<td class="minutes">0.63</td>
<td class="minutes">1</td>
</tr>
<tr>
<td>3</td>
<td class="minutes">29</td>
<td class="minutes">11</td>
<td class="minutes">25</td>
<td class="minutes">44.0 %</td>
<td class="minutes">33</td>
<td class="minutes">1.14</td>
<td class="minutes">5</td>
</tr>
<tr>
<td>4</td>
<td class="minutes">7</td>
<td class="minutes">1</td>
<td class="minutes">5</td>
<td class="minutes">20.0 %</td>
<td class="minutes">5</td>
<td class="minutes">0.71</td>
<td class="minutes">1</td>
</tr>
</tbody>
</table>

Table row was not showing

I am using knockout Js. I want to show the table row with table header when I click another table row in the table. I used this code below. Can anyone help me out?
var ViewModel = function() {
var self = this;
this.client_details = [{
name: 'Jack',
email: 'jack#gmail.io',
phone: '256987',
address: 'US',
dob: '24/01/1975',
taxid: '125'
}, {
name: 'Hari',
email: 'hari#yahoo.com',
phone: '247896',
address: 'chennai',
dob: '02/01/1975',
taxid: '255'
}];
this.datas = [{
name: 'John',
email: 'john#gmail.com',
phone: '58963287'
}, {
name: 'JohnBert',
email: 'bert#gmail.com',
phone: '589625887'
}];
self.seletedRow = ko.observable();
self.goToFolder = function(folder) {
self.seletedRow(folder);
};
};
ko.applyBindings(new ViewModel(self.datas));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table width='100%'>
<thead>
<tr>
<th width='25%'>Client Name</th>
<th width='25%'>Email</th>
<th class='Phone' width='15%'>Phone</th>
<th class='Address' width='10%'>Address</th>
<th class='dob' width='15%'>DOB</th>
<th class='tax' width='15%'>Tax ID</th>
</tr>
</thead>
<tbody data-bind="foreach: client_details">
<tr class="table_row">
<td data-bind="text: name,click: $root.goToFolder"></td>
<td data-bind="text: email"></td>
<td data-bind="text: phone"></td>
<td data-bind="text: address"></td>
<td data-bind="text: dob"></td>
<td data-bind="text: taxid"></td>
</tr>
</tbody>
</table>
<table data-bind="with: seletedRow">
<thead>
<tr>
<th width='25%'>User Name</th>
<th width='25%'>Email</th>
<th class='Phone' width='15%'>Phone</th>
</tr>
</thead>
<tbody data-bind="foreach: datas">
<tr>
<td data-bind="text: name"></td>
<td data-bind="text: email"></td>
<td data-bind="text: phone"></td>
</tr>
</tbody>
</table>
Can anyone help me to get the table row data using knockout?
The with binding creates a new binding context. Your second <table> therefore looks for the name, email and phone properties inside the currently selected client.
If you just want to show/hide the second table based on if there's a selection, you can use the if binding.
If you want to perform any filters/logic on data based on the row that's selected, you can use a computed.
Note that I've also moved your click binding to the <tr>, so you can click anywhere in the row.
var ViewModel = function() {
var self = this;
this.client_details = [{
name: 'Jack',
email: 'jack#gmail.io',
phone: '256987',
address: 'US',
dob: '24/01/1975',
taxid: '125'
}, {
name: 'Hari',
email: 'hari#yahoo.com',
phone: '247896',
address: 'chennai',
dob: '02/01/1975',
taxid: '255'
}];
this.datas = [{
name: 'John',
email: 'john#gmail.com',
phone: '58963287'
}, {
name: 'JohnBert',
email: 'bert#gmail.com',
phone: '589625887'
}];
self.selectedRow = ko.observable();
self.goToFolder = function(folder) {
self.selectedRow(folder);
};
};
ko.applyBindings(new ViewModel(self.datas));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table width='100%'>
<thead>
<tr>
<th width='25%'>Client Name</th>
<th width='25%'>Email</th>
<th class='Phone' width='15%'>Phone</th>
<th class='Address' width='10%'>Address</th>
<th class='dob' width='15%'>DOB</th>
<th class='tax' width='15%'>Tax ID</th>
</tr>
</thead>
<tbody data-bind="foreach: client_details">
<tr class="table_row" data-bind="click: $root.goToFolder">
<td data-bind="text: name"></td>
<td data-bind="text: email"></td>
<td data-bind="text: phone"></td>
<td data-bind="text: address"></td>
<td data-bind="text: dob"></td>
<td data-bind="text: taxid"></td>
</tr>
</tbody>
</table>
<table data-bind="if: selectedRow">
<thead>
<tr>
<th width='25%'>User Name</th>
<th width='25%'>Email</th>
<th class='Phone' width='15%'>Phone</th>
</tr>
</thead>
<tbody data-bind="foreach: datas">
<tr>
<td data-bind="text: name"></td>
<td data-bind="text: email"></td>
<td data-bind="text: phone"></td>
</tr>
</tbody>
</table>

Binding knockout foreach with a table row

I have the below table structure
<table style="width: 100%;">
<tr>
<td><b>Fund Value:</b></td>
<td data-bind="text: ItemDetails().FundValue"></td>
<td><b>Fund Code:</b></td>
<td data-bind="text: ItemDetails().FundCode"></td>
<td><b>Fund Desc:</b></td>
<td data-bind="text: ItemDetails().FundDesc"></td>
</tr>
<tr data-bind="foreach: ItemDetails().PriceRebates">
<td><b>Rebate Value:</b></td>
<td data-bind="text: RebateValue"></td>
<td><b>Rebate Code:</b></td>
<td data-bind="text: RebateCode"></td>
<td><b>Rebate Desc:</b></td>
<td data-bind="text: RebateDesc"></td>
</tr>
</table>
It's bound to the knockout viewmodel. The issue I am having is that the tr is bound to the foreach loop and so it is creating multiple td for the ItemDetails().PriceRebates knockout data which I do not want. I want multiple tr to be created for the ItemDetails().PriceRebates data. Can someone please tell me how I can achieve that.
Thanks
You can use foreach without a container element:
<!-- ko foreach: ItemDetails().PriceRebates -->
<tr>
<td><b>Rebate Value:</b></td>
<td data-bind="text: RebateValue"></td>
<td><b>Rebate Code:</b></td>
<td data-bind="text: RebateCode"></td>
<td><b>Rebate Desc:</b></td>
<td data-bind="text: RebateDesc"></td>
</tr>
<!-- /ko -->

Knockout: Can't push to observableArray

I've recently started using KnockOut, so I'm very new to this.
I have completed every tutorial on their site, yet can't get this specific thing to work.
I have to arrays, on the left being all the items, on the right being the items you've selected.
Once you click on the item (left table), it should .push to the right table
ViewModel:
var orderedItemsTable = $("form.orderedDataWithoutBatch")
var viewModel = {
//right side
orderedItems: ko.observableArray(),
//Left side
items: ko.observableArray(),
sortColumn: ko.observable(),
total: ko.observable(),
}
request.done(function (data) {
item.addItem = function () {
alert("item clicked, materiaal id: " + this.MateriaalId);//works
alert(this.MateriaalDescription);//works
viewModel.orderedItems.push(this);//doesn't 'work'
}
viewModel.items.push(item);//unrelated to this context
}
I'm assuming it's either in this code here, or I'm not showing it correctly in my html (because I'm not getting any console errors)
HTML (right side)
<form id="OrderedItemsWithoutBatch" class="orderedDataWithoutBatch">
<table class="orderFormArticlesTable" style="width: 47%;float: right; font-size: 9pt;">
<thead>
<tr>
<th>SKU</th>
<th>Product</th>
<th style="width: 15%">Qty</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: orderedItems">
<tr>
<td data-bind="text: MateriaalSku"> </td>
<td data-bind="text: MateriaalDescription"> </td>
<td data-bind="text: MateriaalId"><!-- Quantity--> </td>
<!--<td><input class="orderedQty" style="max-width: 15%" value="1" />[pieces]</td>-->
<td>Remove</td>
</tr>
</tbody>
</table>
I'm not sure I've understood you right, but I'd solve your task this way:
var orderedItemsTable = $("form.orderedDataWithoutBatch")
var viewModel = {
//right side
orderedItems: ko.observableArray(),
//Left side
items: ko.observableArray(),
sortColumn: ko.observable(),
total: ko.observable(),
}
function proscessRequest(item) {
item.addItem = function () {
//alert("item clicked, materiaal id: " + this.MateriaalId);//works
//alert(item.MateriaalDescription);//works
viewModel.orderedItems.push(this);//doesn't 'work'
}
viewModel.items.push(item);//unrelated to this context
}
ko.applyBindings(viewModel);
proscessRequest({MateriaalSku: "M1", MateriaalDescription: "D1", MateriaalId: "1"});
proscessRequest({MateriaalSku: "M2", MateriaalDescription: "D2", MateriaalId: "2"});
proscessRequest({MateriaalSku: "M3", MateriaalDescription: "D3", MateriaalId: "3"});
proscessRequest({MateriaalSku: "M4", MateriaalDescription: "D4", MateriaalId: "4"});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<form id="OrderedItemsWithoutBatch" class="orderedDataWithoutBatch">
<div>Alavilable items:</div>
<div>
<table class="orderFormArticlesTable">
<thead>
<tr>
<th>SKU</th>
<th>Product</th>
<th style="width: 15%">Qty</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td data-bind="text: MateriaalSku"> </td>
<td data-bind="text: MateriaalDescription"> </td>
<td data-bind="text: MateriaalId"><!-- Quantity--> </td>
<td><div data-bind="click: addItem">Add</div></td>
</tr>
</tbody>
</table>
</div>
<div style="margin-top: 30px;">
<div>Ordered items:</div>
<table class="orderFormArticlesTable">
<thead>
<tr>
<th>SKU</th>
<th>Product</th>
<th style="width: 15%">Qty</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: orderedItems">
<tr>
<td data-bind="text: MateriaalSku"> </td>
<td data-bind="text: MateriaalDescription"> </td>
<td data-bind="text: MateriaalId"><!-- Quantity--> </td>
<td><div data-bind="click: function() { $parent.orderedItems.remove($data); }">Remove</div></td>
</tr>
</tbody>
</table>
</div>
</form>
Note
I've mocked request with "proscessRequest" function called after bindings have been applied.