Javascript loop table row working with rowspan and tr - javascript

I have table that need to custom with my JS in loop.
Below is the demo. What I need the final result is like this:
Is there any trick how to achieve as my result needed?
var jsonStr = {
  "data": [
    {
      "data2": [
        {
          "partNo": "ABC",
          "plan": "120"
        },
        {
          "partNo": "DEF",
          "plan": "50"
        }
      ],
      "lineID": "1"
    },
    {
      "data2": [
        {
          "partNo": "FAB",
          "plan": "75"
        }
      ],
"lineID": "2"
    }
  ]
};
for(var i=0; i<jsonStr.data.length; i++) {
var line = "LINE " + jsonStr.data[i].lineID;
var element = `<tr><td>${line}</td></tr>`;
$(".tbl1 tbody").append(element);
for(var j=0; j<jsonStr.data[i].data2.length; j++) {
var partNo = jsonStr.data[i].data2[j].partNo;
//console.log(partNo);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="tbl1" border="1">
<thead>
<th>Line</th>
<th>Part No.</th>
</thead>
<tbody></tbody>
</table>
<p>
It should be like this:
<table border="1">
<thead>
<th>Line</th>
<th>Part No.</th>
</thead>
<tbody>
<tr>
<td rowspan="2">LINE 1</td>
<td>ABC</td><tr>
<td>DEF</td>
</tr>
<tr>
<td rowspan="1">LINE 2</td>
<td>FAB</td>
</tr>
</tbody>
</table>

This is an approach using Array.forEach over the obj.data property to feed a target table tbody using the rowspan strategy.
Each time a new entry is visited in the new array, a new row is created and is given a rowspan value equal to the number of elements in its own data2 property array (partNo).
Then for each pf those, a new row is added, starting from the second one, holding the current partNo alone.
I didn't see you were using jQuery so I went for vanilla js. Anyway this is the MDN reference to the topics faced here:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td#attr-rowspan
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
var obj = {  
"data": [
{ 
"lineID": "1",
"data2": [{"partNo": "ABC","plan": "120"},{"partNo": "DEF","plan": "50"}],
},
{      
"lineID": "2",
"data2": [{"partNo": "FAB","plan": "75"}],
}
]
};
//target tbody
const tbody = document.querySelector('#tbl1 tbody');
//for each entry in obj.data
obj.data.forEach( entry => {
//create a new currentRow
let currentRow = document.createElement('tr');
//create a cell for the current line and append it to the currentRow
const tdLine = document.createElement('td');
tdLine.textContent = `LINE ${entry.lineID}`;
if(entry.data2.length > 1)
tdLine.setAttribute('rowspan', entry.data2.length);
currentRow.append(tdLine);
//for each partNo
entry.data2.forEach( (part, i) => {
//if the index of the current partNo is > 0, commit the currentRow and make a new one
if(i > 0){
tbody.append(currentRow);
currentRow = document.createElement('tr');
}
//create the cell for the current partNo and append it to the currentRow
const tdPart = document.createElement('td');
tdPart.textContent = part.partNo;
currentRow.append(tdPart);
});
//append the currentRow to the table
tbody.append(currentRow);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="tbl1" class="tbl1" border="1">
<thead>
<th>Line</th>
<th>Part No.</th>
</thead>
<tbody></tbody>
</table>

Just set rowspan for the first cell of first group based on data2 length. Then render rest of group's rows with single cell with data2.
const jsonStr = {
"data": [
{
"data2": [
{
"partNo": "ABC",
"plan": "120"
},
{
"partNo": "DEF",
"plan": "50"
}
],
"lineID": "1"
},
{
"data2": [
{
"partNo": "FAB",
"plan": "75"
}
],
"lineID": "2"
}
]
};
const tbody = $(".tbl1").find("tbody");
for(let i=0; i<jsonStr.data.length; i++) {
const label = "LINE " + jsonStr.data[i].lineID;
let tr = document.createElement("tr");
tbody.append(tr);
let td = document.createElement("td");
td.innerHTML = label;
td.rowSpan = jsonStr.data[i].data2.length;
tr.appendChild(td);
td = document.createElement("td");
td.innerHTML = jsonStr.data[i].data2[0].partNo;
tr.appendChild(td);
for(let j=1; j<jsonStr.data[i].data2.length; j++) {
const partNo = jsonStr.data[i].data2[j].partNo;
tr = document.createElement("tr");
tbody.append(tr);
td = document.createElement("td");
td.innerHTML = partNo;
tr.appendChild(td);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="tbl1">
<tbody></tbody>
</table>

Related

create table from jsp in javascript

I have the following table with the columns shown in the code below (in jsp).
I want this same table to be done in javascript, where list in my case will be a json array of objects.
Can you kindly help me with this?
<table border="1" width="90%">
<tr>
<th>Id</th>
<th>Name</th>
<th>Password</th>
<th>Email</th>
<th>Sex</th>
<th>Country</th>
<th>Edit</th>
<th>Delete</th></tr>
<c:forEach items="${list}" var="u">
<tr><td>${u.getId()}</td>
<td>${u.getName()}</td>
<td>${u.getPassword()}</td>
<td>${u.getEmail()}</td>
<td>${u.getSex()}</td>
<td>${u.getCountry()}</td>
<td>Edit</td>
<td>Delete</td></tr>
</c:forEach>
</table>
The most simplest thing you can try is something like that (if i understood you correctly):
let table = document.getElementById("my-table");
let list = [{
"id":1,
"name":"Jhon",
"password":"doejhon#",
"email":"jhondoe#doe.com",
"sex":"male",
"country":"USA"
},
{
"id":2,
"name":"Lisa",
"password":"w87e8c8787%",
"email":"lisa#doe.com",
"sex":"female",
"country":"UK"
}];
list.forEach(item=>{
let child = document.createElement("tr");
child.innerHTML = `<td>${item.id}</td><td>${item.name}</td><td>${item.password}</td><td>${item.email}</td><td>${item.sex}</td><td>${item.country}</td><td>-</td><td>-</td>`;
table.appendChild(child);
})
<table border="1" width="90%" id="my-table">
<tr>
<th>Id</th>
<th>Name</th>
<th>Password</th>
<th>Email</th>
<th>Sex</th>
<th>Country</th>
<th>Edit</th>
<th>Delete</th></tr>
</table>
<!--
<c:forEach items="${list}" var="u">
<tr><td>${u.getId()}</td>
<td>${u.getName()}</td>
<td>${u.getPassword()}</td>
<td>${u.getEmail()}</td>
<td>${u.getSex()}</td>
<td>${u.getCountry()}</td>
<td>Edit</td>
<td>Delete</td></tr>
</c:forEach>
-->
Here is one approach, demoing with a smaller set of fields.
It is not entirely clear what the links for Edit/Delete are supposed to be. Here, we leave it as a link to a JSP.
let table = document.createElement('TABLE');
let header = document.createElement('TR');
let fields = [ 'Id', 'Name', 'Password', 'Edit' ];
let cell;
for (var i=0; i<fields.length; i++) {
cell = document.createElement('TH');
cell.innerHTML = fields[i];
header.appendChild(cell);
}
table.appendChild(header);
let data = [
{
'Id': 'someId',
'Name': 'some name',
'Password': 'some encrypted password',
'Edit': "<a href='editform.jsp?id=someId'>Edit</a>"
},
{
'Id': 'anotherId',
'Name': 'some other name',
'Password': 'some other encrypted password',
'Edit': "<a href='editform.jsp?id=anotherId'>Edit</a>"
}
];
let rowData;
let fieldName;
for (i=0 ; i<data.length ; i++) {
let row = document.createElement('TR');
rowData = data[i];
for (var j=0; j<fields.length; j++) {
fieldName = fields[j];
cell = document.createElement('TD');
cell.innerHTML = rowData[fieldName];
row.appendChild(cell);
}
table.appendChild(row);
}
let body = document.querySelector('BODY');
body.appendChild(table);

What am I doing wrong in creating this dynamically generated table?

Apologies for any simple mistakes, this is my first Stack Overflow post and I'm relatively new to coding.
I am attempting to create a website that displays a dynamically generated table using DOM elements. This table's rows and columns have been defined using DOM elements, and it should now populate itself on page load when storeItemOutput() is called from initialize(). It should be pulling the data from a loop through the previously defined and populated array storeItems, and displaying their attributes in the table id "storeItemOutput". It should also get one of five values from a dropdown box, and display items that match the selected category whenever it is changed.
However, I can't get the table itself or it's contents to actually display on the page. I'm unsure what is preventing this, and the lack of any output has left me stumped. Am I missing some code in my function? Is the table not created properly?
I've included parts of my code below, as well as expected output and actual output to try and help you understand my issue.
<select class="categoryDropDown" style="margin: 30px;">
<p>
<option selected value="All" onload="storeItemOutput();">All</option>
<option value="Tops" onchange="storeItemOutput();">Tops</option>
<option value="Bottoms" onchange="storeItemOutput();">Bottoms</option>
<option value="Shoes" onchange="storeItemOutput();">Shoes</option>
<option value="Accessories" onchange="storeItemOutput();">Accessories</option>
</p>
</select>
<table id="storeItemOutput">
<span><strong>| ID | Product Name | Price | Qty | Max | Category | Image |</strong></span>
</br>
<tbody>
<tr>
<th>b</th>
<th>b</th>
<th>b</th>
<th>b</th>
<th>b</th>
<th>b</th>
<th>b</th>
</tr>
<tr>
<td>b</td>
<td>b</td>
<td>b</td>
<td>b</td>
<td>b</td>
<td>b</td>
<td>b</td>
</tr>
</tbody>
(Output all store items via DOM table here)
</table>
This is some of my HTML code with an ID'd dummy table, and a dropdown menu class.
var storeItems = [];
function StoreItem(id, name, price, qtyOnHand, maxPerCust, category, shipping, reviews, description, image) {
this.id = id; //String
this.name = name; //String
this.price = price; //Number
this.qtyOnHand = qtyOnHand; //Number
this.maxPerCust = maxPerCust; //Number
this.category = category; //String
this.shipping = shipping; //Number
this.reviews = reviews; //Array
this.description = description; //String
this.image = image; //String
}
storeItems.push(new StoreItem("Y2k111", "Black Hoodie", 119.99, 10, 1, "Tops", 19.99, this.reviews, "100% Cotton Hoodie in Black", "/img/home_img/link"));
Some Javascript code of creating an empty array for store items, creating an object constructor for store items, and pushing a new item to the array (normally there is more than one item being pushed, I used just one here to save space).
function storeItemOutput() {
var itemTableDiv = document.getElementById("cartItemOutput");
var table = document.createElement("table");
itemTableDiv.innerHTML = "";
document.getElementsByTagName("tbody")[0].remove();
var tBody = document.createElement("tbody");
var headerRow = document.createElement("tr");
var hC1 = document.createElement("th");
var hC2 = document.createElement("th");
var hC3 = document.createElement("th");
var hC4 = document.createElement("th");
var hC5 = document.createElement("th");
var hC6 = document.createElement("th");
var hC7 = document.createElement("th");
hC1.innerHTML = "Item ID";
hC2.innerHTML = "Item Name";
hC3.innerHTML = "Item Price";
hC4.innerHTML = "Item Quantity";
hC5.innerHTML = "Max Items Per Customer";
hC6.innerHTML = "Category";
hC7.innerHTML = "Image";
headerRow.appendChild(hC1);
headerRow.appendChild(hC2);
headerRow.appendChild(hC3);
headerRow.appendChild(hC4);
headerRow.appendChild(hC5);
headerRow.appendChild(hC6);
headerRow.appendChild(hC7);
tbody.appendChild(headerRow);
for (var index = 0; index < storeItems.length; index++) {
var products = storeItems[i];
var theRow = document.createElement("tr");
var c1 = document.createElement("td");
var c2 = document.createElement("td");
var c3 = document.createElement("td");
var c4 = document.createElement("td");
var c5 = document.createElement("td");
var c6 = document.createElement("td");
var c7 = document.createElement("td");
c1.innerHTML = products.id;
c2.innerHTML = products.name;
c3.innerHTML = "$" + products.price.toFixed(2);
c4.innerHTML = products.qtyOnHand;
c5.innerHTML = products.maxPerCust;
c6.innerHTML = products.category;
c7.innerHTML = products.image;
theRow.appendChild(c1);
theRow.appendChild(c2);
theRow.appendChild(c3);
theRow.appendChild(c4);
theRow.appendChild(c5);
theRow.appendChild(c6);
theRow.appendChild(c7);
tbody.appendChild(theRow);
}
itemTableDiv.appendChild(tbody);
var selectedCategory = document.getElementByClass("categoryDropDown").value;
var filteredItems = [];
var index = 0;
while (index < storeItems.length) {
if (storeItems[index].category == selectedCategory) {
filteredItems.push(storeItems[index]);
}
index++;
}
storeItemOutput(filteredItems);
And finally, my function that is meant to create and populate the table, before displaying the items that match the selected category.
Here is an image of what the table should look like:
working table
And the lack of output for my table:
my missing table
Any help would be appreciated.
Here's a working example. A few things worthy of mention:
I've used a template element, since it makes repeatedly creating
similar content very much faster.
Floating-point math has rounding errors. For this reason, I've stored the
prices in cents rather than dollars. Perform all math on the number
of cents, then present it as dollars & cents
A NodeList is very similar to, but slightly different than an array. It does not for instance have a forEach member function. For this reason, I used Array.from in the appendRow function. (which is actually shorter by 1 line if you use the commented code instead)
"use strict";
function newEl(tag) {
return document.createElement(tag)
}
function byId(id) {
return document.getElementById(id)
}
function qs(sel, parent = document) {
return parent.querySelector(sel)
}
function qsa(sel, parent = document) {
return parent.querySelectorAll(sel)
}
window.addEventListener('load', onLoaded, false);
function onLoaded(evt) {
var tableData = [
["PID01", "Fluffy Bear", 599, 600, 20, "Toy", "bear.png"],
["PID02", "Rubber Ducky", 1599, 40, 5, "Toy", "duck.png"],
["PID03", "Cool Handbag", 599, 1, 2, "Fashion", "bag.png"],
["PID04", "Fidget Spinner", 999, 120, 10, "Toy", "spinner.png"],
["PID05", "Lame Handbag", 4599, 60, 3, "Fashion", "bag.png"],
["PID06", "UltraMega Genuine Laptop", 170599, 20, 2, "Technology", "laptop.png"],
];
populateTable(tableData);
var categoryNames = ["All", "Fashion", "Toy", "Technology"];
populateSelect(byId('catSelector'), categoryNames);
qs('select').addEventListener('change', updateFilter, false);
}
function populateSelect(selElem, data) {
selElem.innerHTML = '';
data.forEach(txt => selElem.appendChild(new Option(txt, txt)));
}
function populateTable(data) {
data.forEach(appendRow);
function appendRow(itemData, itemIndex, items) {
let newRow = byId('productRowTemplate').content.cloneNode(true);
let cells = Array.from(newRow.firstChild.cells);
cells.forEach((cell, index) => {
if (index == 2)
cell.textContent = '$' + (itemData[index] / 100).toFixed(2);
else
cell.textContent = itemData[index];
});
// cells[0].textContent = itemData[0];
// cells[1].textContent = itemData[1];
// cells[2].textContent = '$'+(itemData[2]/100).toFixed(2);
// cells[3].textContent = itemData[3];
// cells[4].textContent = itemData[4];
// cells[5].textContent = itemData[5];
byId('storeItemOutput').tBodies[0].appendChild(newRow);
}
}
function updateFilter() {
let filter = byId('catSelector').value;
let prodRows = qsa('#storeItemOutput > tbody > tr');
if (filter == 'All') {
prodRows.forEach(row => row.classList.remove('notShown'));
} else {
prodRows.forEach(
row => {
if (row.cells[5].textContent == filter)
row.classList.remove('notShown');
else
row.classList.add('notShown');
}
);
}
}
.notShown {
display: none;
}
.price,
.qty,
.max {
text-align: right;
}
<template id='productRowTemplate'><tr>
<td class='id'></td>
<td class='name'></td>
<td class='price'></td>
<td class='qty'></td>
<td class='max'></td>
<td class='cat'></td>
<td><img class='icon'/></td>
</tr></template>
<body>
Filter:
<select id='catSelector'></select>
<table id='storeItemOutput'>
<thead>
<tr>
<th>ID</th>
<th>Product</th>
<th>Price</th>
<th>Qty</th>
<th>Max</th>
<th>Category</th>
<th>Image</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</body>

I have a long json that i want to be displayed only four when the page loads and shows the rest when a user clicks on the investment link

I have a long json that i want to be displayed only four when the page loads and shows the rest when a user clicks on the investment link.
This is my investment table
<table class="table table-bordered table-striped table-vcenter js-dataTable-full-pagination table-responsive" id="investmentTable">
<thead id="tableHead">
<tr id="tableRow">
<th class="text-center" style="width: 30%;" id="serialNo">S/N</th>
<th class="d-sm-table-cell" style="width: 30%;" id="investmentNo">Investment No</th>
<th class="d-sm-table-cell" style="width: 30%;" id="amount">Amount</th>
<th class="d-sm-table-cell" style="width: 30%;" id="status">Status</th>
</tr>
</thead>
</table>
This is the Json test and code
// Call for Investment Api
function investmentData(){
var myInvestment = [
{
"investmentNo":"00032",
"amount":"70000",
"status": "Expired",
"duration": "2",
"startDate": "7-02-2020",
"yield": "2.60",
"repayAmt":"70500",
"description": "Official"
},
{
"investmentNo":"00033",
"amount":"40000",
"status": "Current",
"duration": "3",
"startDate": "4-01-2019",
"yield": "12.0",
"repayAmt":"42000",
"description": "Personal"
},
{
"investmentNo":"00034",
"amount":"5000",
"status": "Current",
"duration": "4",
"startDate": "5-04-2008",
"yield": "20.0",
"repayAmt":"6000",
"description": "School fees"
}
]
var investmentTable = document.querySelector("#investmentTable");
if(myInvestment.length>0){
var col = []; // define an empty array
for (var i = 0; i < myInvestment.length; i++) {
for (var key in myInvestment[i]) {
if (col.indexOf(key) === -1) {
col.push(key);
}
}
}
// CREATE TABLE HEAD .
var tHead = document.querySelector("#tableHead");
// CREATE ROW FOR TABLE HEAD .
var hRow = document.querySelector("#tableRow");
// ADD COLUMN HEADER TO ROW OF TABLE HEAD.
tHead.appendChild(hRow);
investmentTable.appendChild(tHead);
// CREATE TABLE BODY .
var tBody = document.createElement("tbody");
// ADD COLUMN HEADER TO ROW OF TABLE HEAD.
for (var i = 0; i < myInvestment.length; i++) {
var bRow = document.createElement("tr");
// CREATE ROW FOR EACH RECORD .
var td = document.createElement("td");
td.innerHTML = i+1;
bRow.appendChild(td);
for (var j = 0; j < 3; j++) {
var td = document.createElement("td");
if (j==0) {
td.innerHTML = ''+myInvestment[i][col[j]]+ '';
bRow.appendChild(td);
}else{
td.innerHTML = myInvestment[i][col[j]];
bRow.appendChild(td);
}if (j==2) {
td.innerHTML = '<div class="badge">'+myInvestment[i][col[j]]+ '</div>';
if (td.textContent=="Expired") {
td.innerHTML = '<div class="badge badge-success">'+myInvestment[i][col[j]]+ '</div>';
} else {
td.innerHTML = '<div class="badge badge-danger">'+myInvestment[i][col[j]]+ '</div>';
}
}
}
tBody.appendChild(bRow)
}
investmentTable.appendChild(tBody);
var link = document.getElementsByTagName('a');
for(x=0;x<link.length;x++){
link[x].onclick = function invModalView(k){
var href = this.getAttribute("href");
var modal = document.getElementById("modal-block-normal");
modal.style.display = "block";
var investNo = document.getElementById("investNo");
var investmentTableModal = document.querySelector("#investmentTableModal");
if(myInvestment.length>0){
var col = []; // define an empty array
for (var i = 0; i < myInvestment.length; i++) {
for (var key in myInvestment[i]) {
if (col.indexOf(key) === -1) {
col.push(key);
}
}
}
// CREATE TABLE BODY .
var tBody = document.createElement("tbody");
// ADD COLUMN HEADER TO ROW OF TABLE HEAD.
for (var k = 3; k < 7; k++){
var bRow = document.createElement("tr");
for (var i = 0; i < myInvestment.length; i++) {
// CREATE ROW FOR EACH RECORD .
var td = document.createElement("td");
td.innerHTML = myInvestment[i][col[k]];
bRow.appendChild(td);
}
tBody.appendChild(bRow)
}
investmentTableModal.appendChild(tBody);
}
};
}
}
}
**This is the modal table**
<table class="table table-bordered table-striped table-vcenter table-responsive" id="investmentTableModal">
<thead id="tableHeadModal">
<tr>
<th class="d-sm-table-cell" style="width: 40%;">Investment No</th>
</tr>
<tr>
<th class="d-sm-table-cell" style="width: 35%;">Duration</th>
</tr>
<tr>
<th class="d-sm-table-cell" style="width: 40%;">StartDate</th>
</tr>
<tr>
<th class="d-sm-table-cell" style="width: 40%;">Yield</th>
</tr>
<tr>
<th class="d-sm-table-cell" style="width: 40%;">RepaymentAmount</th>
</tr>
<tr>
<th class="d-sm-table-cell" style="width: 40%;">Description</th>
</tr>
</thead>
</table>
The image is where the problem lies. it displays all values at once when i only want it to display the first array from index 3-7 in a row when a user clicks on the first link.

How do I display a dynamically created html table only once?

Each time I input another football score, the league table is updated and displayed but it's appended to a list of tables. How do I display only the latest table?
Here is an extract of the html:
<div>
<table id="matches" border="1"> </table>
</div>
<div>
<table id="standings" border="1"> </table>
</div>
<input type="button" value="Update" onclick="update()" />
Here is the javascript that displays the fixtures for inputting scores:
// Display fixtures to input the scores
window.onload = function()
{
table = document.getElementById("matches");
var row;
var cell1;
var cell2;
var cell3;
for (i = 1; i < Results.length; i++)
{
row = table.insertRow(i-1); //table starts row 0 but Results row 1 so i-1 used
cell1 = row.insertCell(0);
cell2 = row.insertCell(1);
cell3 = row.insertCell(2);
cell4 = row.insertCell(3);
cell1.innerHTML = Results[i][0];
cell2.innerHTML = '<input type="number" min="0" max="99"/>'
cell3.innerHTML = '<input type="number" min="0" max="99"/>'
cell4.innerHTML = Results[i][3];
}
}
And here is the code that displays the table after the lastest scores have been inputed:
// Display League Table
standings = document.getElementById("standings");
for (i = 0; i < League.length; i++)
{
row = standings.insertRow(i);
cell1 = row.insertCell(0);
cell2 = row.insertCell(1);
cell3 = row.insertCell(2);
cell4 = row.insertCell(3);
cell5 = row.insertCell(4);
cell6 = row.insertCell(5);
cell7 = row.insertCell(6);
cell8 = row.insertCell(7);
cell1.innerHTML = League[i][0];
cell2.innerHTML = League[i][1];
cell3.innerHTML = League[i][2];
cell4.innerHTML = League[i][3];
cell5.innerHTML = League[i][4];
cell6.innerHTML = League[i][5];
cell7.innerHTML = League[i][6];
cell8.innerHTML = League[i][7];
}
After entering three scores this is what is displayed:
I've tried clearing the league array within javascript but still the same outcome. How do I only display top version of the table? Thanks
Thanks again to comments, and some further googling, the following deletes the table ahead of updating it, unless there's a better way?
for(var i = standings.rows.length - 1; i >= 0; i--)
{
standings.deleteRow(i);
}
Cheers everyone! :)
For your table update/question, focus on the updateRow function. This line does the actual update of contents of row rownum column(<td>) i
rows[rownum].getElementsByTagName('td')[i].innerHTML = coldata[i];
There is more here than just updating the table rows, for that you can review the function updateRow in my name-spaced object. updateRow calls createRow if it needs to (the row at that index does not exist), nothing fancy here, then updates the new row.
I use the array of match objects in matches I created (was not one in the question so I made assumptions) also in the namespace:
matches: [{
match: 1,
score: [{
team: "Ap",
score: 3
}, {
team: "Or",
score: 2
}]
}],
Note where I call this code to update the table for standings in the table with standings-table id. I have no idea what those are so I simply inserted some stuff in the array then update the table using
for (let i = 0; i < myLeague.standings.length; i++) {
myLeague.updateRow('standings-table', myLeague.standings[i], i);
}
Other things: I created the form simply to show how to update the table when a new match is inserted, I trigger an event and it does what it needs to update or insert a row - but really that is just to test the update as new matches are created.
Row in a table are either updated or inserted depending totally on the array of matches content
nothing handles deletions from the table or array since this was just about insert and update
if a row index for a match index does not exist, it creates a new row and updates it
var myLeague = myLeague || {
teamSelect1: "team1",
teamSelect2: "team2",
matchesPlayed: 1,
teams: [{
name: "Apples",
abbreviation: "Ap"
},
{
name: "Oranges",
abbreviation: "Or"
},
{
name: "Pears",
abbreviation: "Pe"
}
],
matches: [{
match: 1,
score: [{
team: "Ap",
score: 3
}, {
team: "Or",
score: 2
}]
}],
standings: [
["A", 2, 1, 1, 3, 2, 3, 0],
["B", 3, 1, 1, 3, 2, 3, 6]
],
cloneRow: function(tableid, objectRef) {
// find table to clone/append to
let table = document.getElementById(tableid);
// find row to clone, I use first one
let firstRow = mytable.rows[0];
// let row = document.getElementById("rowToClone");
let clone = firstRow.cloneNode(true); // copy children too
clone.id = ""; // change id or other attributes/contents
table.appendChild(clone); // add new row to end of table
},
createRow: function(tableid, colCount, rowCount = 1, defaultContent = "") {
let row = document.createElement('tr'); // create row node
for (let i = 0; i < colCount; i++) {
let newText = document.createTextNode(defaultContent);
let col = row.insertCell(i);
col.appendChild(newText);
}
let table = document.getElementById(tableid); // find table to append to
let tbody = table.getElementsByTagName('tbody')[0];
for (let r = 1; r <= rowCount; r++) {
tbody.appendChild(row); // append row to table
}
},
updateRow: function(tableid, coldata = ['$nbsp;'], rownum = 0) {
let table = document.getElementById(tableid); // find table to update to
let tbody = table.getElementsByTagName('tbody')[0];
let rows = tbody.rows; // get rows node
let maxRows = 20; //keep it from going crazy adding rows
while (rows.length < maxRows && !rows[rownum]) {
this.createRow(tableid, coldata.length, 1, "x");
}
//myLeague.updateRow(tableid,coldata, rownum);
for (let i = 0; i < coldata.length; i++) {
rows[rownum].getElementsByTagName('td')[i].innerHTML = coldata[i];
}
},
addTeam: function(team, teamid) {
var sel = document.getElementById(teamid);
var optNew = document.createElement("option");
optNew.value = team.abbreviation;
optNew.text = team.name;
sel.add(optNew, null);
},
addTeamsToSelect: function() {
myLeague.teams.forEach(function(team) {
myLeague.addTeam(team, this.teamSelect1);
myLeague.addTeam(team, this.teamSelect2);
}, this);
},
listMatches: function(event) {
// event.target is the div
let src = event.target.dataset.source;
console.log("src:", src);
document.getElementById("matchplayed").textContent = event.matches;
this[src].forEach(function(item, index, array) {
document.getElementById('matchplayed').textContent = array.length;
let rowdata = [item.score[0].team, item.score[0].score, item.score[1].team, item.score[1].score];
this.updateRow(src, rowdata, index);
}, this);
},
clickAddListener: function(event) {
// 'this' is bound to the namespace object
// console.log(event.target); // the button
// console.log(this.matchesPlayed);//namespace
if (!document.getElementById(this.teamSelect1).value || !document.getElementById(this.teamSelect2).value) {
let errorEl = document.getElementById("form1")
.getElementsByClassName("error-text")[0];
errorEl.textContent = "Both teams need to be selected.";
errorEl.style.visibility = 'visible';
errorEl.style.opacity = '1';
setTimeout(function() {
errorEl.style.WebkitTransition = 'visibility .5s, opacity .5s';
errorEl.style.opacity = '0';
errorEl.style.visibility = 'hidden';
errorEl.textContent = "";
}, 5000);
} else {
this.matchesPlayed++;
let r = {
match: this.matchesPlayed,
score: [{
team: document.getElementById(this.teamSelect1).value,
score: document.getElementById("score1").value
}, {
team: document.getElementById(this.teamSelect2).value,
score: document.getElementById("score2").value
}]
};
this.matches.push(r);
}
document.getElementById('matches').dispatchEvent(this.showmatchesevent);
},
addListeners: function() {
let scope = this;
document.getElementById(this.teamSelect1)
.addEventListener('change', function() {
let s = document.getElementById(scope.teamSelect2);
let oval = s.value;
if (this.value == oval) {
s.value = '';
}
}, this);
document.getElementById(this.teamSelect2)
.addEventListener('change', function() {
let s = document.getElementById(scope.teamSelect1);
let oval = s.value;
if (this.value == oval) {
s.value = '';
}
}, this);
document.getElementById('add-match')
// bind this namespace to the event listener function
.addEventListener('click', (this.clickAddListener).bind(this), false);
this.showmatchesevent = new CustomEvent('showmatches');
document.getElementById('matches')
.addEventListener('showmatches', this.listMatches.bind(this), false);
}
};
window.onload = function() {
myLeague.addTeamsToSelect();
myLeague.addListeners();
for (let i = 0; i < myLeague.standings.length; i++) {
myLeague.updateRow('standings-table', myLeague.standings[i], i);
}
// set table from defaults/imported list
document.getElementById('matches').dispatchEvent(myLeague.showmatchesevent);
};
/* typography */
html {
font-family: 'helvetica neue', helvetica, arial, sans-serif;
}
th {
letter-spacing: 2px;
}
td {
letter-spacing: 1px;
}
tbody td {
text-align: center;
}
.match-inputs {
border: solid 2px #DDDDDD;
padding;
1em;
margin: 1em;
}
.error-text {
height: 1em;
color: red;
}
.matches-played {
padding: 13m;
}
/* table layout */
table {
border-collapse: collapse;
border: 1px solid black;
}
.score th,
td {
padding: 0.2em;
border: solid #DDDDDD 1px;
}
.container {
padding: 1em;
}
<div class="container match-inputs">
<form id="form1">
<div>Add Matches</div>
<div class="input-group"><label>Choose L Team:</label>
<select id="team1">
<option value="">Choose</option>
</select>
</div>
<div class="input-group"><label>Choose L2 Team:</label>
<select id="team2">
<option value="">Choose</option>
</select>
</div>
<div class="input-group score-group"><label>Team1 score:</label>
<input id="score1" type="number" class="score-input" value="0" min="0" max="99" value="0" />
</div>
<div class="input-group score-group"><label>Team2 score:</label>
<input id="score2" type="number" class="score-input" value="0" min="0" max="99" value="0" />
</div>
<div class="input-group"><label>Add this match to the list.</label>
<button type="button" id="add-match">Add Match</button>
</div>
<div class="error-text"> </div>
</form>
</div>
<div class="container">
<div class="matches-played">Matches Played:<span id="matchplayed"></span></div>
<table id="matches" data-source="matches">
<thead>
<tr>
<th colspan="4">Matches</th>
</tr>
<tr>
<th>L</th>
<th>S</th>
<th>S2</th>
<th>L1</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<div class="container">
<table id="standings-table">
<thead>
<tr>
<th colspan="8">Standings</th>
</tr>
<tr>
<th>Team</th>
<th>P</th>
<th>W</th>
<th>D</th>
<th>L</th>
<th>F</th>
<th>A</th>
<th>Pts</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>

sorting the table when user click on the column

I have the html table which populated the dynamic values from json(written in the javascript code).
When user click on any column header in the table, the table should sort accordingly. Any suggestions would be helpful.
When user click on the column the table should sort ascending and then descending if user clicks for the second time on the same column.
Demo https://jsfiddle.net/o2ram4tu/
Sample code below:
function CreateTableFromJSON() {
var myBooks = [
{
"Book ID": "1",
"Book Name": "Computer Architecture",
"Category": "Computers",
"Price": "125.60"
},
{
"Book ID": "2",
"Book Name": "Asp.Net 4 Blue Book",
"Category": "Programming",
"Price": "56.00"
},
{
"Book ID": "3",
"Book Name": "Popular Science",
"Category": "Science",
"Price": "210.40"
}
]
// EXTRACT VALUE FOR HTML HEADER.
// ('Book ID', 'Book Name', 'Category' and 'Price')
var col = [];
for (var i = 0; i < myBooks.length; i++) {
for (var key in myBooks[i]) {
if (col.indexOf(key) === -1) {
col.push(key);
}
}
}
var table = document.getElementById("resulttable");
var tr = table.insertRow(1);
// ADD JSON DATA TO THE TABLE AS ROWS.
for (var i = 0; i < myBooks.length; i++) {
tr = table.insertRow(-1);
for (var j = 0; j < col.length; j++) {
var tabCell = tr.insertCell(-1);
tabCell.innerHTML = myBooks[i][col[j]];
}
}
// FINALLY ADD THE NEWLY CREATED TABLE WITH JSON DATA TO A CONTAINER.
var divContainer = document.getElementById("showData");
divContainer.innerHTML = "";
divContainer.appendChild(table);
}
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<title>Convert JSON Data to HTML Table</title>
<style>
th, td, p, input {
font:14px Verdana;
}
table, th, td
{
border: solid 1px #DDD;
border-collapse: collapse;
padding: 2px 3px;
text-align: center;
}
th {
font-weight:bold;
}
</style>
</head>
<body onload="CreateTableFromJSON()" >
<table class="fdt-datatable" id="resulttable" name="resulttable">
<tbody>
<tr>
<th name = "bookID"> Book ID</th>
<th name = "bookName"> Book Name</th>
<th name = "category"> Category</th>
<th name = "price"> Price</th>
</tr>
</tbody>
</table>
<p id="showData"></p>
</body>
</html>
I edited your code and add some new staff fort sortering
Here is jsfiddle
Snippet is below
function CreateTableFromJSON() {
var myBooks = [
{
"Book ID": "1",
"Book Name": "Computer Architecture",
"Category": "Computers",
"Price": "125.60"
},
{
"Book ID": "2",
"Book Name": "Asp.Net 4 Blue Book",
"Category": "Programming",
"Price": "56.00"
},
{
"Book ID": "3",
"Book Name": "Popular Science",
"Category": "Science",
"Price": "210.40"
}
]
// EXTRACT VALUE FOR HTML HEADER.
// ('Book ID', 'Book Name', 'Category' and 'Price')
var col = [];
for (var i = 0; i < myBooks.length; i++) {
for (var key in myBooks[i]) {
if (col.indexOf(key) === -1) {
col.push(key);
}
}
}
var table = document.getElementById("resulttable");
var tbody = document.getElementById("resulttable_body");
var tr = tbody.insertRow(0);
// ADD JSON DATA TO THE TABLE AS ROWS.
for (var i = 0; i < myBooks.length; i++) {
tr = tbody.insertRow(-1);
for (var j = 0; j < col.length; j++) {
var tabCell = tr.insertCell(-1);
tabCell.innerHTML = myBooks[i][col[j]];
}
}
// FINALLY ADD THE NEWLY CREATED TABLE WITH JSON DATA TO A CONTAINER.
var divContainer = document.getElementById("showData");
divContainer.innerHTML = "";
divContainer.appendChild(table);
}
// FOR TABLE SORT
$(document).ready(function(){
var sortOrder = 1; // flag to toggle the sorting order
function getVal(elm, colIndex){
var td = $(elm).children('td').eq(colIndex).text();
if(typeof td !== "undefined"){
var v = td.toUpperCase();
if($.isNumeric(v)){
v = parseInt(v,10);
}
return v;
}
}
$(document).on('click', '.sortable', function(){
var self = $(this);
var colIndex = self.prevAll().length;
var o = (sortOrder == 1) ? 'asc' : 'desc'; // you can use for css to show sort direction
sortOrder *= -1; // toggle the sorting order
$('.sortable').removeClass('asc').removeClass('desc');
self.addClass(o);
var tbody = self.closest("table").find("tbody");
var tr = tbody.children("tr"); //.get();
tr.sort(function(a, b) {
var A = getVal(a, colIndex);
var B = getVal(b, colIndex);
if(A < B) {
return -1*sortOrder;
}
if(A > B) {
return 1*sortOrder;
}
return 0;
});
$.each(tr, function(index, row) {
//console.dir(row)
tbody.append(row);
});
});
});
th, td, p, input {
font:14px Verdana;
}
table, th, td
{
border: solid 1px #DDD;
border-collapse: collapse;
padding: 2px 3px;
text-align: center;
}
th {
font-weight:bold;
}
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<title>Convert JSON Data to HTML Table</title>
</head>
<body onload="CreateTableFromJSON()" >
<table class="fdt-datatable" id="resulttable" name="resulttable">
<thead>
<tr>
<th name = "bookID" class="sortable"> Book ID</th>
<th name = "bookName" class="sortable"> Book Name</th>
<th name = "category" class="sortable"> Category</th>
<th name = "price" class="sortable"> Price</th>
</tr>
</thead>
<tbody id="resulttable_body">
</tbody>
</table>
<p id="showData"></p>
</body>
</html>
For your question from coment about this jsfiddle code
HTML part
You have table with everything in tbody. I separated row with th to thead and I have empty tbody. Because I need to separate header fields which is clickable, and to separate content which can be sort.
Important thing is to add class sortable on which column you want to be sortable. In this case all column is sortable except first with checkboxes
JavaScript part
I added var tbody = document.getElementById("resulttable_body"); and at the end all rows are added to our empty tbody.appendChild(row);
Mayor thing is that you created element input and you append input to table cell, which look like this image:
I've created td element and put input inside it
//Multi Stage Checkbox creation
tblCell = document.createElement('td');
var input = document.createElement("INPUT");
input.setAttribute("type", "checkbox");
input.setAttribute("name", "");
input.setAttribute("value", "");
input.setAttribute("id", 1);
tblCell.appendChild(input);
tblCell.style.textAlign = 'center';
row.appendChild(tblCell);

Categories

Resources