Converting JSON array in HTML table using JQuery - javascript

My JSON Array containing date and key-value pairs of alphabets. I need columns as date values and rows heading as Alphabets.
{
"error":0,
"data":[
{
"date":"2017-12-01",
"A":1,
"B":2
},
{
"date":"2017-12-02",
"A":2,
"B":3
}
]
}
I want to create table as given below
Alpha 2017-12-01 2017-12-02
A 1 2
B 2 3
My HTML Code containing datatable for table formatting:
<table id="report" class="table table-striped table-bordered">
<thead>
<tr>
<th>Alpha</th>
</tr>
</thead>
<tbody></tbody>
</table>
And JQuery ajax get response that calls the API:
$.ajax({
url: 'userData/01/2018',
success: function(response) {
let reportData = response.data;
let i = 0;
let j = 1;
let k = 0;
let table = document.getElementById('report');
let tr = table.tHead.children[0];
reportData.forEach(function(data) {
let row = table.insertRow(j);
if (i == 0) {
let th = document.createElement('th');
th.innerHTML = data.date;
tr.appendChild(th);
}
if (k == 0) {
let keys = Object.keys(data);
for (let p = 1; p < keys.length; p++) {
let cell = row.insertCell(k);
cell.innerHTML = keys[p];
for (let q = 1; q < keys.length; q++) {}
}
}
});
}
});
I am able to insert headers as table columns but facing an issue in data insertion.

slight changes in your json string,
HTML:
<table id="report"></table>
JavaScript:
var jsonString = '{"error": 0,"Alpha": [{"date": "2017-12-01","A": 1,"B": 2},{"date": "2017-12-02","A": 2,"B": 3}]}';
var s = '';
$.each(JSON.parse(jsonString), function(i, j) {
if (i == 'Alpha') {
s += '<thead><th>' + i + '</th>';
$.each(j, function(k, val) {
s += '<th>' + val.date + '</th>';
});
s += '</thead>';
$('#report').html(s);
for (var l = 0; j.length; l++) {
if (l == 0) {
s = '<tbody><tr><td> ' + Object.keys(j[l])[l + 1] + ' </td>';
s += '<td> ' + j[l].A + ' </td><td>' + j[l].B + '</td></tr>';
$('#report').append(s);
} else {
s = '<tr><td>' + Object.keys(j[l])[l + 1] + '</td><td>' + j[l].A + '</td><td>' + j[l].B + '</td></tr>';
$('#report').append(s);
}
s += '</tbody>';
}
}
});
For reference - https://jsfiddle.net/zvxqf9mz/

Related

javascript function not working (TableFilter library)

