Populate specific html elements with javascript variable values - javascript

I have a JS-function that counts duplicate keys from array of objects and prints keys (category names) and the amount of duplicate keys.
What I want to do is loop through a set of html-elements with specific class and print the values in them.
Here is the HTML I want to achieve
<table>
<th>Category name</th>
<th>Category count</th>
<tr>
<td class="cat_name">Shoes</td>
<td class="cat_amount">2</td>
</tr>
<tr>
<td class="cat_name">Shirts</td>
<td class="cat_amount">1</td>
</tr>
<tr>
<td class="cat_name">Hats</td>
<td class="cat_amount">3</td>
</tr>
</table>
And here is what I have achieved so far with my javascript function.
<table>
<th>Category name</th>
<th>Category count</th>
<tr>
<td class="cat_name">Shoes</td>
<td class="cat_amount">2</td>
</tr>
<tr>
<td class="cat_name">Shoes</td>
<td class="cat_amount">2</td>
</tr>
<tr>
<td class="cat_name">Shoes</td>
<td class="cat_amount">2</td>
</tr>
</table>
So basically i probably should somehow loop through all the elements and all the values and individually inject the values but i don't know how.
My code:
var myObject = [
{
"product": "Tennis shoes",
"price": "10€",
"categoryname": "Shoes"
},
{
"product": "High heels",
"price": "40€",
"categoryname": "Shoes"
},
{
"product": "Basic shirt",
"price": "20€",
"categoryname": "Shirts"
},
{
"product": "Huge Cap",
"price": "15€",
"categoryname": "Hats"
},
{
"product": "Mage hat",
"price": "25€",
"categoryname": "Hats"
},
{
"product": "Wizard hat",
"price": "45€",
"categoryname": "Hats"
}
];
function countCategorynames() {
var counter = {};
for (var i = 0; i < myObject.length; i += 1) {
counter[this.myObject[i].categoryname] = (counter[this.myObject[i].categoryname] || 0) + 1;
}
for (var key in counter) {
if (counter[key] > 0) {
console.log("we have ", key, " duplicated ", counter[key], " times");
var el1 = document.getElementsByClassName('cat_name');
for (var i = 0; i < el1.length; i++) {
el1[i].innerHTML = key;
}//for
var el2 = document.getElementsByClassName('cat_amount');
for (var i = 0; i < el2.length; i++) {
el2[i].innerHTML = counter[key];
}//for
}//if
}// for
}// function
<table>
<th>Category name</th>
<th>Category count</th>
<tr>
<td class="cat_name"></td>
<td class="cat_amount"></td>
</tr>
<tr>
<td class="cat_name"></td>
<td class="cat_amount"></td>
</tr>
<tr>
<td class="cat_name"></td>
<td class="cat_amount"></td>
</tr>
</table>
<button onClick="countCategorynames()">Count</button>

You were on the right track. Here's an example of one way to loop through your values and insert them into a table.
// declaration of myObject for this example
var myObject = [{
"categoryname": "Shoes"
},
{
"categoryname": "Shoes"
},
{
"categoryname": "Shirts"
},
{
"categoryname": "Hats"
},
{
"categoryname": "Hats"
},
{
"categoryname": "Hats"
}
];
var el1 = document.getElementsByClassName('cat_name');
var el2 = document.getElementsByClassName('cat_amount');
function countCategorynames() {
var counter = {};
for (var i = 0; i < myObject.length; i++) {
counter[myObject[i].categoryname] = (counter[myObject[i].categoryname] || 0) + 1;
}
var j = 0; // variable to use as a counter for the table
for (var key in counter) {
if (counter[key] > 0) {
console.log("we have ", key, " duplicated ", counter[key], " times");
//This prints out each categoryname and the amount of duplicates
//for example
//we have Shoes duplicated 2 times
//we have Shirts duplicated 1 times etc...
el1[j].innerHTML = key;
el2[j++].innerHTML = counter[key]; // increment the counter
}
}
}
countCategorynames();
<table>
<th>Category name</th>
<th>Category count</th>
<tr>
<td class="cat_name"></td>
<td class="cat_amount"></td>
</tr>
<tr>
<td class="cat_name"></td>
<td class="cat_amount"></td>
</tr>
<tr>
<td class="cat_name"></td>
<td class="cat_amount"></td>
</tr>
</table>
From the looks of what you have in your code so far, myObject seems to be an array of objects; you may want to consider renaming it. If it isn't an array, then you'll need to loop through it using the keys rather than just the .length property.
You were declaring el1 and el2 multiple times, which isn't really wrong but doesn't need to be done. You can declare the variables one time and refer to them in each iteration, since the elements inside the node list aren't changing.
The way you had it set up, you were grabbing the last value for both the category name and the number each time, so that's the only value that was getting applied. Your code was heading in the right direction; it was just the timing that was off.

