Javascript - how to toggle all next singlings until class found - javascript

I have the table below which hides all the child rows by default.
I'd like to toggle all child rows right underneath the corresponding clicked root row. That is, the n .child rows next to the clicked .root. How can I do this in pure Javascript?
.hidden {
display:none;
}
<table>
<tr>
<td>Root</td>
</tr>
<tr class="hidden">
<td>Child 1</td>
</tr>
<tr class="hidden">
<td>Child 2</td>
</tr>
<tr class="hidden">
<td>Child 3</td>
</tr>
<tr class="hidden">
<td>Child 4</td>
</tr>
<tr>
<td>Root</td>
</tr>
<tr class="hidden">
<td>Child 1</td>
</tr>
<tr class="hidden">
<td>Child 2</td>
</tr>
</table>

If, what you want to do is to remove the hidden classname from all the rows after the clicked one until you get to a row that is not hidden, then you can do this:
function func(root) {
var row = root.parentNode.parentNode;
row = nextElement(row, "tr");
while (row && row.className === "hidden") {
row.className = "";
row = nextElement(row, "tr");
}
}
function nextElement(start, tag) {
tag = tag.toUpperCase();
start = start.nextSibling;
while (start) {
if (start.tagName === tag) {
return start;
} else {
start = start.nextSibling;
}
}
return start;
}
Working demo: http://jsfiddle.net/jfriend00/dvg6j9or/
Here's another version that works off the array of rows and uses a parent search to find the right level of the table:
function func(root) {
var table = findParentTag(root, "table");
var currentRow = findParentTag(root, "tr");
var rows = Array.prototype.slice.call(table.querySelectorAll("tr"));
var currentIndex = rows.indexOf(currentRow) + 1;
// now traverse rows until you find one that is different than the starting row
for (; currentIndex < rows.length; ++currentIndex) {
if (rows[currentIndex].className.indexOf("hidden") !== -1) {
rows[currentIndex].className = "";
} else {
break;
}
}
}
function findParentTag(start, tag) {
tag = tag.toUpperCase();
while (start && start.tagName !== tag) {
start = start.parentNode;
}
return start;
}
Working demo: http://jsfiddle.net/jfriend00/hut56fLg/

Related

Collapsing and expanding multiple nested rows in jQuery