I'm trying to make a table in my web app filterable. The TableFilter library seems to be really good but I'm not able to make it work (only in the web app since it works with a simple html page).
this is the code of my page:
<html>
<head>
<title>Show Elements In Table Page</title>
<script src="~/tableFilter/tablefilter.js"></script>
<script src="~/tableFilter/tablefilter_all.js"></script>
<script src="~/tableFilter/tablefilter_all_min.js"></script>
<script src="~/tableFilter/tablefilter_min.js"></script>
</head>
<body id="pageBody" onload="createTable(getLocalItem('selectedTable'), 'elementsTable');
hideElement('loading');
document.getElementById('tableName').innerHTML = getLocalItem('selectedTable');
prova();">
<h3 id="loading">loading...</h3>
<div style="margin-left: 1em; margin-top: 1em;">
<h3 id="tableName"></h3>
<table align="left" border="1" cellpadding="5" cellspacing="0" id="elementsTable">
<!--the table loads with the createTable() function-->
</table>
</div>
<script language="javascript" type="text/javascript">
setFilterGrid("elementsTable");
<!--this is not working-->
</script>
</body>
</html>
this is the createTable() js function:
function createTable(tableName, tableId) {
fetch(domain + urlParameters + tableName)
.then(r => r.text())
.then(j => JSON.parse(j))
.then(o => {
var cols = getVarNames(o);
//header
var tableHtml = "<thead><tr>";
for (var i = 0; i < cols.length; i++) {
tableHtml += "<th>" + cols[i] + "</th>";
}
tableHtml += "</tr></thead>";
//body
tableHtml += "<tbody><tr>";
for (var i = 0; i < o.length; i++) {
for (var j = 0; j < cols.length; j++) {
tableHtml += "<td>" + o[i][cols[j]] + "</td>";
}
tableHtml += "</tr>";
}
tableHtml += "</tbody>";
//insertion in document
document.getElementById(tableId).innerHTML = tableHtml;
});
}
function getVarNames(list) {
var columns = [];
for (var i = 0; i < list.length; i++) {
var row = list[i];
for (var k in row) {
if ($.inArray(k, columns) == -1) {
columns.push(k);
}
}
}
return columns;
}
the table is loaded but it is not filterable. the script in the body seems to not recognize the table. how could i solve?
i solved creating my own query methods in javascript. maybe this could be helpful for someone.
var tableObject; //variable storing the json object form the api
function createTable(tableName, tableId) {
fetch(domain + urlParameters + tableName)
.then(r => r.text())
.then(j => JSON.parse(j))
.then(o => {
tableObject = o;
//insert filtering variables
var cols = getVarNames(tableObject);
//header
var tableHtml = "<thead><tr>";
for (var i = 0; i < cols.length; i++) {
tableHtml += "<th>" + cols[i] + "</th>";
}
//insert selection and filtering tools
tableHtml += "<tr>";
for (var i = 0; i < cols.length; i++) {
tableHtml += "<td><textarea class=\"filter\" rows=\"1\" placeholder=\"input\" style=\"resize: none;\"></textarea></td>";
//add some kind of tag matching the column -> maybe a class? or an id?
}
tableHtml += "</tr>";
tableHtml += "</tr></thead>";
//body
tableHtml += "<tbody id=\"tableBody\"><tr>";
for (var i = 0; i < tableObject.length; i++) {
if (objectIncludesFilters(tableObject[i], cols, getValuesFilters())) {
for (var j = 0; j < cols.length; j++) {
tableHtml += "<td>" + tableObject[i][cols[j]] + "</td>";
}
tableHtml += "</tr>";
}
}
tableHtml += "</tbody>";
//insertion in document
document.getElementById(tableId).innerHTML = tableHtml;
});
}
function getVarNames(list) {
var columns = [];
for (var i = 0; i < list.length; i++) {
var row = list[i];
for (var k in row) {
if ($.inArray(k, columns) == -1) {
columns.push(k);
}
}
}
return columns;
}
function getValuesFilters() {
const collection = document.getElementsByClassName("filter");
var values = [];
for (var i = 0; i < collection.length; i++) {
var value = collection[i].value;
values.push(value);
if (value == null) {
values.push("");
}
}
return values;
}
function objectIncludesFilters(obj, cols, filters) {
var result = true;
for (var i = 0; i < filters.length; i++) {
if (!obj[cols[i]].toLowerCase().includes(filters[i].toLowerCase())) {
result = false;
}
}
return result;
}

how to get Different name for each td?

I need some help, what should I do so that all the rows have each one a different id for example:introdu1,introdu2,introdu3
var perrow = 1;
array.forEach((value, i) => {
myTable += `<td id="ore">${value}</td>`;
myTable += `<td id="introdu" > </td>`;
var next = i + 1;
if (next%perrow==0 && next!=array.length) { myTable += "</tr><tr>"; }
});
It is very easy you can use ${variable} like you do in ${value}
let array = ['r','4','6'];
let myTable = "";
var perrow = 1;
array.forEach((value, i) => {
var next = i + 1;
myTable += `<td id="ore${next}">${value}</td>`;
myTable += `<td id="introdu${next}" > </td>`;
if (next%perrow==0 && next!=array.length) { myTable += "</tr><tr>"; }
});
console.log(myTable);
td {
background : red;
}
Use a dynamically generated ID:
var perrow = 1;
var id = 1;
array.forEach((value, i) => {
myTable += `<td id="ore${id}">${value}</td>`;
myTable += `<td id="introdu${id++}" > </td>`;
var next = i + 1;
if (next % perrow == 0 && next != array.length) {
myTable += "</tr><tr>";
}
});

Creating M*N table and export and download excel file with java script in html page

