I'm trying to have an html table where the first column is sticky. I followed other advice on using position: sticky. I'm also using some javascript because I'm building the table dynamically depending on the data passed to the DOM. The following code works as expected:
html
<table class="table table-hover">
<thead>
<tr>
<th scope="col" class="filled">Person</th>
<th scope="col"># Items 1</th>
<th scope="col"># Items 2</th>
<th scope="col"># Items 3</th>
<th scope="col"># Items 4</th>
<th scope="col"># Items 5</th>
<th scope="col"># Items 6</th>
<th scope="col"># Items 7</th>
<th scope="col"># Items 8</th>
<th scope="col"># Items 9</th>
<th scope="col"># Items 10</th>
<th scope="col"># Items 11</th>
<th scope="col"># Items 12</th>
<th scope="col"># Items 13</th>
<th scope="col"># Items 14</th>
<th scope="col"># Items 15</th>
<th scope="col"># Items 16</th>
</tr>
</thead>
<tbody>
<tr>
<td id="row_1" class="filled">Jim</td>
<td id="row_1_col_1">64</td>
<td id="row_1_col_2">12</td>
<td id="row_1_col_3">33</td>
<td id="row_1_col_4">32</td>
<td id="row_1_col_5">59</td>
<td id="row_1_col_6">64</td>
<td id="row_1_col_7">12</td>
<td id="row_1_col_8">33</td>
<td id="row_1_col_9">32</td>
<td id="row_1_col_10">59</td>
</tr>
<tr>
<td id="row_2" class="filled">Sam</td>
<td id="row_2_col_1">83</td>
<td id="row_2_col_2">12</td>
<td id="row_2_col_3">32</td>
<td id="row_2_col_4">27</td>
<td id="row_2_col_5">9</td>
<td id="row_2_col_6">83</td>
<td id="row_2_col_7">12</td>
<td id="row_2_col_8">32</td>
<td id="row_2_col_9">27</td>
<td id="row_2_col_10">9</td>
</tr>
<tr>
<td id="row_3" class="filled">Ted</td>
<td id="row_3_col_1">11</td>
<td id="row_3_col_2">39</td>
<td id="row_3_col_3">77</td>
<td id="row_3_col_4">68</td>
<td id="row_3_col_5">93</td>
<td id="row_3_col_6">11</td>
<td id="row_3_col_7">39</td>
<td id="row_3_col_8">77</td>
<td id="row_3_col_9">68</td>
<td id="row_3_col_10">93</td>
</tr>
</tbody>
</table>
javascript
var rowName = [];
var cellName = [];
var numberPeople = 3;
var numberItems = 10;
var score = 5
for(var n=0; n < (numberPeople); n++) {
for(var i = 0; i < numberItems; i++) {
// +1 b/c starts at 0
rowName[n] = "row_" + (n + 1) + "_col_" + (i+1);
cellName[n] = document.createElement('td');
document.getElementById(rowName[n]).appendChild(cellName[n]);
switch (score) {
case 5:
document.getElementById(rowName[n]).style.backgroundColor = "#fff";
document.getElementById(rowName[n]).style.opacity += "0.5";
break;
}
}
}
css
.table th:first-child,
.table td:first-child {
position: sticky;
left: 0;
z-index: 6;
}
.table .filled {
background-color: #fff;
}
Here is the jsfiddle link.
However, when I try to use this code in my actual webpage, it does not work as expected. In my actual webpage, the text in the table cells that scrolls will sit over top of the sticky column (whereas in the jsfiddle, the cell text will go behind the sticky column - hidden by the background-color: #fff).
The webpage code and js is almost the same as the jsfiddle, the css is the same for both.
html
<div class="container ps-4">
<div class="row">
<div class = "table-responsive">
<table id="grade-table" class="table table-bordered table-sm ">
<thead>
<tr>
<th scope="col" class="filled">Students</th>
{% for obj in objective_list %}
<th scope="col">{{ obj.objective_name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for student in student_list %}
<tr>
<td id="row_{{ forloop.counter }}" class="filled">{{ student }}</td>
{% for obj in objective_list %}
<td id="row_{{ forloop.parentloop.counter }}_col_{{ forloop.counter }}"></td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<div>
javascript
<script>
// gradeArray contains number of students & objectives, objective name and score for each objective
var gradeArray = {{ grade_report|safe }};
var numberStudent = gradeArray.shift();
var numberObj = gradeArray.shift();
if (numberObj > 0) {
var obj = []
for (var g = 0; g < numberObj; g++) {
obj[g] = gradeArray.shift();
}
}
var rowName = [];
var studentname = [];
var objective = [];
var cellName = [];
if (numberObj > 0) {
for(var n=0; n < (numberStudent); n++) {
for(var i = 0; i < numberObj; i++) {
// +1 b/c starts at 0
rowName[n] = "row_" + (n + 1) + "_col_" + (i + 1);
cellName[n] = document.createElement('td');
// numberObj + 2 b/c in the array one index is the name and the other is the grade
let score = gradeArray[(n)*(numberObj+2)+i+1];
cellName[n].innerHTML = score
document.getElementById(rowName[n]).appendChild(cellName[n]);
//document.getElementById(rowName[n]).style.color = "grey";
switch (score) {
case 'BEG':
case 'EMG':
document.getElementById(rowName[n]).className += "table-danger";
break;
case 'DEV':
document.getElementById(rowName[n]).className += "table-warning";
break;
case 'APP':
case 'PRF':
document.getElementById(rowName[n]).className += "table-success";
break;
case 'APP+':
case 'PRF+':
document.getElementById(rowName[n]).className += "table-info";
break;
case 'EXT':
document.getElementById(rowName[n]).className += "table-primary";
break;
case '---':
case 'I':
document.getElementById(rowName[n]).className += "table-secondary";
document.getElementById(rowName[n]).style.opacity += "0.5";
break;
}
}
}
}
</script>
There are a couple of tags in here from the django framework such as {{ student }} but I don't think they are problem - they're just how I'm passing data to the DOM. It's also how I iterate through the data. All of the text, colors, data, displays as expected except for the cell data/text not scrolling behind the sticky column.
My webpage is using boostrap 4, I don't know if that is causing the issue.
Edit
I have set up a demo account to see this issue live. Here is the direct link to a page that will show issue, you may need to make your browser window a bit more narrow to bring up the table scrolling.
username: Demo
password: demodemo
I just checked out your website and the following CSS changes fix the issue:
First, remove the z-index from this CSS selector (style.css):
.table th:first-child, .table td:first-child {
position: sticky;
left: 0;
/* z-index: 6; */
Instead, add a z-index to your .filled elements:
.table .filled {
background-color: #fff;
z-index: 1;
}
Also, in order to get rid of the rows being shown left to the row header (when scrolling), remove (or overwrite) the padding on this element (bootstrap's _grid.scss):
.row>* {
flex-shrink: 0;
width: 100%;
max-width: 100%;
padding-right: calc(var(--bs-gutter-x) * .5);
/* padding-left: calc(var(--bs-gutter-x) * .5); */
margin-top: var(--bs-gutter-y);
}
Related
I am trying to add Price from table column to a total.
I am having problem adding values such as 10.00 or 5.99. I am able to calculate prices with int values, but not with values 10.00 or 5.99, etc.
Here is what I have below.
var table = document.getElementById("myTable"),
sumVal = 0;
for (var i = 1; i < table.rows.length; i++) {
sumVal = sumVal + parseF(table.rows[i].cells[2].innerHTML);
}
document.getElementById("val").innerHTML = "SubTotal =" + sumVal;
console.log(sumVal);
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>Remove</th>
</tr>
<tr>
<td>Hoddie</td>
<td class="count-me">15.00</td>
<td><button onClick="myFunction()">Remove</button></td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td><button onClick="myFunction()">Remove</button></td>
</tr>
</table>
<span id="val"></span>
You have three issues:
You are grabbing the wrong cell index, indices start at 0:
table.rows[i].cells[1]
You need to call the correct parse function:
parseFloat(table.rows[i].cells[1].innerHTML);
You need to format your output:
"SubTotal = $" + sumVal.toFixed(2);
Update: Added functionality for removing rows.
updateSubTotal(); // Initial call
function updateSubTotal() {
var table = document.getElementById("myTable");
let subTotal = Array.from(table.rows).slice(1).reduce((total, row) => {
return total + parseFloat(row.cells[1].innerHTML);
}, 0);
document.getElementById("val").innerHTML = "SubTotal = $" + subTotal.toFixed(2);
}
function onClickRemove(deleteButton) {
let row = deleteButton.parentElement.parentElement;
row.parentNode.removeChild(row);
updateSubTotal(); // Call after delete
}
#myTable td {
padding: 0.25em;
}
#val {
display: block;
margin-top: 0.5em;
}
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>Remove</th>
</tr>
<tr>
<td>Hoodie</td>
<td class="count-me">15.00</td>
<td><button onClick="onClickRemove(this)">Remove</button></td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td><button onClick="onClickRemove(this)">Remove</button></td>
</tr>
</table>
<span id="val"></span>
You are accessing the incorrect array element and also need to use parseFloat
The cells array is zero-based so you need to use cells[1] to access the second column:
var table = document.getElementById("myTable"),
sumVal = 0;
for (var i = 1; i < table.rows.length; i++) {
sumVal = sumVal + parseFloat(table.rows[i].cells[1].innerHTML);
}
document.getElementById("val").innerHTML = "SubTotal =" + sumVal;
console.log(sumVal);
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>Remove</th>
</tr>
<tr>
<td>Hoddie</td>
<td class="count-me">15.00</td>
<td><button onClick="myFunction()">Remove</button></td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td><button onClick="myFunction()">Remove</button></td>
</tr>
</table>
<span id="val"></span>
updateSubTotal(); // Initial call
function updateSubTotal() {
var table = document.getElementById("myTable");
let subTotal = Array.from(table.rows).slice(1).reduce((total, row) => {
return total + parseFloat(row.cells[1].innerHTML);
}, 0);
let subTotal2 = Array.from(table.rows).slice(1).reduce((total, row) => {
return total + parseFloat(row.cells[2].innerHTML);
}, 0);
document.getElementById("val").innerHTML = "SubTotal = $" + subTotal.toFixed(2);
document.getElementById("val1").innerHTML = subTotal2.toFixed(2);
}
function onClickRemove(deleteButton) {
let row = deleteButton.parentElement.parentElement;
row.parentNode.removeChild(row);
updateSubTotal(); // Call after delete
}
#myTable td {
padding: 0.25em;
}
#val {
display: block;
margin-top: 0.5em;
}
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>M2</th>
<th>Remove</th>
</tr>
<tr>
<td>Hoodie</td>
<td class="count-me">15.00</td>
<td class="count-me">34.00</th>
<td><button onClick="onClickRemove(this)">Remove</button></td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td class="count-me">22.34</th>
<td><button onClick="onClickRemove(this)">Remove</button></td>
</tr>
</table>
<span id="val"></span>
<span id="val1"></span>
var cell = document.getElementsByClassName("count-me");
var val = 0;
var i = 0;
while (cell[i] != undefined) {
val += parseFloat(cell[i].innerHTML);
i++;
} //end while
document.getElementById("val").innerHTML = parseFloat(val).toFixed(2);
console.log(parseFloat(val).toFixed(2));
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>Remove</th>
</tr>
<tr id="">
<td>Hoddie</td>
<td class="count-me">15.00</td>
<td>
<button onClick="myFunction()">Remove</button>
</td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td>
<button onClick="myFunction()">Remove</button>
</td>
</tr>
</table>
<span id="val"></span>
I have a table with id #tab1.
For each row, I want to calculate the value of column Points / Matches and to put it in the column Coeficiency, but my code doesn't work.
The numbers aren't parsed to int. I would always like to know if
elem[4].innerHTML(z); is ok to set coeficiency.
Average();
function Average() {
var table = document.getElementById('tab1'),
rows = table.getElementsByTagName('tbody')[1].getElementsByTagName('tr');
//console.log(rows.length);
for (var i = 0; i < rows.length; i++) {
elem = rows[i].getElementsByClassName("columns");
var x = parseInt(elem[2]);
var y = parseInt(elem[3]);
// console.log(x+y," ");
console.log(x, " ", y);
var z = y / x;
elem[4].innerHTML(z);
}
<div id="mytable">
<table id="tab1">
<tr class="rows">
<th class="columns">#</th>
<th class="columns">Team</th>
<th class="columns">Matches</th>
<th class="columns">Points</th>
<th class="columns">Coeficiency</th>
</tr>
<tbody>
<tr class="rows">
<td class="columns">1</td>
<td class="columns">Baetasii</td>
<td class="columns">3</td>
<td class="columns">9</td>
<td class="columns">100%</td>
</tr>
<tr class="rows">
<td class="columns">2</td>
<td class="columns">Carcotasii</td>
<td class="columns">2</td>
<td class="columns">5</td>
<td class="columns">100%</td>
</tr>
</tbody>
</table>
</div>
Okay, so a few pointers having looked over your code, first of all innerHTML is not a function, it's a simple property, you can just reassign it, however, I suggest using textContent due to the fact that using innerHTML, you can allow for XSS to occur.
I mean I know XSS probably isn't an issue in this specific scenario, however I thought it my be of value mentioning that.
Also, as I mentioned in the comments above, using parseInt, you need to pass it a string rather than an object which is what you were originally doing. Using functions such as getElementsByClassName or querySelectorAll, you'll have an array-like object, such as a HTMLCollection which contains a number of objects, usually Elements or Nodes.
Average();
function Average() {
var table = document.getElementById('tab1'),
rows = table.getElementsByTagName('tbody')[1].getElementsByTagName('tr');
//console.log(rows.length);
for (var i = 0; i < rows.length; i++) {
elem = rows[i].getElementsByClassName("columns");
var x = parseInt(elem[2].textContent);
var y = parseInt(elem[3].textContent);
// console.log(x+y," ");
console.log(x, " ", y);
var z = y / x;
elem[4].textContent = z;
}
}
<div id="mytable">
<table id="tab1">
<tr class="rows">
<th class="columns">#</th>
<th class="columns">Team</th>
<th class="columns">Matches</th>
<th class="columns">Points</th>
<th class="columns">Coeficiency</th>
</tr>
<tbody>
<tr class="rows">
<td class="columns">1</td>
<td class="columns">Baetasii</td>
<td class="columns">3</td>
<td class="columns">9</td>
<td class="columns">100%</td>
</tr>
<tr class="rows">
<td class="columns">2</td>
<td class="columns">Carcotasii</td>
<td class="columns">2</td>
<td class="columns">5</td>
<td class="columns">100%</td>
</tr>
</tbody>
</table>
</div>
Edit
I thought I'd also include a neater version, it does near enough the same logic stuff, it's more or less just more modern JavaScript syntax, using a more 'functional-style'. Originally I basically copied the exact same style that you provided for the sake of simplicity, but I thought that there's a few issues with that. An example being how you've used a capital letter for the Average, personally I only use a capital letter at the start of a name if it's a class, this is a personal choice however, feel free to disagree or stick to what you know!
I personally prefer using more modern syntax as personally I think is easier to read, it's more clear and concise, generally it looks like less code to read through.
// States if an array like object is empty or not.
const isEmpty = a => a.length > 0;
// Returns the text content of a html object.
const txt = td => td == null ? null : td.textContent;
// Simply updates the UI.
const render = tds => v => tds[4].textContent = parseFloat(v).toFixed(2);
// Works out whether or not to fire update or do nothing.
const compute = tds => isEmpty(tds) ? render(tds)(txt(tds[3]) / txt(tds[2])) : null;
// Gets the average for each tr.
const avg = trs => trs.forEach(tr => compute(tr.querySelectorAll("td")));
// Fire the avg function.
const update = () => avg(document.querySelectorAll("#tab1 tbody tr"));
// Render tr tag.
const renderTr = i => n => m => p => `<tr>
<td>${i}</td><td>${n}</td><td>${m}</td><td>${p}</td><td></td>
</tr>`;
// Add a table row.
const append = () => {
const tbl = document.getElementById("tab1");
const i = document.querySelectorAll("#tab1 tbody tr").length,
n = '_____',
m = Math.floor(Math.random() * 10) + 1,
p = Math.floor(Math.random() * 10) + 1;
// Safe-ish because what's being entered is controlled 100%.
// But generally try not to use innerHTML.
tbl.innerHTML += renderTr(i)(n)(m)(p);
update();
};
// Allow for auto add.
document.getElementById("add").onclick = append;
update(); // Initial run.
<div id="mytable">
<table id="tab1">
<tr class="rows">
<th class="columns">#</th>
<th class="columns">Team</th>
<th class="columns">Matches</th>
<th class="columns">Points</th>
<th class="columns">Coeficiency</th>
</tr>
<tbody>
<tr class="rows">
<td class="columns">1</td>
<td class="columns">Baetasii</td>
<td class="columns">3</td>
<td class="columns">9</td>
<td class="columns">100%</td>
</tr>
<tr class="rows">
<td class="columns">2</td>
<td class="columns">Carcotasii</td>
<td class="columns">2</td>
<td class="columns">5</td>
<td class="columns">100%</td>
</tr>
</tbody>
</table>
</div>
<button id="add">Add Row</button>
Using Object#values Array#forEach #getElementsByTagName
The main issue is that you needed to retrieve the text value with innerText.
You also don't need the redundant class names.
const table = document.getElementById("table");
const rows = table.querySelectorAll("tbody > tr");
Object.values(rows).forEach(row => {
const tds = row.getElementsByTagName('td');
if (tds.length === 5) {
const x = parseInt(tds[2].innerText),
y = parseInt(tds[3].innerText);
const z = y / x;
tds[4].innerText = `${z}`;
}
});
<table id="table">
<tr>
<th>#</th>
<th>Team</th>
<th>Matches</th>
<th>Points</th>
<th>Coeficiency</th>
</tr>
<tbody>
<tr>
<td>1</td>
<td>Baetasii</td>
<td>3</td>
<td>9</td>
<td>100%</td>
</tr>
<tr>
<td>2</td>
<td>Carcotasii</td>
<td>2</td>
<td>5</td>
<td>100%</td>
</tr>
</tbody>
</table>
getElementsByClassName returns an array-like object of all child elements which have all of the given class names.
Since we have a collection of DOM elements, elem[2] it's a DOM element and you should access its textContent property.
Also, you're using innerHTML property in a wrong way. Just replace
elem[4].innerHTML(z);
to
elem[4].innerHTML = z;
Average();
function Average() {
var table = document.getElementById('tab1'),
rows = table.getElementsByTagName('tbody')[1].getElementsByTagName('tr');
for (var i = 0; i < rows.length; i++) {
elem = rows[i].getElementsByClassName("columns");
var x = parseInt(elem[2].textContent);
var y = parseInt(elem[3].textContent);
console.log(x, " ", y);
var z = y / x;
elem[4].innerHTML = z;
}
}
<div id="mytable">
<table id="tab1">
<tr class="rows">
<th class="columns">#</th>
<th class="columns">Team</th>
<th class="columns">Matches</ht>
<th class="columns">Points</th>
<th class="columns">Coeficiency</th>
<tbody>
<tr class="rows">
<td class="columns">1</td>
<td class="columns">Baetasii</td>
<td class="columns">3</td>
<td class="columns">9</td>
<td class="columns">100%</td>
</tr>
<tr class="rows">
<td class="columns">2</td>
<td class="columns">Carcotasii</td>
<td class="columns">2</td>
<td class="columns">5</td>
<td class="columns">100%</td>
</tr>
</tbody>
</table>
</div>
I am learning Javascript, in a school assignment we have to by using a loop count how many games was made in 2014.
It does not return anything in the console, where have I gone wrong?
var allGames = document.getElementsByTagName('td');
var array = Array.prototype.slice.call(allGames, 0)
var games14 = 0;
for (var i = 0; i < array.length; ++i) {
if (array[i] == 2014) {
games14++;
console.log(games14)
}
}
<table id="games">
<thead>
<tr>
<th>Titel</th>
<th>Genre</th>
<th>Årstal</th>
</tr>
</thead>
<tbody id="games_tbody">
<tr class="horror">
<td class="title">Outlast</td>
<td>Horror</td>
<td>2013</td>
</tr>
<tr class="rpg">
<td class="title">Dragon Age: Inquisition</td>
<td>Role-playing Game</td>
<td>2014</td>
</tr>
<tr class="rpg">
<td class="title">Skyrim</td>
<td>Role-playing Game</td>
<td>2011</td>
</tr>
<tr class="horror">
<td class="title">Amnesia: The Dark Descent</td>
<td>Horror</td>
<td>2010</td>
</tr>
<tr class="simulator">
<td class="title">Scania Truck Driving Simulator</td>
<td>Simulator</td>
<td>2012</td>
</tr>
<tr class="horror">
<td class="title">Five Nights at Freddy’s</td>
<td>Horror</td>
<td>2014</td>
</tr>
<tr class="simulator">
<td class="title">Sims 4</td>
<td>Simulator</td>
<td>2014</td>
</tr>
<tr class="rts" id="last">
<td class="title">Warcraft III: Reign of Chaos</td>
<td>Real-time Strategy</td>
<td>2002</td>
</tr>
</tbody>
</table>
You need to check for its text:
var allGames = document.getElementsByTagName('td');
...
if (array[i].innerHTML == '2014') {
OR,
if(array[i].innerText == '2014' || array[i].textContent == '2014'){
No need to do Loop through elements in a HTML table.. You can simply use regular expressions to count all occurrences within the games_tbody:
var games14 = document
.getElementById('games_tbody')
.innerText
.match(/2014/g)
.length;
console.log('Games made in 2014:', games14);
<table id="games">
<thead>
<tr><th>Titel</th><th>Genre</th><th>Årstal</th></tr>
</thead>
<tbody id="games_tbody">
<tr class="horror"><td class="title">Outlast</td><td>Horror</td><td>2013</td></tr>
<tr class="rpg"><td class="title">Dragon Age: Inquisition</td><td>Role-playing Game</td><td>2014</td></tr>
<tr class="rpg"><td class="title">Skyrim</td><td>Role-playing Game</td><td>2011</td></tr>
<tr class="horror"><td class="title">Amnesia: The Dark Descent</td><td>Horror</td><td>2010</td></tr>
<tr class="simulator"><td class="title">Scania Truck Driving Simulator</td><td>Simulator</td><td>2012</td></tr>
<tr class="horror"><td class="title">Five Nights at Freddy’s</td><td>Horror</td><td>2014</td></tr>
<tr class="simulator"><td class="title">Sims 4</td><td>Simulator</td><td>2014</td></tr>
<tr class="rts" id="last"><td class="title">Warcraft III: Reign of Chaos</td><td>Real-time Strategy</td><td>2002</td></tr>
</tbody>
</table>
array[i] == 2014
Everything in the array will be an HTML Table Data Cell Element object.
Nothing in the array will be the Number 2014.
You need to read the text content from the element and then compare that.
I think this is a better way.
var table = document.getElementById("games");
count = 0;
for (let i = 0; row = table.rows[i]; i++) {
if (row.cells[2].innerHTML === "2014"){
count++;
}
/*
for (let j = 0; col = row.cells[j]; j++) {
if (col.innerHTML === "2014"){
count++;
}
}
*/
}
console.log(count);
The commented code is for checking every item on a single row.
I have multiple tbody in a table which some of span columns and rows. And then I got a jQuery code to sort this tbody based on the th.data- click.
In the first th column when it is clicked it will sort correctly. However, in the second th column when it is clicked it does not sort the tbody.
Here is the snippet :
var table = $('table'),
th = table.find('thead th'),
tbody = table.find('tbody');
$(th).on('click', function() {
$(th).removeClass();
var index = this.cellIndex,
sortType = $(this).data('sort'),
sortDir = $(this).data('dir') || 'asc';
var that = $(this);
$('table').find('tbody').slice().sort(function(a, b) {
var dataTH = that.data('class');
//alert(dataTH);
if(dataTH == 'number')
{
//alert("hi this is a number");
var aText = $(a).find('td.sortNum:eq(' + index + ')').text(),
bText = $(b).find('td.sortNum:eq(' + index + ')').text();
}
else if(dataTH == 'department')
{
//alert("hi this is a department");
var aText = $(a).find('td.depart:eq(' + index + ')').text(),
bText = $(b).find('td.depart:eq(' + index + ')').text();
}
if (sortDir == 'desc') {
temp = aText;
aText = bText;
bText = temp;
}
if (sortType == 'string') {
return aText.localeCompare(bText);
}
else {
return +aText - +bText;
}
})
.appendTo('table');
$(this).data('dir', sortDir == 'asc' ? 'desc' : 'asc');
$(this).removeClass().addClass('sort-' + sortDir);
});
table {
border-collapse: collapse;
width: 400px;
}
th, td {
padding: 5px;
border: 1px #DDD solid;
}
.sort-asc:after,
.sort-desc:after {
content: '▲';
font-size: 12px;
}
.sort-desc:after {
content: '▼';
}
<table>
<thead>
<tr>
<th data-sort="number" data-class="number" >No</th>
<th data-sort="number" data-class="department" >Department</th>
<th data-sort="number">Quantity</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="2" class="sortNum">1</td>
<td class="depart">20</td>
<td>20</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">VTP</td>
</tr>
</tbody>
<tbody>
<tr>
<td rowspan="2" class="sortNum">2</td>
<td class="depart">30</td>
<td>25</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">VTP</td>
</tr>
</tbody>
<tbody>
<tr>
<td rowspan="2" class="sortNum">3</td>
<td class="depart">40</td>
<td>50</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">VTP</td>
</tr>
</tbody>
<tbody>
<tr>
<td rowspan="2" class="sortNum">4</td>
<td class="depart">50</td>
<td>15</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">VTP</td>
</tr>
</tbody>
<tbody>
<tr>
<td rowspan="2" class="sortNum">5</td>
<td class="depart">60</td>
<td>32</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">VTP</td>
</tr>
</tbody>
</table>
You do not need the :eq Selector since you are referencing the Cells by css class. It does work in the first Column because the cell index is zero. What you are essentially saying in the selector $(a).find('td.sortNum:eq(' + index + ')') is "give me the list of td's with the class 'sortNum' and of that list the element at position index. But the first condition of the Selector - td.sortNum - will only return one element.
To make your sorting work again for the second column you could get rid of the :eq part
if(dataTH == 'number')
{
//alert("hi this is a number");
var aText = $(a).find('td.sortNum').text(),
bText = $(b).find('td.sortNum').text();
}
else if(dataTH == 'department')
{
//alert("hi this is a department");
var aText = $(a).find('td.depart').text(),
bText = $(b).find('td.depart').text();
}
see also http://jsfiddle.net/doc_snyder/Lvvmow8g/1/
I have the following table:
<table id="btt-ranges" cellspacing="0" cellpadding="0" border="0"
<tbody>
<tr>
<th scope="col"> </th>
<th id="Business" scope="col">Type of Business</th>
<th id="Ranges" scope="col"> Ranges</th>
<th scope="col">BTT</th>
</tr>
<tr>
<td>Example</td>
<td>Example</td>
<td>Example</td>
<td>Example</td>
</tr>
<tr>
<td>Example</td>
<td>Example</td>
<td>Example</td>
<td>Example</td>
</tr>
<tr>
<td>Example</td>
<td>Example</td>
<td>Example</td>
<td>Example</td>
</tr>
</tbody>
</table>
What I have to do is hide the last column, but I can't change how the table is right now.
I can use Javascript and so far this is what I tried:
function show_hide_column() {
var tbl = document.getElementById('btt-changes');
var rows = tbl.getElementsByTagName('tr');
for (var row = 0; row < rows.length; row++) {
var cols = rows[row].children;
console.log(1, cols.length);
if (4 >= 0 && 4 < cols.length) {
var cell = cols[4];
console.log(cell, cell.tagName);
if (cell.tagName == 'TD') cell.style.display = 'none';
}
}
}
What can I do without touching the table?
This code selects the col's cells (th and tds), and then hides them (fiddle):
var lastColHeader = Array.prototype.slice.call(document.querySelectorAll('th:last-child', '#btt-ranges'), 0); // get the header cell
var lastColCells = Array.prototype.slice.call(document.querySelectorAll('td:last-child', '#btt-ranges'), 0).concat(lastColHeader); // get the column cells, and add header
lastColCells.forEach(function(cell) { // iterate and hide
cell.style.display = 'none';
});
You don't need to use javascript for this. You can use a CSS selector to hide the last column:
#btt-ranges tr td:last-child { display: none; }
Edit: Just realized you specifically need to do it in javascript. Not sure if there is any way to append a style without touching the table.