Please take a look at this fiddle.
How can I slice an array into several small arrays
var data =
[ { number: '1' },
{ number: '2' },
{ number: '3' },
{ number: '4' },
{ number: '5' },
{ number: '6' },
{ number: '7' },
{ number: '8' },
{ number: '9' },
{ number: '10'}
];
and build a table for each of them?
Example:
<table>
<thead>
<tr>
<th>Number</th><th>Number</th><th>Number</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td><td>2</td><td>3</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>Number</th><th>Number</th><th>Number</th>
</tr>
</thead>
<tbody>
<tr>
<td>4</td><td>5</td><td>6</td>
</tr>
</tbody>
</table>
........
The following code isn't working. The output is kind of a mess. As you can see in the fiddle, I can't access the key(number), and there are empty <table></table> tags in between the tables. Can anyone show me how to slice the array properly.
Code:
var data = [ { number: '1' },
{ number: '2' },
{ number: '3' },
{ number: '4' },
{ number: '5' },
{ number: '6' },
{ number: '7' },
{ number: '8' },
{ number: '9' },
{ number: '10'}
];
var chunks = [];
var item_html ="";
for (var i=0; i<data.length; ) {
chunks.push(data.slice(i, i+=3));
}
for (var i=0; i<chunks.length; i++) {
item_html += "<table><thead><tr>";
(i, chunks[i].map(function(key,v){
item_html += "<th>"+key+"</th>";
}));
item_html += "</tr></thead><tbody><tr>";
(i, chunks[i].map(function(v){
item_html += "<td>"+v.number+"</td>";
}));
item_html += "</tr></tbody><table>";
}
$('#area').append(item_html)
The incorrect headings are because you have the arguments to the iteration function in the wrong order in the first .map() call. The first argument is the value, the second argument is the key. It should be:
chunks[i].map(function (v, key) {
The empty tables are because of a typo. This line:
item_html += "</tr></tbody><table>";
should be:
item_html += "</tr></tbody></table>";
You were missing the / in </table>.
The corrected loop is:
for (var i = 0; i < chunks.length; i++) {
item_html += "<table><thead><tr>";
chunks[i].map(function (v, key) {
item_html += "<th>" + key + "</th>";
});
item_html += "</tr></thead><tbody><tr>";
chunks[i].map(function (v) {
item_html += "<td>" + v.number + "</td>";
});
item_html += "</tr></tbody></table>";
}
There was no point to the extra (i, ...) that you had around each call to .map(), so I removed it.
Updated fiddle
Related
Given a Javscript Object:
var obj = {
"results": [{
"B": "Row 1 Col 2"
}, {
"A": "Row 1 Col 1"
"B": "Row 2 Col 2"
}, {
"C": "Row 1 Coll 3"
}
}]
I wish to convert it to a table that looks like the following.
<table border="1">
<thead>
<tr>
<th id="A">A</th>
<th id="B">B</th>
<th id="C">C</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row 1 Col 1</td>
<td>Row 1 Col 2</td>
<td>Row 1 Col 3</td>
</tr>
<tr>
<td></td>
<td>Row 2 Col 2</td>
<td></td>
</tr>
</tbody>
</table>
Which looks like:
Demo Table Data
More precisely, I'm looking for a way to somehow insert the value of a property directly below it.
javascript:
var cols = obj.results.reduce(function(arr, currObj) {
return arr.concat(Object.keys(currObj).filter(function(key) {
return arr.indexOf(key) == -1
}));
}, []).sort();
// create header from sorted column keys
var header = '<tr><th>' + cols.join('</th><th>') + '</th></tr>';
var rows = obj.results.map(function(item) {
// loop over column keys checking matches to item keys
return '<tr>' +
cols.map(function(key) {
return '<td>' + (item.hasOwnProperty(key) ? item[key] : '') + '</td>';
}).join('') + '</tr>';
}).join('');
var table = '<table border="1">' + header + rows + '</table>';
Might not be the most elegant way but works
var cols = obj.results.reduce(function(arr, currObj) {
return arr.concat(Object.keys(currObj).filter(function(key) {
return arr.indexOf(key) == -1
}));
}, []).sort();
// create header from sorted column keys
var header = '\n<thead>\n\t<tr>\n\t\t<th>' + cols.join('</th>\n\t\t<th>') + '</th>\n\t</tr>\n</thead>';
var j = {}
obj.results.map(function(item) {
// loop over column keys checking matches to item keys
cols.map(function(key) {
if(j[key] == undefined)
{
j[key] = []
}
if (item.hasOwnProperty(key))
{
j[key].push(item[key]);
}
})
});
var rows = []
var index = 0
for(let k in j)
{
rows.push([])
for(let e in j[k])
{
rows[index].push(j[k][e])
}
index += 1
}
function transposeArray(array, arrayLength){
var newArray = [];
for(var i = 0; i < array.length; i++){
newArray.push([]);
};
for(var i = 0; i < array.length; i++){
for(var j = 0; j < arrayLength; j++){
newArray[j].push(array[i][j]);
};
};
return newArray;
}
rows = transposeArray(rows, 3)
var rowsStr = "";
for(let k in rows)
{
rowsStr += '\n\t<tr>';
for(let e in rows[k])
{
if(rows[k][e] != undefined)
{
rowsStr += '\n\t\t<td>' + rows[k][e]+ '\t\t</td>'
}
else
{
rowsStr += "\n\t\t<td></td>"
}
}
rowsStr += '\n\t</tr>';
}
var table = '<table border="1">' + header + "\n<tbody>" + rowsStr + "\n</tbody>" + '\n</table>';
I have data like this one but find hard to loop both objects and get data into one table where th to be company and td to be their drivers
{…}
driver: Array(18) [ {…}, {…}, {…}, … ]
company: "TEST"
{…}
driver: Array(10) [ {…}, {…} ]
company: "TEST 1"
i tried like this one but is do not work properly
$.each(response.allDrivers, function(key, value){
var thead = '';
thead += '<th>'+value.company+'</th>';
$('#table-allDrivers thead tr').append(thead);
$.each(value.driver, function(id,name){
var tbody = '';
tbody = '<tr> <td>'+name.driver+'<td></tr>';
$('#table-allDrivers tbody').append(tbody);
})
});
result im getting is like this one
<thead>
<tr>
<th>TEST</th>
<th>TEST 1</th>
</tr>
</thead>
<tbody>
<tr>
<td>Driver 1</td>
<td></td>
</tr>
<tr>
<td>Driver 2</td>
<td></td>
</tr>
<tr>
<td>Driver 3</td>
<td></td>
</tr>
<tr>
<td>Driver 4</td>
<td></td>
</tr>
</tbody>
Suppose you have 2 driver (driver1 and driver2) but maybe more. Find the one with more elements and iterate from that (I assumed driver1 has more elements);
var markup = "";
for( let i = 0 ; i < driver1.length; i++)
{
if (i < driver2.length)
{
markup += '<tr><td>'+driver1[i].+'</td><td>'+driver2[i]+'</td><tr>';
}
else
{
markup += '<tr><td>'+driver1[i].+'</td><td></td><tr>';
}
}
$('#table-allDrivers tbody').append(markup);
I think this would show the correct result even if this is not the best way but i tried with as much information i got.
It's a little different from how you have it there, but you can try something like this—run the snippet to see the result:
var arr = [
{
driver: ['item1', 'item2', 'item3'],
company: "Company1"
},
{
driver: ['item1', 'item2'],
company: "Company2"
}
]
var thead = document.querySelector('table thead tr')
var tbody = document.querySelector('table tbody')
arr.forEach(function(item) {
thead.innerHTML += '<th>' + item.company + '</th>';
item.driver.forEach(function(driverItem) {
tbody.innerHTML += '<tr></tr>';
})
tbody.querySelectorAll('tr').forEach(function(tr, i) {
tr.innerHTML += item.driver[i] ? '<td>' + item.driver[i] + '</td>' : '<td></td>' //catering for colspan layout
tr.innerHTML === '<td></td>' ? tr.remove() : '' //removing empty <tr> elements
})
})
<table>
<thead>
<tr></tr>
</thead>
<tbody></tbody>
</table>
The right way to use HTML Tables with multiple values for each cell is to use rowspan or colspan attribute, which in your case each company has multiple drivers. To achieve that:
Javascript:
// Your data
const allDrivers = [
{
drivers: ['driverComapnyA-1', 'driverComapnyA-2', 'driverComapnyA-3'],
company: 'Comapny A',
},
{
drivers: [
'driverComapanyB-1',
'driverComapanyB-2',
'driverComapanyB-3',
'driverComapanyB-4',
],
company: 'Comapny B',
},
];
allDrivers.forEach((item, index) => {
if (index == 0) {
// Make sure to setup tbody markup once
$('#table-allDrivers').append('<tbody></tbody>');
}
const tableBody = $('#table-allDrivers').find('tbody');
tableBody.append(
'<tr data-index="' +
index +
'"><th rowspan="' +
item.drivers.length +
'">' +
item.company +
'</th></tr>'
);
item.drivers.forEach((driver, i) => {
if (i == 0) {
// if its the first item in drivers array then add it as a child in <tr>
tableBody
.find('[data-index="' + index + '"')
.append('<td>' + driver + '</td>');
} else {
// otherwise just append it to <tbody>
tableBody.append('<tr><td>' + driver + '</td></tr>')
}
});
});
Markup:
<table id="table-allDrivers"></table>
And here's a working fiddle: https://jsfiddle.net/khzway7u/
I use an array of object to display data on a dynamic table I create with javascript
inside the table, there are 2 button delete and edit
when I press the delete I delete the data from the array but for some reason, the data still remains in the table ? can someone give me a clue why?
workers = [{
name: 'Roni',
phone: '0545931252',
nickname: 'RoniBoy',
mail: 'Roni#gmail.com',
},
{
name: 'Lior',
phone: '0545996452',
nickname: 'LiorBoy',
mail: 'Lior#gmail.com',
},
{
name: 'Arman',
phone: '0545886452',
nickname: 'ArmanBoy',
mail: 'Arman#gmail.com',
}
];
function deleteFromList(id) {
workers.splice(id, 1);
console.log(workers);
}
const toAppend = document.getElementById('appendBox');
let markup = '';
for (let x = 0; x < workers.length; x++) {
markup += `<tr>
<td >` + workers[x].name + `</td>
<td>` + workers[x].nickname + `</td>
<td>` + workers[x].phone + `</td>
<td>` + workers[x].mail + `</td>
<td><button onClick="deleteFromList(this.id)" id="` + x + `" class="btn btn-danger">Remove</button> <button class="btn btn-success">Edit</button></td>
</tr>`
}
toAppend.innerHTML = markup;
<table id="appendBox"></table>
You have rerender html every time you update you array
workers = [
{
name: 'Roni',
phone: '0545931252',
nickname: 'RoniBoy',
mail: 'Roni#gmail.com',
},
{
name: 'Lior',
phone: '0545996452',
nickname: 'LiorBoy',
mail: 'Lior#gmail.com',
},
{
name: 'Arman',
phone: '0545886452',
nickname: 'ArmanBoy',
mail: 'Arman#gmail.com',
}
];
function deleteFromList(id){
workers.splice(id,1);
console.log(workers);
renderMarkup();
}
function renderMarkup() {
const toAppend = document.getElementById('appendBox');
let markup = '';
for(let x = 0; x < workers.length; x++){
markup += `
<tr>
<td >`+workers[x].name+`</td>
<td>`+workers[x].nickname+`</td>
<td>`+workers[x].phone+`</td>
<td>`+workers[x].mail+`</td>
<td><button onClick="deleteFromList(this.id)" id="`+x+`" class="btn btn-danger">Remove</button> <button class="btn btn-success">Edit</button></td>
</tr>`
}
toAppend.innerHTML = markup;
}
renderMarkup();
<table id="appendBox"></table>
If you want to remove stuff from your table then you might want to add some sequential IDs to each row so that you can directly delete one. You could also do something like this just grabbing one in the spot it's in and delete it that way. Are you looking to delete rows or are you just trying to delete a column in a row?
var tblBody = document.getElementById("tblBody"); //referencing a <tbody> tag's id
var row = document.getElementsByTagName("tr"); //get every tr element
tblBody.deleteRow(row[i].rowIndex);
Hw to download arr content into the table cells from left to right and from up to down? What is wrong with my code? How to solve the problem? Thanks in advance.
<button onclick="myFunction()></button>
<table id="myTable" border='1px'>
<tr>
<th>N</th>
<th>Name</th>
<th>Surname</th>
<th>tel.</th>
<th>email</th>
</tr>
</table>
var arr=[[1,2,3,4,'a'],[5,6,7,8,'b'],[9,10,11,12,'c']];
function myFunction() {
createTable();
}
function createTable(){
var i,j;
var table = document.getElementById("myTable");
for( i=0; i<arr.length; i++ ) {
var row = table.insertRow(1);
for( j=0,k=0; j<5, k<arr[i].length;j++, k++ ) {
var cell = row.insertCell(0);
cell.innerHTML = arr[i][k];
}
}
}
Well i am not sure about your data structure but if you get your data in the following form.
[ { N: 1, Name: 2, Surname: 3, Tel: 4, email: 'a' },
{ N: 5, Name: 6, Surname: 7, Tel: 8, email: 'b' },
{ N: 9, Name: 10, Surname: 11, Tel: 12, email: 'c' } ]
You can use the following tableMaker function. It will take the properties as headers (if second argument is provided as true) and values as corresponding cells to generate an HTML text. So here it goes as follows;
var tableMaker = (o,h) => {var keys = o.length && Object.keys(o[0]),
rowMaker = (a,t) => a.reduce((p,c,i,a) => p + (i === a.length-1 ? "<" + t + ">" + c + "</" + t + "></tr>"
: "<" + t + ">" + c + "</" + t + ">"),"<tr>"),
rows = o.reduce((r,c) => r + rowMaker(keys.reduce((v,k) => v.concat(c[k]),[]),"td"),h ? rowMaker(keys,"th") : []);
return rows.length ? "<table>" + rows + "</table>" : "";
},
arr = [[1,2,3,4,'a'],[5,6,7,8,'b'],[9,10,11,12,'c']],
tableObj = arr.map(e => ({N: e[0], Name: e[1], Surname : e[2], Tel: e[3], email: e[4]})),
tableHTML = tableMaker(tableObj,true);
document.write(tableHTML);
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.