Is there a way that the following script after creating the table (N * M) can finally receive and download Excel output from it. Of course, I mean without using Excel software DLLs.
The script for creating the table is as follows (Generates the script below the table but I do not know how to convert it to Excel.) :
var rows = prompt("How many rows for your multiplication table?");
var cols = prompt("How many columns for your multiplication table?");
if (rows == "" || rows == null)
rows = 10;
if (cols == "" || cols == null)
cols = 10;
createTable(rows, cols);
function createTable(rows, cols) {
var j = 1;
var output = "<table border='1' width='500' cellspacing='0'cellpadding='5'>";
for (i = 1; i <= rows; i++) {
output = output + "<tr>";
while (j <= cols) {
output = output + "<td>" + i * j + "</td>";
j = j + 1;
}
output = output + "</tr>";
j = 1;
}
output = output + "</table>";
document.write(output);
}
A simple solution would be just encode the table and save as excel -
var rows = prompt("How many rows for your multiplication table?");
var cols = prompt("How many columns for your multiplication table?");
if (rows == "" || rows == null)
rows = 10;
if (cols == "" || cols == null)
cols = 10;
createTable(rows, cols);
function createTable(rows, cols) {
var j = 1;
var output = "<table border='1' width='500' cellspacing='0'cellpadding='5'>";
for (i = 1; i <= rows; i++) {
output = output + "<tr>";
while (j <= cols) {
output = output + "<td>" + i * j + "</td>";
j = j + 1;
}
output = output + "</tr>";
j = 1;
}
output = output + "</table>";
document.write(output);
const html = document.getElementsByTagName('table')[0].outerHTML;
var url = 'data:application/vnd.ms-excel,' + encodeURIComponent(html);
location.href = url;
}
JSFiddle
Try using function exportToExcel below. It takes tableString string & downloads export.xls file with this table.
var rows = prompt("How many rows for your multiplication table?");
var cols = prompt("How many columns for your multiplication table?");
if (rows == "" || rows == null)
rows = 10;
if (cols == "" || cols == null)
cols = 10;
function createTable(rows, cols) {
var j = 1;
var output = "<table border='1' width='500' cellspacing='0'cellpadding='5'>";
for (i = 1; i <= rows; i++) {
output = output + "<tr>";
while (j <= cols) {
output = output + "<td>" + i * j + "</td>";
j = j + 1;
}
output = output + "</tr>";
j = 1;
}
output = output + "</table>";
return output;
}
/*
* Export table string as excel
*/
function exportToExcel(tableString){
var uri = 'data:application/vnd.ms-excel;base64,';
var template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>{table}</table></body></html>';
var base64 = function(s) {
return window.btoa(unescape(encodeURIComponent(s)))
};
var format = function(s, c) {
return s.replace(/{(\w+)}/g, function(m, p) {
return c[p];
})
};
var ctx = {
worksheet : 'Worksheet',
table : tableString
}
var link = document.createElement("a");
link.download = "export.xls";
link.href = uri + base64(format(template, ctx));
link.click();
}
// create table as a string
const tableString = createTable();
// export table string to excel (be sure that popups are allowed in your browser)
exportToExcel(tableString)

Grabbing elementID