both for loops you are running to embed the html is at wrong place.. those will always run and finally updated the last value to your html.
You need to do some changes in code as follows:
function countCategorynames(myObject) {
var counter = {};
for (var i = 0; i < myObject.length; i += 1) {
counter[myObject[i].categoryname] = (counter[myObject[i].categoryname] || 0) + 1;
}
var el1 = document.getElementsByClassName('cat_name');
var el2 = document.getElementsByClassName('cat_amount');
for (var key in counter) {
if (counter[key] > 0) {
console.log("we have ", key, " duplicated ", counter[key], " times");
//This prints out each categoryname and the amount of duplicates
//for example
//we have Shoes duplicated 2 times
//we have Shirts duplicated 1 times etc...
//This is my attempt to get all elements with class
//'cat_name' and 'cat_amount'
//and populate them with values from the object
el1[i].innerHTML = key;
el2[i].innerHTML = counter[key];
}
}
}

Related

How do I insert certain values of an array as a CSS style property for a <td> in a dynamic table?

I have a script that collects data from an array and uses these to generate a dynamic table. Some of these values in the array are Font Awesome styles.
My existing script inserts all the values in the array into each table cell.
The intention is for the Font Awesome style values to be inserted as a cell style, during the rendering of the table.
In the code below, notice that the array properties for paymentStatus stores a CSS Font Awesome style value.
var array = [{
amount: 12,
payersNumber: 1245,
paymentStatus: class="fas fa-exclamation-triangle"
}];
table = document.getElementById("table");
var currentTransaction;
var keys = ["payersNumber", "amount", "paymentStatus"];
for (var i = 0; i < array.length; i++) {
console.log("Number of transactions: " + array.length);
var newRow = table.insertRow(table.length);
currentTransaction = array[i];
for (var b = 0; b < keys.length; b++) {
var cell = newRow.insertCell(b);
cell.innerText = currentTransaction[keys[b]];
}
}
How do I get the paymentStatus values to get inserted into the table as the style for each <th>Status</th> column?
Find below the HTML table that my existing code geneates:
<table id="table" border="1">
<tr>
<th>Amount</th>
<th>Number</th>
<th>Status</th>
</tr>
</table>
<tr>
<td> 12 </td>
<td> 1245 </td>
<td> class="fas fa-exclamation-triangle" </td>
</tr>
For the Font Awesome style to successfully be put in effect, it needs to be inserted into the <td> </td> as a class style.
The desired effect would, therefore, look like this:
<table id="table" border="1">
<tr>
<th>Amount</th>
<th>Number</th>
<th>Status</th>
</tr>
<tr>
<td>12</td>
<td>1245</td>
<td class="fas fa-exclamation-triangle"></td>
</tr>
</table>
Inside the nested for-loop you can make a distinction based on the current value of keys[b]. If it's paymentStatus add an <i> tag with the css for the font awesome exclamation mark and use the .innerHTML property of the cell. If it's something else just assign the appropriate text to the .innerText proeprty.
var array = [{
amount: 12,
payersNumber: 1245,
paymentStatus: "okay"
}, {
amount: 24,
payersNumber: 3345,
paymentStatus: "okay"
}, {
amount: 45,
payersNumber: 4534,
paymentStatus: "not okay"
}];
table = document.getElementById("table");
var currentTransaction;
var keys = ["payersNumber", "amount", "paymentStatus"];
for (var i = 0; i < array.length; i++) {
var newRow = table.insertRow(table.length);
currentTransaction = array[i];
for (var b = 0; b < keys.length; b++) {
var cell = newRow.insertCell(b);
if (keys[b] == "paymentStatus") {
cell.innerHTML = "<i class='fas fa-exclamation-triangle'></i>" + currentTransaction[keys[b]];
} else {
cell.innerText = currentTransaction[keys[b]];
}
}
}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.10.0/css/all.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.10.0/css/v4-shims.css">
<table id="table" border="1">
<tr>
<th>Number</th>
<th>Amount</th>
<th>Status</th>
</tr>
</table>
You can use classList.add method to add css class to HTML element as follows:
for (var b = 0; b < keys.length; b++) {
var cell = newRow.insertCell(b);
if (keys[b] == 'paymentStatus') {
let className = '';
// it is assumed that paymentStatus value format is consistent
const classNameArr = currentTransaction[keys[b]].split('=');
if (classNameArr.length === 2) {
className = classNameArr[1];
cell.classList.add(className);
}
} else {
cell.innerText = currentTransaction[keys[b]];
}
}