I need a little help with collapsing and expanding nested rows. Currently my code below expands and collapses as desired at the first level but the subsequent levels also show.
$(document).ready(function(e) {
$('.collapseTitle').click(function() {
$(this).parent()
.parent()
.next('tbody')
.toggleClass('collapsed');
});
});
.collapsed {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<td class="collapseTitle">Title</td>
</tr>
</thead>
<tbody class="collapsed">
<tr>
<td>Level 1</td>
</tr>
<tr>
<td>Level 2</td>
</tr>
</tbody>
</table>
I am trying to achieve that Level 1 expands when "collapseTitle" is clicked and that only when "collapseAccount" is clicked, does Level 2 expand. Now I know that my code should look something like the below, but I am struggling...
<table>
<thead>
<tr>
<td class="collapseTitle">Title</td>
</tr>
</thead>
<tbody>
<tr class="collapsed account">
<td class="collapseAccount">Level 1</td>
</tr>
<tr class="collapsed level">
<td>Level 2</td>
</tr>
</tbody>
</table>
<script>
$(document).ready(function(e) {
$('.collapseTitle').click(function() {
$(this).parent().parent().next('tbody tr').toggleClass('account');
});
});
$(document).ready(function(e) {
$('.collapseAccount').click(function() {
$(this).next('tr').toggleClass('level');
});
});
</script>
Any help would be greatly appreciated.
The following code should do it. I hope it helps with what you want to achieve:
collapses/expands columns when clicking on the header/title of the column and
collapses/expands all rows following the account row when clicking on it (until the next account row)
The only thing you need to do is add the class account to the higher level rows. You can do this pretty easily when you're displaying these with a loop.
.collapsed {
/* using visibility, since display causes layout issues */
/* due to empty rows rows/columns collapsing */
visibility: collapse;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<td>Title1</td>
<td>Title2</td>
</tr>
</thead>
<tbody>
<tr class="account">
<td class="collapsed">Account Summary - Account A</td>
<td class="collapsed">Account Summary - Account A</td>
</tr>
<tr class="collapsed">
<td class="collapsed">Account Details Part I - Account A</td>
<td class="collapsed">Account Details Part I - Account A</td>
</tr>
<tr class="collapsed">
<td class="collapsed">Account Details Part II - Account A</td>
<td class="collapsed">Account Details Part II - Account A</td>
</tr>
<tr class="account">
<td class="collapsed">Account Summary - Account B</td>
<td class="collapsed">Account Summary - Account B</td>
</tr>
<tr class="collapsed">
<td class="collapsed">Account Details Part I - Account B</td>
<td class="collapsed">Account Details Part I - Account B</td>
</tr>
</tbody>
</table>
<script>
$(document).ready(() => {
/* the following handlers expand/collapse the columns */
$('thead > tr > td').each((i, el) => {
$(el).click(() => {
const colIndex = $(el).index() + 1;
const nRows = $('tbody > tr').length;
for (let j = 0; j < nRows; j += 1) {
let cellSelector = `tbody > tr:nth-child(${j+1})`
cellSelector += `> td:nth-child(${colIndex})`;
$(cellSelector).toggleClass('collapsed');
}
})
})
/* the following handlers expand/collapse the account-details rows */
$('tbody > tr.account').each((i, el) => {
$(el).click(() => {
$(el).nextUntil('.account').each((j, ele) => {
$(ele).toggleClass('collapsed');
})
})
})
});
</script>
Your jQuery selectors are just a bit off for the toggleClass. You can use the class names of the row to toggle. Also you should create a class to be toggled that displays the row/hides it. For example:
edit:
I now created the titles and rows dynamically to give you a better idea of how this can be done using data- attributes.
You will have a title td and a row td that match on a data- attribute, so when you click a title and corresponding tr will be shown. So for example if you click title 1 (with a data-index=1) then the tr with the attribute data-rowindex=1 will be shown.
$(document).ready(function(e) {
createTable();
$('.collapseTitle').click(function() {
// grab the data-index value from the clicked title
let index = $(this).attr("data-index");
// find a tr that has the attribute data-rowindex and it matches index
$("tr[data-rowindex='" + index + "']").toggleClass("collapsed");
});
});
function createTable(){
// create the titles and the level rows
for(let i = 0; i < 3; i++){
// create the title row
let $trTitle = $('<tr>');
let $tdTitle = $('<td>', {class: "collapseTitle", text: "Title " + i});
$tdTitle.attr("data-index", i);
let $finalTitleRow = $trTitle.append( $tdTitle );
// create the level row
let $trLevel = $('<tr>', {class: "collapsed account"} );
$trLevel.attr("data-rowindex", i);
let $tdLevel = $('<td>', {text: "Level " + i});
let $finalLevelRow = $trLevel.append( $tdLevel );
// add the title and level row pairs to the head and body
$("#myTableHead").append($finalTitleRow[0]);
$("#myTableBody").append($finalLevelRow[0]);
}
}
.collapsed {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead id="myTableHead">
</thead>
<tbody id="myTableBody">
</tbody>
</table>
I managed to find the answer I was looking for... Thank you to "stackoverfloweth",
Answer To My Question
The snippet of code which has helped me thus far is below,
$('.parent-row').click(function(){
var $element = $(this).next();
while(!$element.hasClass('parent-row')){
$element.toggle();
if($element.next().length >0){
$element = $element.next();
}
else{
return;
}
} });
$('.child-row.has-children').click(function(){
var $element = $(this).next();
while($element.hasClass('child-child-row')){
$element.toggle();
if($element.next().length >0){
$element = $element.next();
}
else{
return;
}
} });

Remove extra cell spaces

I have a script below:
var cells = [].slice.call(document.querySelectorAll("#myTable td"));
var search = document.getElementById("myInput");
search.addEventListener("keyup", function() {
cells.forEach(function(cell) {
if (!search.value.trim()) {
cell.style.background = "white";
cell.style.display = 'table-cell';
} else if (cell.textContent.toLowerCase().indexOf(search.value.toLowerCase()) == 0) {
cell.style.background = 'yellow';
cell.style.display = "table-cell";
} else {
cell.style.background = "white";
cell.style.display = 'none';
}
});
});
<input id='myInput' type='text'>
<table id='myTable'>
<tr>
<td>a</td>
<td>ab</td>
<td>abs</td>
<td>ador</td>
<td>turous</td>
<td>acac</td>
<td>accle</td>
</tr>
<tr>
<td>ed</td>
<td>aced</td>
<td>ate</td>
<td>acg</td>
<td>aci</td>
<td>atic</td>
<td>ive</td>
</tr>
<tr>
<td>l</td>
<td>pt</td>
<td>able</td>
<td>ad</td>
<td>adoent</td>
<td>ble</td>
<td>d</td>
</tr>
<tr>
<td>ed</td>
<td>a</td>
<td>aate</td>
<td>a</td>
<td>aavating</td>
<td>aive</td>
<td>a</td>
</tr>
<tr>
<td>d</td>
<td>ng</td>
<td>eable</td>
<td></td>
<td>alarmed</td>
<td>ming</td>
<td>t</td>
</tr>
<tr>
<td>ted</td>
<td>ae</td>
<td>all</td>
<td>agjhistic</td>
<td>akjhkjg</td>
<td>hjious</td>
<td>ample</td>
</tr>
<tr>
<td>hjbsed</td>
<td>ahkjng</td>
<td>anhjkd</td>
<td>ahjhnt</td>
<td>ahjkjc</td>
<td>a</td>
<td>hjhed</td>
</tr>
<tr>
<td>aghjed</td>
<td>hjjal</td>
<td>ghjmher</td>
<td>amjhkiue</td>
<td>ahkjus</td>
<td>any</td>
<td>ahmkjehensive</td>
</tr>
<tr>
<td>ajhjkjiate</td>
<td>ahkjpt</td>
<td>arctic</td>
<td>arid</td>
<td>aromatic</td>
<td>artistic</td>
<td>ashamed</td>
</tr>
<tr>
<td>assured</td>
<td>astonishing</td>
<td>athletic</td>
<td>attached</td>
<td>attentive</td>
<td>atkjkjactive</td>
<td>ahghbtere</td>
</tr>
<tr>
<td>bhkuhish</td>
<td>hkjh</td>
<td>bhkre</td>
<td>barren</td>
<td>basic</td>
</tr>
<tr>
<td>befsgdfgful</td>
<td>bdsfsdfed</td>
<td>dsfsdfved</td>
<td>bedsfsfcial</td>
<td>better</td>
<td>best</td>
<td>bdfsfitched</td>
</tr>
</table>
I use this script for searching text with an HTML table. It have more than 500 cells like 100 rows and 5 columns etc. This script works well for finding text within a short table but when I search anything it also display gap of rows and columns, if i have a long table which has more than 500 cells.
Here I tried to used regular expressions like \s and /g but it doesn't work, may be I insert them on wrong place. Also I tried to change cell.style.display = "table-cell"; with many other style but doesn't work.
Can any one properly guide me what and where I have to put exactly to get output properly without rows/columns gap if i have more than 500 cells and what that mean with syntax description.
Try this! =)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input type="text" class="input"/>
<div class="print"></div>
<script>
var data = ['food', 'bar', 'google']; // your data
var fx = function(text) {
var print = function(list,s) {
var table = $('<table/>').css('width','100%');
var x = 0;
while (list[x]) {
var tr = $('<tr/>');
while (list[x] && x < 5) {
var td = $('<td/>').text(list[x])
if(s == list[x]){
td.css('background','red');
}
tr.append(td);
x++;
}
table.append(tr);
}
$('.print').html(table);
}
if (typeof text === "undefined") {
print(data, '');
} else {
var find = [];
for (var i = 0; data[i]; i++) {
if (data[i].toLowerCase().indexOf(text.toLowerCase()) == 0) find[find.length] = data[i];
}
print(find,text);
}
}
$(function() {
$('.input').keyup(function() {
fx($(this).val());
});
fx();
});
</script>

JQuery compare class names

I'm not sure what I've done wrong in this. I have assigned classes dynamically to rows. These classes are ordered and a row can have the same class. I want to order all the classes with multiple of the same identifier one colour. Then the next set of numbers an alternative colour before going back to the original colour. The last row always seems to fail though.
<body>
<table>
<thead>Row</thead>
<tbody>
<tr class="a-1"><td>A1 row</td></tr>
<tr class="a-2"><td>A2 row</td></tr>
<tr class="a-2"><td>A2 row</td></tr>
<tr class="a-2"><td>A2 row</td></tr> // should have class warning,but doesn't after js
<tr class="a-3"><td>A3 row</td></tr>
<tr class="a-4"><td>A4 row</td></tr>
<tr class="a-4"><td>A4 row</td></tr>
<tr class="a-4"><td>A4 row</td></tr>
<tr class="a-4"><td>A4 row</td></tr> // should have class warning,but doesn't after js
</tbody>
</table>
</body>
JQuery
var flag = true;
$("table tr[class^='a-']").each(function(){
var current = $(this);
if((current.attr("class") == current.next().attr("class")) || (current.attr("class") == current.prev().attr("class"))){
if(flag){
current.addClass("info");
} else {
current.addClass("warning");
}
} else {
if(flag){
flag = false;
} else {
flag = true;
}
}
});
I made a jsfiddle to show my problem
$(function() {
var flag = true;
$("table tr[class^='a-']").each(function() {
var current = $(this);
var next = current.next();
var prev = current.prev();
var currentClassName = $(this).attr('class');
// alert(currentClassName);
if(next.hasClass(currentClassName) || prev.hasClass(currentClassName))
{
if(flag){
current.addClass("info");
} else {
current.addClass("warning");
}
}
else {
if(flag){
flag = false;
} else {
flag = true;
}
}
});
});
.info{background-color: blue;}
.warning{background-color: yellow;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<table>
<thead>Row</thead>
<tbody>
<tr class="a-1">
<td>A1 row</td>
</tr>
<tr class="a-2">
<td>A2 row</td>
</tr>
<tr class="a-2">
<td>A2 row</td>
</tr>
<tr class="a-2">
<td>A2 row</td>
</tr>// should have class warning,but doesn't after js
<tr class="a-3">
<td>A3 row</td>
</tr>
<tr class="a-4">
<td>A4 row</td>
</tr>
<tr class="a-4">
<td>A4 row</td>
</tr>
<tr class="a-4">
<td>A4 row</td>
</tr>
<tr class="a-4">
<td>A4 row</td>
</tr>// should have class warning,but doesn't after js
</tbody>
</table>
</body>
Hope this helps
This part of condition was never fullfiled:
(current.attr("class") == current.prev().attr("class")
because when you added class "warning" or "info" to it, so even if it contains the same class as current element, it has additional class and it's not equal. So it's better, write something like that:
var currClassName = "warning";
$("table tr[class^='a-']").each(function(){
var current = $(this);
var currClass = current.attr("class");
if((current.next().hasClass(currClass)) || current.prev().hasClass(currClass)){
current.addClass(currClassName);
}
else {
currClassName = (currClassName == "info") ? "warning" : "info";
}
});

How to arrange table rows up and down along auto arranging row number sequentially?

HTML:
<table class="myTable" border="1" width="80%">
<tr >
<td></td>
<td>one</td>
<td><button onClick="MoveUp();">⇧</button></td>
<td><button onClick="MoveDown();">⇩</button></td>
</tr>
<tr>
<td></td>
<td>two</td>
<td><button onClick="MoveUp();">⇧</button></td>
<td><button onClick="MoveDown();">⇩</button></td>
</tr>
<tr>
<td></td>
<td>three</td>
<td><button onClick="MoveUp();">⇧</button></td>
<td><button onClick="MoveDown();">⇩</button></td>
</tr>
<tr>
<td></td>
<td>four</td>
<td><button onClick="MoveUp();">⇧</button></td>
<td><button onClick="MoveDown();">⇩</button></td>
</tr>
<tr>
<td></td>
<td>five</td>
<td><button onClick="MoveUp();">⇧</button></td>
<td><button onClick="MoveDown();">⇩</button></td>
</tr>
</table>
CSS:
table.myTable {
counter-reset: rowNumber;
}
table.myTable tr {
counter-increment: rowNumber;
}
table.myTable tr td:first-child::before {
content: counter(rowNumber);
min-width: 1em;
margin-right: 0.5em;
}
JavaScript:
function MoveUp() {
var tablebody = document.getElementById('mytable');
if(TableLocation > 0) {
tablebody.moveRow(TableLocation, TableLocation - 1);
TableLocation = TableLocation - 1;
}
}
function MoveDown() {
var tablebody = document.getElementById('mytable');
if((TableLocation > 0) && (TableLocation < tablebody.rows.length - 1)) {
tablebody.moveRow(TableLocation, TableLocation + 1);
TableLocation = TableLocation + 1;
}
}
I am getting table data from back end and adding row number from css. I am using JavaScript for moving the rows up and down. It is not working. If Moving rows up and down is happened it has to auto arrange the row number from one to last.
Here is my fiddle.
Working version
You have to find the parent tr of the button and then find the element to wich append before. Because of there is no function for append after one element you have to find the second next element when you want to move down.
Move up function:
function MoveUp() {
var table,
row = this.parentNode;
// find the parent tr ( the row element )
while ( row != null ) {
if ( row.nodeName == 'TR' ) {
break;
}
row = row.parentNode;
}
// the parent of the row is the table body
table = row.parentNode;
// insert the row before it's previevs siblings
table.insertBefore ( row, get_previoussibling( row ) );
}
Move down function:
function MoveDown() {
var table,
row = this.parentNode;
while ( row != null ) {
if ( row.nodeName == 'TR' ) {
break;
}
row = row.parentNode;
}
table = row.parentNode;
// you have to find the second next siblings to append before
// NOTE: if the second parameter of the 'insertBefore' function is null
// it will append the row to the table!
table.insertBefore ( row, get_nextsibling ( get_nextsibling( row ) ) );
}

Finding the matching value in an HTML table and highlighting it

I need your help.
Because of the way my data will be structured. I need to create some sort of a function that will allow a user to input the record number from column 1 into the input box "record". Then at the click of a button, the code will find the exact matching value from column 1 in my data table and select the row using the existing code to highlight it. I can't seem to be able to put together some sort of logic as to how to make this work.
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
#data tr.normal td {
color: #235A81;
background-color: white;
}
#data tr.highlighted td {
color: #FFFFFF;
background-color: #235A81;
}
</style>
<script type='text/javascript'>
function test() {
var table = document.getElementById("data");
var thead = table.getElementsByTagName("thead")[0];
var tbody = table.getElementsByTagName("tbody")[0];
var ishigh
tbody.onclick = function (e) {
e = e || window.event;
var td = e.target || e.srcElement
var row = td.parentNode;
if (ishigh&&ishigh!=row){
ishigh.className='';
}
row.className = row.className==="highlighted" ? "" : "highlighted";
ishigh=row;
}
document.onkeydown = function(e){
e = e || event;
var code = e.keyCode, rowslim = table.rows.length - 2, newhigh;
if(code === 38){ //up arraow
newhigh = rowindex(ishigh) - 2;
if(!ishigh || newhigh < 0){return GoTo('data', rowslim);}
return GoTo('data', newhigh);
} else if (code === 40){ //down arrow
newhigh = rowindex(ishigh);
if(!ishigh || newhigh > rowslim){return GoTo('data', 0);}
return GoTo('data', newhigh);
}
}
function GoTo(id,nu){
var obj=document.getElementById(id),
trs=obj.getElementsByTagName('TR');
nu = nu + 1;
if (trs[nu]){
if (ishigh&&ishigh!=trs[nu]){
ishigh.className='';
}
trs[nu].className = trs[nu].className=="highlighted" ? "" : "highlighted";
ishigh=trs[nu];
}
}
function rowindex(row){
var rows = table.rows, i = rows.length;
while(--i > -1){
if(rows[i] === row){return i;}
}
}
}//end of nested function
</script>
</head>
<body onload="test()">
<table style="cursor: default;" id="data" cellspacing="1" border="1">
<thead>
<tr>
<th>Record #</th>
<th>first name</th>
<th>last name</th>
<th>age</th>
<th>total</th>
<th>discount</th>
<th>diff</th>
</tr>
</thead>
<tbody>
<tr>
<td>5</td>
<td>peter</td>
<td>parker</td>
<td>28</td>
<td>9.99</td>
<td>20.3%</td>
<td>+3</td>
</tr>
<tr>
<td>3</td>
<td>john</td>
<td>hood</td>
<td>33</td>
<td>19.99</td>
<td>25.1%</td>
<td>-7</td>
</tr>
<tr>
<td>1</td>
<td>clark</td>
<td>kent</td>
<td>18</td>
<td>15.89</td>
<td>44.2%</td>
<td>-15</td>
</tr>
<tr>
<td>4</td>
<td>bruce</td>
<td>almighty</td>
<td>45</td>
<td>153.19</td>
<td>44%</td>
<td>+19</td>
</tr>
<tr>
<td>2</td>
<td>benjamin</td>
<td>evans</td>
<td>56</td>
<td>153.19</td>
<td>23%</td>
<td>+9</td>
</tr>
</tbody>
</table>
<br>
Example: type the record's number in the input box and then select it:
<input type="text" id="record" />
</body>
</html>
I'm still having trouble getting the big picture of what you're trying to do, but I wrote a function to grab the tr whose first td contains the record.
function findTrForRecord(record) {
var nodelist = document.getElementById('data').getElementsByTagName('tr');
for (var i = 0; i < nodelist.length; i++) {
var tr = nodelist.item(i);
var tds = tr.getElementsByTagName('td');
if (tds.length > 0 && tds[0].innerHTML.trim() == record)
return tr;
}
}
From there, you can highlight it or do whatever you want.
/**
* unhighlights previous row and highlights new row
* that matches the record
*/
button.onclick = function () {
var trs = document.getElementsByTagName('tr');
for (var i = 0; i < trs.length; i++)
if (trs[i].className.indexOf('highlighted') > 0) {
trs[i].className.replace('highlighted','');
break;
}
var record = document.getElementById('record').value;
var tr = findTrForRecord(record);
tr.className += ' highlighted';
}
I edited your html file you provided. Check this out. http://pastebin.com/Wz0EdBMV

Categories

Resources