I am creating a table with td ids as follows(id=concatenate(row,column)):
function createTable() {
document.body.innerHTML += '<table border="1" id="mytable"></table>';
for (var i = 0; i < 4; i++) {
document.getElementById("mytable").innerHTML += '<table border="1"><tr id="row' + i + '"></tr></table>';
for (var k = 0; k < 4; k++) {
document.getElementById("row" + i).innerHTML += '<td id=' + i + k + '></td>';
}
}
}
Then I want to change the background color of each cell depending on whether its value is >5 or below. This is the onclick function I call for each cell:
function clickable() {
var table = document.getElementById("mytable");
if (table != null) {
for (var i = 0; i < table.rows.length; i++) {
for (var j = 0; j < table.rows[i].cells.length; j++)
table.rows[i].cells[j].onclick = function () { colorChange(i, j); };
}
}
}
function colorChange(i, j) {
if (document.getElementById("" + i + j).innerHTML > 5) {
document.getElementById("" + i + j).style.backgroundColor = "green";
}
}
but the debugger catches a typeError for trying to access a property of null in the first line of colorChange, which means my method of getting the elementID is wrong. What's the correct way to get the element ID?
It's because you're using vars for loop variables you always have i=4 and j=4 on click. Just replace those with let:
function clickable() {
var table = document.getElementById("mytable");
if (table != null) {
for (let i = 0; i < table.rows.length; i++) {
for (let j = 0; j < table.rows[i].cells.length; j++)
table.rows[i].cells[j].onclick = function () { colorChange(i, j); };
}
}
}
You don't need any of the i and j business. Just select the cell elements directly and loop through them to add an event listener, using querySelectorAll, as per the demo below.
N.B. You mentioned that you want to "change the background color of each cell depending on whether its value is >5 or below" ...but how are you defining the "value"? It's isn't clear. In the colorChange function, you try to test the value using the cell's "innerHTML", but your cells don't have any content anyway, so it would never work.
Therefore, for the purposes of the demo, I've assumed you intended to populate the cells with the values of i and k, and then interpret those as a single number when you do the test in colorChange.
Also <table border="1"> needed to be removed. You can't have a table directly within another table. And it's not necessary, anyway.
function createTable() {
document.body.innerHTML += '<table border="1" id="mytable"></table>';
for (var i = 0; i < 4; i++) {
document.getElementById("mytable").innerHTML += '<tr id="row' + i + '"></tr></table>';
for (var k = 0; k < 4; k++) {
document.getElementById("row" + i).innerHTML += '<td id=' + i + k + '>' + i + k + '</td>';
}
}
}
function clickable() {
var cells = document.querySelectorAll("#mytable td");
cells.forEach(function(cell) {
cell.addEventListener("click", colorChange);
});
}
function colorChange() {
console.log(this.innerHTML);
if (this.innerHTML > 5) {
this.style.backgroundColor = "green";
}
}
createTable();
clickable();
See https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll for documentation.
I think you're missing an opening curly bracket on the "j" loop of clickable
for (var j = 0; j < table.rows[i].cells.length; j++)
I also changed colorChange() to work with the event target:
function createTable() {
document.body.innerHTML += '<table border="1" id="mytable"></table>';
for (var i = 0; i < 4; i++) {
document.getElementById("mytable").innerHTML += '<table border="1"><tr id="row' + i + '"></tr></table>';
for (var k = 0; k < 4; k++) {
document.getElementById("row" + i).innerHTML += "<td id=" + i + k + ">" + Math.floor(Math.random() * 10) + "</td>";
}
}
}
function clickable() {
var table = document.getElementById("mytable");
if (table != null) {
for (var i = 0; i < table.rows.length; i++) {
for (var j = 0; j < table.rows[i].cells.length; j++) {
table.rows[i].cells[j].onclick = function(event) {
colorChange(event);
};
}
}
}
}
function colorChange(event) {
const cell = event.target;
if (cell.innerHTML > 5) {
cell.style.backgroundColor = "green";
}
}
<button onclick="createTable();clickable()">run</button>

Update totals in a table