jQuery - Combine <TR>(s) values that are in same Section # with same Group # / remove duplicates

I have updated the code, which is currently working up to the Place for each Group #. The existing code determines a matching Section # with Group #, and combines the TR values, adding the Average(s) and dividing by the number of TR(s), and removing any duplicate(s).
I am attempting to determine a Place for each Group # within a Section #. (*example - Section 1: Group #1 - 1st / Group #2 - 3rd / Group #3 - 2nd)
$(function() {
alert('View Table Before Grouping');
sort_array();
combine_rows();
compute_average();
});
//function sort_array
function sort_array() {
var $table = $('table');
var header = $('table tr:first-child').html();
var l = [];
$table.find('tr').each( function() {
//get values from td(s) from each row
var section = $(this).find('.class_section_number').text();
var group_number = $(this).find('.group_number').text();
var average = $(this).find('td:eq(2)').text();
var place = $(this).find('td:eq(3)').text();
//add to array
l.push([section, group_number, average, place]);
//remove saved row
$(this).remove();
});
l = l.slice(1);
//sort the array by section #, then group #
l.sortBy(0, true, 1, true, 2, false);
$table.prepend(header);
//rebuild table after sort
$.each(l, function(key, value) {
$('table').append('<tr><td class="class_section_number">' + value[0] + '</td><td class="group_number">' + value[1] + '</td><td class="grade">' + value[2] + '</td><td>' + value[3] + '</td></tr>');
});
}
//function combine_rows
function combine_rows() {
$('table tr').each( function() {
//get current row data
var section = $(this).find('.class_section_number').text();
var group = $(this).find('.group_number').text();
var average = $(this).find('td:eq(2)').text();
//get next row data
var next_section = $(this).next('tr').find('.class_section_number').text();
var next_group = $(this).next('tr').find('.group_number').text();
var next_average = $(this).next('tr').find('td:eq(2)').text();
//check for section # / group # row match
if ((section === next_section) && (group === next_group)) {
//check for empty average
if (average === 'No Data') {
average = 0 + ',' + next_average;
}
else {
average = average + ',' + next_average;
}
//set combined average
$(this).next('tr').find('td:eq(2)').text(average);
//remove matching row
$(this).remove();
}
});
}
//function compute_average
function compute_average() {
$('table tr').each( function() {
//get average from row
var average = $(this).find('td:eq(2)').text();
//split average into array (*if comma separated values)
average_array = average.split(',');
var total = 0;
//total average values from array / divide by count and set
for (var i = 0; i < average_array.length; i++) {
total += (+average_array[i]);
$(this).find('td:eq(2)').text((total / average_array.length).toFixed(2));
}
});
}
//array sort function
Array.prototype.sortBy = function (propertyName, sortDirection) {
var sortArguments = arguments;
this.sort(function (objA, objB) {
var result = 0;
for (var argIndex = 0; argIndex < sortArguments.length && result === 0; argIndex += 2) {
var propertyName = sortArguments[argIndex];
result = (objA[propertyName] < objB[propertyName]) ? -1 : (objA[propertyName] > objB[propertyName]) ? 1 : 0;
result *= sortArguments[argIndex + 1] ? 1 : -1;
}
return result;
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<table>
<tbody>
<tr>
<th>Section #</th>
<th>Group #</th>
<th>Averages</th>
<th>Place</th>
</tr>
<tr>
<td class="class_section_number">1</td>
<td class="group_number">2</td>
<td class="grade">78.29</td>
<td>Test Place 1st</td>
</tr>
<tr>
<td class="class_section_number">1</td>
<td class="group_number">2</td>
<td class="grade">85.52</td>
<td>Test Place 1st</td>
</tr>
<tr>
<td class="class_section_number">1</td>
<td class="group_number">1</td>
<td class="grade">74.41</td>
<td>Test Place 2nd</td>
</tr>
<tr>
<td class="class_section_number">1</td>
<td class="group_number">2</td>
<td>No Data</td>
<td>Test Place 3rd</td>
</tr>
<tr><td class="class_section_number">2</td>
<td class="group_number">1</td>
<td class="grade">78.90</td>
<td>Test Place 2nd</td>
</tr>
</tr>
<tr><td class="class_section_number">1</td>
<td class="group_number">3</td>
<td class="grade">91.03</td>
<td>Test Place 2nd</td>
</tr>
</tr>
<tr><td class="class_section_number">2</td>
<td class="group_number">2</td>
<td class="grade">81.69</td>
<td>Test Place 2nd</td>
</tr>
<tr>
<td class="class_section_number">2</td>
<td class="group_number">2</td>
<td class="grade">81.13</td>
<td>Test Place 1st</td>
</tr>
<tr>
<td class="class_section_number">2</td>
<td class="group_number">2</td>
<td class="grade">78.13</td>
<td>Test Place 1st</td>
</tr>
</tbody>
</table>

Calculate sum of merged rows and display in third column

I am trying to calculate the monthly expenses from my table.
Want to sum up all the amount month wise and display in total like for January month total will be $180, March will be $230 and May $200. The amount should reflect in the total column. I have created this table using ng-repeat of angular framework (dynamic table)
JSFIDDLE
I have tried below code which will sum up all the individual cols having only numeric values. This code is not working for merged rows.
for (col = 1; col < ncol + 1; col++) {
console.log("column: " + col);
sum = 0;
$("tr").each(function(rowindex) {
$(this).find("td:nth-child(" + col + ")").each(function(rowindex) {
newval = $(this).find("input").val();
console.log(newval);
if (isNaN(newval)) {
$(this).html(sum);
} else {
sum += parseInt(newval);
}
});
});
}
});
Any help on this will be really helpful.
I would add a data-month attribute to the cell displaying the amount, it is not visible to users, but super helpful for you. Have a look at the solution below.
function getMonth(month) {
var monthCells = $("td[data-month='" + month + "']"); // get all TDs with a data month attribute
var sum = 0;
for(var i = 0; i < monthCells.length; i++){ // iterate over the tds
var amountCell = monthCells[i]; // get a td for given iteration
var amountCellText = $(amountCell).text(); // get the text content
sum += parseInt(amountCellText.replace(/\D/, "")); // in amoutnCellText replace anything that's not a digit into an empty string
}
return sum;
}
console.log(getMonth("march"))
table, th, td {
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<th>Month</th>
<th>Savings</th>
<th>Total</th>
</tr>
<tr>
<td rowspan="2">January</td>
<td data-month="january">$100</td>
</tr>
<tr>
<td data-month="january">$80</td>
</tr>
<tr>
<td rowspan="2">March</td>
<td data-month="march">$200</td>
</tr>
<tr>
<td data-month="march">$30</td>
</tr>
<tr>
<td>May</td>
<td data-month="may">$200</td>
</tr>
</table>
How about something like this?
vm.data = [
{
month: 'January',
savings: [
{ amount: 100 },
{ amount: 200}
]
},
{
month: 'February',
savings: [
{ amount: 300 },
{ amount: 400 }
]
}
];
In html:
<table class="table table-bordered table-condensed">
<tr>
<th>Month</th>
<th>Savings</th>
<th>Total</th>
</tr>
<tr ng-repeat="row in vm.data">
<td>{{row.month}}</td>
<td>
<table class="table table-bordered table-condensed">
<tr ng-repeat="s in row.savings">
<td>${{s.amount}}</td>
</tr>
</table>
</td>
<td>${{vm.getTotal(row.savings)}}</td>
</tr>
</table>
In JS:
vm.getTotal = getTotal;
function getTotal(savings) {
var total = 0;
angular.forEach(savings,
function (row) {
total += row.amount;
});
return total;
}
The key here is data modeling so that you have a simple function in getting total. Hope it will help.
Sample

Populate html table with multiple value ranges from an array

I'm trying to populate the table with the "cost" values from the array.
e.g. cells 1A - 1D should display the price $3.49,
2A - 6D should display $6.59, and 7A - 10D should display $1.99
It's working for the last range (cells 7A - 10D) as seen in my jsfiddle
Any help is much appreciated.
JsFiddle: https://jsfiddle.net/Fraser_M/ct9Lm9er/
JS:
$(function () {
var myArray = [{
"range": ["1A", "1D"],
"cost": 3.49,
"group": "My group 1"
}, {
"range": ["2A", "6D"],
"cost": 6.59,
"group": "My group 2"
}, {
"range": ["7A", "10D"],
"cost": 1.99,
"group": "My group 3"
}];
var rows = $('.row').length;
for (var i = 0; i < rows; i++) {
// number each row 1-10
var rowIndex = $('.row')[i].rowIndex + 1;
console.log(rowIndex);
}
for (var i = 0; i < rows; i++) {
// get range start number
var rangeBegin = (myArray[i].range[0].replace(/\D/g, ''));
// get range end number
var rangeEnd = (myArray[i].range[1].replace(/\D/g, ''));
console.log(rangeBegin, rangeEnd);
if ((rowIndex >= rangeBegin) && (rowIndex <= rangeEnd)) {
// Append values to table
$('.row' + (rangeBegin - 1)).nextUntil('.row' + (rangeEnd + 1)).children().append("<br>$" + myArray[i].cost);
}
}
});
Here's a way to do it using a collection of <td> cells and slice() method to filter the appropriate cells to populate
Basic concept is to get beginning and ending indices from the range selectors.
var $cells= $('td')
$.each(myArray, function(_,item){
// index range elements within `$cells` collection
var startIndex = $cells.index( $('#' + item.range[0]) ),
lastIndex = $cells.index( $('#' + item.range[1]) ) + 1;
// slice and populate $cells
$cells.slice(startIndex, lastIndex).append('<br>$' + item.cost);
});
DEMO
Loop through starting row to ending row and inside this loop through A to D using ASCII value like following.
var myArray = [{
"range": ["1A", "1D"],
"cost": 3.49,
"group": "My group 1"
}, {
"range": ["2A", "6D"],
"cost": 6.59,
"group": "My group 2"
}, {
"range": ["7A", "10D"],
"cost": 1.99,
"group": "My group 3"
}];
$.each(myArray, function () {
var start = this.range[0].slice(0, -1) * 1; // get starting row num
var end = this.range[1].slice(0, -1) * 1; // get ending row num
for (var i = start; i <= end; i++) { //loop through starting row to ending row
for (var j = 65; j <= 68; j++) { //loop through 'A' to 'D'
$('#' + i + String.fromCharCode(j)).append('<br/>$' + this.cost);
}
}
});
FIDDLE
$(function () {
var myArray = [{
"range": ["1A", "1D"],
"cost": 3.49,
"group": "My group 1"
}, {
"range": ["2A", "6D"],
"cost": 6.59,
"group": "My group 2"
}, {
"range": ["7A", "10D"],
"cost": 1.99,
"group": "My group 3"
}];
var rows = $('.row').length;
var rowIndex = 0;
for (var i = 0; i < rows; i++) {
// number each row 1-10
rowIndex = $('.row')[i].rowIndex + 1;
console.log(rowIndex);
}
for (var i = 0; i < rows; i++) {
// get range start row number
var rangeBegin = (myArray[i].range[0].replace(/\D/g, ''));
// get range end row number
var rangeEnd = (myArray[i].range[1].replace(/\D/g, ''));
rangeEnd = parseInt(rangeEnd) +1;
console.log(rangeBegin, rangeEnd);
if ((rowIndex >= rangeBegin) || (rowIndex <= rangeEnd)) {
$('.row' + (rangeBegin)).children().append("<br>$" + myArray[i].cost);
$('.row' + (rangeBegin)).nextUntil(".row"+rangeEnd).children().append("<br>$" + myArray[i].cost);
}
}
});
td {
border: 1px solid black;
padding: 2px 10px 2px 10px;
text-align: center;
border-radius: 2px;
}
<table>
<tr class="row row1">
<td class='m' id='1A'>1A</td>
<td class='m' id='1B'>1B</td>
<td class='m' id='1C'>1C</td>
<td class='m' id='1D'>1D</td>
</tr>
<tr class="row row2">
<td class='m' id='2A'>2A</td>
<td class='m' id='2B'>2B</td>
<td class='m' id='2C'>2C</td>
<td class='m' id='2D'>2D</td>
</tr>
<tr class="row row3">
<td class='m' id='3A'>3A</td>
<td class='m' id='3B'>3B</td>
<td class='m' id='3C'>3C</td>
<td class='m' id='3D'>3D</td>
</tr>
<tr class="row row4">
<td class='m' id='4A'>4A</td>
<td class='m' id='4B'>4B</td>
<td class='m' id='4C'>4C</td>
<td class='m' id='4D'>4D</td>
</tr>
<tr class="row row5">
<td class='m' id='5A'>5A</td>
<td class='m' id='5B'>5B</td>
<td class='m' id='5C'>5C</td>
<td class='m' id='5D'>5D</td>
</tr>
<tr class="row row6">
<td class='m' id='6A'>6A</td>
<td class='m' id='6B'>6B</td>
<td class='m' id='6C'>6C</td>
<td class='m' id='6D'>6D</td>
</tr>
<tr class="row row7">
<td class='m' id='7A'>7A</td>
<td class='m' id='7B'>7B</td>
<td class='m' id='7C'>7C</td>
<td class='m' id='7D'>7D</td>
</tr>
<tr class="row row8">
<td class='m' id='8A'>8A</td>
<td class='m' id='8B'>8B</td>
<td class='m' id='8C'>8C</td>
<td class='m' id='8D'>8D</td>
</tr>
<tr class="row row9">
<td class='m' id='9A'>9A</td>
<td class='m' id='9B'>9B</td>
<td class='m' id='9C'>9C</td>
<td class='m' id='9D'>9D</td>
</tr>
<tr class="row row10">
<td class='m' id='10A'>10A</td>
<td class='m' id='10B'>10B</td>
<td class='m' id='10C'>10C</td>
<td class='m' id='10D'>10D</td>
</tr>
</table>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-beta1/jquery.min.js"></script>
Solution with a single for loop:
$(function() {
var myArray = [{
"range": ["1A", "1D"],
"cost": 3.49,
"group": "My group 1"
}, {
"range": ["2A", "6D"],
"cost": 6.59,
"group": "My group 2"
}, {
"range": ["7A", "10D"],
"cost": 1.99,
"group": "My group 3"
}];
var rows = $('.row').length;
var rangeObj = { // set of number limits
'group1': [myArray[0].range[0][0], myArray[0].range[1][0]],
'group2': [myArray[1].range[0][0], myArray[1].range[1][0]],
'group3': [myArray[2].range[0][0], myArray[2].range[1].substr(0,2)]
};
var rowIndex = 0;
for (var i = 0; i < rows; i++) {
var currentIndex = $('.row')[i].rowIndex + 1;
if (rowIndex > currentIndex) {
continue; // bypass redundant iterations
} else {
rowIndex = currentIndex;
}
var groupIndex = 0;
if ((rowIndex >= rangeObj.group1[0]) && (rowIndex <= rangeObj.group1[1])){
groupIndex = '1';
} else if ((rowIndex >= rangeObj.group2[0]) && (rowIndex <= rangeObj.group2[1])) {
groupIndex = '2';
} else if ((rowIndex >= rangeObj.group3[0]) && (rowIndex <= rangeObj.group3[1])) {
groupIndex = '3';
}
// get range start row number
var rangeBegin = parseInt(rangeObj['group' + groupIndex][0]);
// get range end row number
var rangeEnd = parseInt(rangeObj['group' + groupIndex][1]);
//console.log(rangeBegin, rangeEnd);
var startClass = (rangeBegin - 1)? (rangeBegin - 1) : 1;
if ((rowIndex >= rangeBegin) && (rowIndex <= rangeEnd)) {
if (rowIndex === 1) $('.row' + startClass).children().append("<br>$" + myArray[parseInt(groupIndex) - 1].cost);
$('.row' + startClass).nextUntil('.row' + (rangeEnd + 1)).children().append("<br>$" + myArray[parseInt(groupIndex) - 1].cost);
rowIndex = rangeEnd + 1;
}
}
});
https://jsfiddle.net/272kk7yx/

Iterate over table cells, re-using rowspan values

I have a simple HTML table, which uses rowspans in some random columns. An example might look like
A | B |
---|---| C
D | |
---| E |---
F | | G
I'd like to iterate over the rows such that I see rows as A,B,C, D,E,C, then F,E,G.
I think I can probably cobble together something very convoluted using cell.index() to check for "missed" columns in later rows, but I'd like something a little more elegant...
without jquery:
function tableToMatrix(table) {
var M = [];
for (var i = 0; i < table.rows.length; i++) {
var tr = table.rows[i];
M[i] = [];
for (var j = 0, k = 0; j < M[0].length || k < tr.cells.length;) {
var c = (M[i-1]||[])[j];
// first check if there's a continuing cell above with rowSpan
if (c && c.parentNode.rowIndex + c.rowSpan > i) {
M[i].push(...Array.from({length: c.colSpan}, () => c))
j += c.colSpan;
} else if (tr.cells[k]) {
var td = tr.cells[k++];
M[i].push(...Array.from({length: td.colSpan}, () => td));
j += td.colSpan;
}
}
}
return M;
}
var M = tableToMatrix(document.querySelector('table'));
console.table(M.map(r => r.map(c => c.innerText)));
var pre = document.createElement('pre');
pre.innerText = M.map(row => row.map(c => c.innerText).join('\t')).join('\n');
document.body.append(pre);
td {
border: 1px solid rgba(0,0,0,.3);
}
<table>
<tr>
<td colspan=2>A</td>
<td rowspan=2>B</td>
</tr>
<tr>
<td>C</td>
<td rowspan=3>D</td>
</tr>
<tr>
<td rowspan=2>E</td>
<td rowspan=4>F</td>
</tr>
<tr></tr>
<tr>
<td rowspan=2 colspan=2>G</td>
</tr>
<tr></tr>
<tr>
<td rowspan=3 colspan=3>H</td>
</tr>
<tr></tr>
<tr></tr>
<tr>
<td colspan=3>I</td>
</tr>
</table>
Try this:
<table id="tbl">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td colspan="2" rowspan="2">A</td>
<td rowspan="2">C</td>
</tr>
<tr>
<td rowspan="2">E</td>
</tr>
<tr>
<td>F</td>
<td>G</td>
</tr>
</table>
Script:
var finalResult = '';
var totalTds = $('#tbl TR')[0].length;
var trArray = [];
var trArrayValue = [];
var trIndex = 1;
$('#tbl TR').each(function(){
var currentTr = $(this);
var tdIndex = 1;
trArray[trIndex] = [];
trArrayValue[trIndex] = [];
var tdActuallyTraversed = 0;
var colspanCount = 1;
$('#tbl TR').first().children().each(function(){
if(trIndex > 1 && trArray[trIndex - 1][tdIndex] > 1)
{
trArray[trIndex][tdIndex] = trArray[trIndex - 1][tdIndex] - 1;
trArrayValue[trIndex][tdIndex] = trArrayValue[trIndex - 1][tdIndex];
finalResult = finalResult + trArrayValue[trIndex][tdIndex];
}
else
{
if(colspanCount <= 1)
{
colspanCount = currentTr.children().eq(tdActuallyTraversed).attr('colspan') != undefined ? currentTr.children().eq(tdActuallyTraversed).attr('colspan') : 1;
}
if(colspanCount > 1 && tdIndex > 1)
{
trArray[trIndex][tdIndex] = currentTr.children().eq(tdActuallyTraversed + colspanCount).attr('rowspan') != undefined ?currentTr.children().eq(tdActuallyTraversed + colspanCount).attr('rowspan') : 1;
trArrayValue[trIndex][tdIndex] = trArrayValue[trIndex][tdIndex - 1];
colspanCount--;
}
else
{
trArray[trIndex][tdIndex] = currentTr.children().eq(tdActuallyTraversed).attr('rowspan') != undefined ?currentTr.children().eq(tdActuallyTraversed).attr('rowspan') : 1;
trArrayValue[trIndex][tdIndex] = currentTr.children().eq(tdActuallyTraversed).html();
tdActuallyTraversed++;
}
finalResult = finalResult + trArrayValue[trIndex][tdIndex];
}
tdIndex++;
});
trIndex++;
});
alert(finalResult);
Fiddle
i am not sure about the performance, but it works well.
what I understood with your question is: You want to split the merged cell with same value and then iterate the table simply by row.
I've created a JSFiddle that will split the merged cells with the same value. Then you'll have a table that can be iterated simply by rows to get the desired output that you specified.
See it running here http://jsfiddle.net/9PZQj/3/
Here's the complete code:
<table id="tbl" border = "1">
<tr>
<td>A</td>
<td>B</td>
<td rowspan="2">C</td>
</tr>
<tr>
<td>D</td>
<td rowspan="2">E</td>
</tr>
<tr>
<td>F</td>
<td>G</td>
</tr>
</table>
<br>
<div id="test"> </div>
Here's the jquery that is used to manipulate the table's data.
var tempTable = $('#tbl').clone(true);
var tableBody = $(tempTable).children();
$(tableBody).children().each(function(index , item){
var currentRow = item;
$(currentRow).children().each(function(index1, item1){
if($(item1).attr("rowspan"))
{
// copy the cell
var item2 = $(item1).clone(true);
// Remove rowspan
$(item1).removeAttr("rowspan");
$(item2).removeAttr("rowspan");
// last item's index in next row
var indexOfLastElement = $(currentRow).next().last().index();
if(indexOfLastElement <= index1)
{
$(currentRow).next().append(item2)
}
else
{
// intermediate cell insertion at right position
$(item2).insertBefore($(currentRow).next().children().eq(index1))
}
}
});
console.log(currentRow)
});
$('#test').append(tempTable);
You can use this Gist. It supports all the requirements by W3C, even "rowspan=0" (which seems to be only supported by Firefox).

Categories

Resources