I have:
$('#createStockOrder').click(function () {
modal('create-stock-order', {}, function () {
var $modal = $(this);
var submitted = false;
var model = [];
$('.glyphicon-plus').click(function () {
var product_id = $('#productSelect option:selected').text(),
size_id = $('#sizeSelect option:selected').text(),
colour_id = $('#colourSelect option:selected').text(),
quantity = $('#quantity').val();
// Get index of the element where all the fields matches
var index = getObjectIndex(model, product_id, size_id, colour_id);
// If object found in the array
if (index !== false) {
// Update the quantity in the same element
model[index].quantity = quantity;
} else {
// Add the element in the array
model.push({
product_id: product_id,
size_id: size_id,
colour_id: colour_id,
quantity: quantity
});
}
printStock(model);
});
var form = document.getElementById('create_sale');
var $form = $(form);
$form.on('submit', function (e) {
e.preventDefault();
if (!submitted) {
submitted = true;
$('#create_sale .btn-primary').addClass('disabled');
var formData = new FormData(form);
qwest.post(form.action, formData)
.then(function (resp) {
$modal.modal('hide');
})
.catch(function (xhr, response, e) {
var html = '';
$.each(response, function (i, v) {
html += '<p>' + v + '</p>';
});
$('#create_sale .alert').html(html).removeClass('hide');
$('#create_sale .btn-primary').removeClass('disabled');
submitted = false;
});
}
})
}, {width: 1000});
});
// Currently the function is Static, but it can be changed to dynamic
// by using nested loop and a flag to store the match status
function getObjectIndex(arr, product_id, size_id, colour_id) {
// Loop over array to find the matching element/object
for (var i = 0; i < arr.length; i++) {
var obj = arr[i];
if (obj.product_id === product_id && obj.size_id === size_id && obj.colour_id === colour_id) {
// When all key-value matches return the array index
return i;
}
}
// When no match found, return false
return false;
}
function printStock(model) {
var html = '';
var total_row_quantity = 0;
var total_row_value = 0;
$.each(model, function (i1, v1) {
html += '<tr>';
$.each(v1, function (i2, v2) {
html += '<td>' + v2 + '</td>';
$('#product_totals tr').each(function(i3, v3){
var product_code = $('td', v3).eq(0).html();
if(product_code == v2) {
total_row_quantity += parseInt(model[i1].quantity);
total_row_value += parseFloat($('td', v3).eq(2).html()*model[i1].quantity);
$('td', v3).eq(1).html(total_row_quantity);
$('td', v3).eq(3).html(accounting.formatMoney(total_row_value, ''));
} else {
total_row_quantity = 0;
total_row_value = 0;
}
})
});
html += '</tr>';
});
$('#stock_order tbody').html(html);
}
The HTML is:
<tbody id="product_totals">
<tr data-id="1">
<td>JW1501</td>
<td class="code-quantity-total">0</td>
<td>79.00</td>
<td class="code-cost-total">0</td>
</tr>
<tr data-id="2">
<td>JW1502</td>
<td class="code-quantity-total">0</td>
<td>99.00</td>
<td class="code-cost-total">0</td>
</tr>
<tr data-id="3">
<td>JW1501-1</td>
<td class="code-quantity-total">0</td>
<td>20.00</td>
<td class="code-cost-total">0</td>
</tr>
<tr data-id="4">
<td>JW1502-2</td>
<td class="code-quantity-total">0</td>
<td>25.00</td>
<td class="code-cost-total">0</td>
</tr>
</tbody>
The list of rows (JW1501, JW1502) is dynamic.
The problem I am having is that if a variant of e.g. JW1502 is added, only the total quantity and value is calculated for that one. Any previous different variants of JW1502 are ignored.
How can I fix this?
Example content of var model:
[
{"product_id":"JW1501","size_id":"70A","colour_id":"小豹纹","quantity":"1"},
{"product_id":"JW1501","size_id":"75B","colour_id":"小豹纹","quantity":"2"},
{"product_id":"JW1502","size_id":"85A","colour_id":"黑色","quantity":"1"}
]
The above for JW1501 would show the incorrect quantity of 2, not 3.
...
$('#product_totals tr').each(function (i3, v3) {
console.log(v1, v2, v3)
...
Outputs:
Object {product_id: "JW1501", size_id: "70A", colour_id: "小豹纹", quantity: "2"}
"JW1501"
<tr data-id=​"1">​<td>​JW1501​</td>​<td class=​"code-quantity-total">​2​</td>​<td>​79.00​</td>​<td class=​"code-cost-total">​158.00​</td>​</tr>​
I have completely changed your printStock function to achieve your goal:
function printStock(model) {
$("#product_totals tr").each(function(){
var id = $("td:eq(0)", this).text().trim();
var price = parseFloat($("td:eq(2)", this).text());
var count = 0;
$.each(model, function(i, item){
if (item.product_id == id) count += (+item.quantity);
});
$("td:eq(1)", this).text(count);
$("td:eq(3)", this).text((count * price).toFixed(2));
});
var rows = $.map(model, function(item){
return [
"<td>" + item.product_id + "</td>",
"<td>" + item.size_id + "</td>",
"<td>" + item.colour_id + "</td>",
"<td>" + item.quantity + "</td>"
].join("");
});
var html = "<tr>" + rows.join("</tr><tr>") + "</tr>";
$('#stock_order tbody').html(html);
}
The main difference is that my code groups items in model by product_id for further counting.
Also refer my fiddle.

Categories

Resources