Toggle the <TR> - javascript

I am trying to do hide the belonging rows. For example if you click on 'Sub Title 1' which will then hide Item 1, Item 2 and Item 3 rows only.
Example:
<table border="1">
<tbody>
<tr class="head">
<td> title </td>
</tr>
<tr class="sub-title">
<td>Sub Title 1</td>
</tr>
<tr> <td>Item 1</td> </tr>
<tr> <td>Item 2</td> </tr>
<tr> <td>Item 3</td> </tr>
<tr class="sub-title">
<td>Sub Title 2</td>
</tr>
<tr> <td>Item 4</td> </tr>
<tr> <td>Item 5</td> </tr>
<tr> <td>Item 6</td> </tr>
</tbody>
</table>
-
$('.sub-title').click( function() {
$(this).parent().nextUntil('.sub-title').toggle();
})
It doesn't seem to work...

nextUntil selects for siblings, not children. Remove the "parent" from your call.
Edited to respond to further question about excluding some rows based on class. Obviously you can also accommodate Kolink's response about preventing toggle's "display: block" overwriting the default "display: table-row", but as long as you test in all supported browsers, I don't see any problem with using toggle.
$('.sub-title').click( function() {
$(this).nextUntil('.sub-title').each(function() {
if (!$(this).hasClass('order'))
$(this).toggle();
});
});

You have to toggle manually:
$(".sub-title").on("click",function() {
$(this).nextUntil(".sub-title").each(function() {
this.style.display = this.style.display == "none" ? "" : "none";
});
});

Related

How to filter getElement based on CSS property in JS or jQuery

The following code gets all the tr tags in #mytable:
table = document.getElementById("myTable");
trs = table.getElementsByTagName("tr");
But if we want to get only tr tags whose display is not none, what should I do?
Thanks.
Not the best solution, but you can do this...
let tableRows = $("#my-table tr");
tableRows.map((i, obj)=>{
if($(obj).attr('style') != 'display: none;'){
// whatever you want to do here...
console.log(obj);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<table id="my-table">
<tbody>
<tr>
<td>data 1</td>
<td>data 2</td>
</tr>
<tr style="display: none;">
<td>data 3</td>
<td>data 4</td>
</tr>
<tr>
<td>data 5</td>
<td>data 6</td>
</tr>
<tr style="display: none;">
<td>data 7</td>
<td>data 8</td>
</tr>
<tr>
<td>data 9</td>
<td>data 10</td>
</tr>
</tbody>
</table>
You can use the :visible selector which is a jquery extension (https://api.jquery.com/visible-selector/) that allows seelction of elements based on display visibility.
In the following snippet - there are 3 tr's but the middle one is hidden with display:none. The console log targets the visible tr's and logs the number (2);
$(document).ready(function(){
const totalRows = $('#myTable tr');
const visibleRows = totalRows.filter(':visible');
console.log('total rows: '+ totalRows.length); // gives 3
console.log('visible rows: '+ visibleRows.length); // gives 2 - since one tr is hidden
})
.second-row {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="myTable">
<tbody>
<tr class="first-row">
<td>row 1</td>
<td>row 1</td>
<td>row 1</td>
</tr>
<tr class="second-row">
<td>row 2</td>
<td>row 2</td>
<td>row 2</td>
</tr>
<tr class="third-row">
<td>row 3</td>
<td>row 3</td>
<td>row 3</td>
</tr>
</tbody>
</table>
Simple solution with VanillaJS
var elems = document.querySelectorAll('tr');
var noneElems = [];
elems.forEach(function (element) {
if (window.getComputedStyle(element).display == 'none') {
noneElems.push(element);
}
});
console.log( { noneElems } );
<table id="mytable">
<tr>
<td>Block</td>
<td>1</td>
</tr>
<tr style="display:none">
<td>None</td>
<td>1</td>
</tr>
<tr>
<td>Block</td>
<td>2</td>
</tr>
<tr style="display:none">
<td>None</td>
<td>2</td>
</tr>
</table>

Is there any direct way to get a minimal HTML node structure in jQuery?

This is the input node structure
<table>
<thead>
<tr style="text-align: left;">
<th class="some_class"><div><div><span>COL1</span></div></div></th>
<th class="some_class"><div><div><span>COL2</span></div></div></th>
<th class="some_class"><div><div><span>COL3</span></div></div></th>
<th class="some_class"><div><div><span>COL4</span></div></div></th>
</tr>
</thead>
<tbody>
<tr>
<td>content 1</th>
<td>content 2</td>
<td>content 3</td>
<td>content 4</td>
</tr>
</tbody>
</table>
And this is the wanted output structure
<table>
<thead>
<tr>
<th>COL1</th>
<th>COL2</th>
<th>COL3</th>
<th>COL4</th>
</tr>
</thead>
<tbody>
<tr>
<td>content 1</th>
<td>content 2</td>
<td>content 3</td>
<td>content 4</td>
</tr>
</tbody>
</table>
I could just remove the elements manually with some mappings or some loops, but I am wondering if there is a better way to just get the minimal HTML possible without attributes
Removing the attributes you can use the removeAttr,.
To get rid of <div><div><span>...,. You could loop the th get the text() and then set using text() again this has the effect of getting rid of the the extra tags.
eg..
const c = $('table').clone();
c.find('*').removeAttr('class style');
c.find('th').each(function() { $(this).text($(this).text()); });
console.log(c[0].outerHTML);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<thead>
<tr style="text-align: left;">
<th class="some_class"><div><div><span>COL1</span></div></div></th>
<th class="some_class"><div><div><span>COL2</span></div></div></th>
<th class="some_class"><div><div><span>COL3</span></div></div></th>
<th class="some_class"><div><div><span>COL4</span></div></div></th>
</tr>
</thead>
<tbody>
<tr>
<td>content 1</td>
<td>content 2</td>
<td>content 3</td>
<td>content 4</td>
</tr>
</tbody>
</table>
Sure, it's pretty easy...
Here i have a codesandbox for you where this works:
https://codesandbox.io/s/wonderful-star-g8h8f?file=/index.html
$(".noattrs *").each(function() {
// first copy the attributes to remove
// if we don't do this it causes problems
// iterating over the array we're removing
// elements from
var attributes = $.map(this.attributes, function(item) {
return item.name;
});
// now use jQuery to remove the attributes
var el = $(this);
$.each(attributes, function(i, item) {
el.removeAttr(item);
});
})

How to remove a pattern of table row elements from a table?

If I have the following table, which I can't manually touch, but can apply javascript to...
<table data="customTable">
<tr>
<td>item 1</td>
</tr>
<tr>
<td height="10"></td>
</tr>
<tr>
<td>item 2</td>
</tr>
<tr>
<td height="10"></td>
</tr>
</table>
...when the DOM loads fully, how can I remove every instance of <tr><td height="10"></td></tr> from the above table via jQuery or raw JavaScript? I don't need that row at all and its causing design issues for me. This is my first time trying to learn how to replace a full pattern of elements.
Hopefully, this is doable via JavaScript?
This should do the trick.
jQuery
$('td[height="10"]').parent().remove();
https://jsfiddle.net/uzv3fn2e/1/
Vanilla JS
Array.from(document.querySelectorAll('td[height="10"]')).forEach(td => td.parentNode.remove());
https://jsfiddle.net/t7y6aqc5/
You can use :has() selector to select tr that has td with specific attribute
$("tr:has(td[height='10'])").remove()
$("tr:has(td[height='10'])").remove()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table data="customTable">
<tr>
<td>item 1</td>
</tr>
<tr>
<td height="10"></td>
</tr>
<tr>
<td>item 2</td>
</tr>
<tr>
<td height="10"></td>
</tr>
</table>
without using jquery javascript has also remove()
document.querySelectorAll("td").forEach(el => el.getAttribute("height") === "10" && el.parentNode.remove())
<table data="customTable">
<tr>
<td>item 1</td>
</tr>
<tr>
<td height="10"></td>
</tr>
<tr>
<td>item 2</td>
</tr>
<tr>
<td height="10"></td>
</tr>
</table>

Populate Bootstrap 4 Table From Array?

I'm currently trying to dynamically populate a bootstrap 4 table from an array. I am trying to populate 3 tables that are actually side by side, and then will eventually filter the data from the array to be stored in each corresponding table. So what I am aiming to have is 3 tables that can be populated with a different number of rows each, with data taken directly from an array.
However, whenever I try and populate or create the table dynamically through a function, I either remove the Bootstrap formatting, or end up with some very odd results!
Below is essentially the type of layout I want to achieve, but this is static and I'd love to have something that can acquire these varying rows, based on how much data they retrieve from an array.
<div class="row">
<div class="col-md-4">
<h2 class="sub-header">Test Tab 1</h2>
<div class="table-responsive">
<table class="table table-striped">
<tbody>
<tr>
<td class="col-md-1">Content 1</td>
<td class="col-md-2">Content 1</td>
<td class="col-md-3">Content 1</td>
</tr>
<tr>
<td class="col-md-1">Content 2</td>
<td class="col-md-2">Content 2</td>
<td class="col-md-3">Content 2</td>
</tr>
<tr>
<td class="col-md-1">Content 3</td>
<td class="col-md-2">Content 3</td>
<td class="col-md-3">Content 3</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-md-4">
<h2 class="sub-header">Test Tab 2</h2>
<div class="table-responsive">
<table class="table table-striped">
<tbody>
<tr>
<td class="col-md-1">Content 4</td>
<td class="col-md-2">Content 4</td>
<td class="col-md-3">Content 4</td>
</tr>
<tr>
<td class="col-md-1">Content 5</td>
<td class="col-md-2">Content 5</td>
<td class="col-md-3">Content 5</td>
</tr>
<tr>
<td class="col-md-1">Content 6</td>
<td class="col-md-2">Content 6</td>
<td class="col-md-3">Content 6</td>
</tr>
<tr>
<td class="col-md-1">Content 7</td>
<td class="col-md-2">Content 7</td>
<td class="col-md-3">Content 7</td>
</tr>
<tr>
<td class="col-md-1">Content 8</td>
<td class="col-md-2">Content 8</td>
<td class="col-md-3">Content 8</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-md-4">
<h2 class="sub-header">Test Tab 3</h2>
<div class="table-responsive">
<table class="table table-striped">
<tbody>
<tr>
<td class="col-md-1">Content 9</td>
<td class="col-md-2">Content 9</td>
<td class="col-md-3">Content 9</td>
</tr>
<tr>
<td class="col-md-1">Content 10</td>
<td class="col-md-2">Content 10</td>
<td class="col-md-3">Content 10</td>
</tr>
<tr>
<td class="col-md-1">Content 11</td>
<td class="col-md-2">Content 11</td>
<td class="col-md-3">Content 11</td>
</tr>
<tr>
<td class="col-md-1">Content 12</td>
<td class="col-md-2">Content 12</td>
<td class="col-md-3">Content 12</td>
</tr>
<tr>
<td class="col-md-1">Content 13</td>
<td class="col-md-2">Content 13</td>
<td class="col-md-3">Content 13</td>
</tr>
<tr>
<td class="col-md-1">Content 14</td>
<td class="col-md-2">Content 14</td>
<td class="col-md-3">Content 14</td>
</tr>
<tr>
<td class="col-md-1">Content 15</td>
<td class="col-md-2">Content 15</td>
<td class="col-md-3">Content 15</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
When experimenting with just a single one of these tables to try and get the general concept working, I've just been going around in circles and can't seem to figure out this hierarchy of table elements and how to associate the javascript created rows to the bootstrap classes for design.
Below is my attempt, but it doesn't seem to alter the base bootstrap html or make any changes at all (one of numerous attempts)(credit to Ovidiu for fixing the error):
var testList = ["TestContent1", "TestContent2", "TestContent3", "TestContent4"];
function drawTable1() {
// get the reference for the body
var table1 = document.getElementById('table1Div');
// get reference for <table> element
var tbl = document.getElementById("table1");
// creating rows
for (var r = 0; r < testList.length; r++) {
var row = document.createElement("tr");
// create cells in row
for (var c = 0; c < 3; c++) {
var cell = document.createElement("td");
var cellText = document.createElement('span');
cellText.innerText = testList[r];
cell.appendChild(cellText);
row.appendChild(cell);
}
tbl.appendChild(row); // add the row to the end of the table body
}
table1.appendChild(tbl); // appends <table> into <div>
}
drawTable1();
Edit: To clarify, my question differs from the duplicate as I would still like to retain my bootstrap formatting. Simply creating a dynamic table removes all of the bootstrap classes and formatting that keeps the tables responsive.
Edit 2: Thank you Ovidiu for the working fiddle! This more clearly illustrates my point that the Bootstrap formatting is no longer applied once the table has been populated dynamically!
To add classes from JavaScript use className property:
var div = document.createElement('div');
div.className = 'some-class other-class';
You may also want to avoid using classes like col-md-3 with tables. Bootstrap layoud is float based while tables have their own display types in HTML/CSS and changing them to floats won't work (especially that you are not using row on rows etc.). Either move to purely <div> based layout or use width=8%, width=17% and width=25% respectively. And of course fix the bug of the widths not summing up to 100% (col-md-1 + col-md-2 + col-md-3 = col-md-6 < col-md-12 (12 is 100% row width in Bootstrap)). Or if you really want free space, then either add it explicitly as an empty cell or just set the whole table width to be 50%.
Answer to comment:
If you are going to use table-stripped then you need table to be <table> and not <div>, obviously. However you MUST NOT use col-md-# classes with table cells. Use width="33%" (or other appropriate value) attribute instead. If you create the whole table content dynamically, you may add <colgroup> sections and define columns separately from the content. Also, you should append your rows inside <tbody> not <table>. Appending them to <table> works only due to browser being backward compatibile with HTML 3, but Bootstrap is not and its styling gets broken. Bootstrap expects all the cells to be either in <thead>, <tbody> or <tfoot>, not directly under <table>. Example code:
<table class="table table-striped">
<colgroup>
<col width="17%">
<col width="33%">
<col width="50%">
</colgroup>
<tbody id="table2">
<tr>
<td>Content 4</td>
<td>Content 4</td>
<td>Content 4</td>
</tr>
<!-- etc. --->
</tbody>
</table>

Drag and drop multiple rows from one table to another table

I need to drag and drop table rows by selecting desired rows from on table to another table. First provide option to select needed rows from one table and then all the selected rows need to be drag and drop into some other table.
I have done the sample to drag and drop single row from on table to another. Find the below code:
html:
<div id="table1" class="bitacoratable">
<table>
<thead>
<tr>
<th>ID</th>
<th>ClassName</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Class 1</td>
</tr>
<tr class="childrow">
<td collspan = "2" >
<table class="childgrid">
<tr class="draggable_tr">
<td>1</td>
<td>Student 1</td>
</tr>
<tr class="draggable_tr">
<td>2</td>
<td>Student 2</td>
</tr>
<tr class="draggable_tr">
<td>3</td>
<td>Student 3</td>
</tr>
<tr class="draggable_tr">
<td>4</td>
<td>Student 4</td>
</tr>
<tr class="draggable_tr">
<td>5</td>
<td>Student 5</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>2</td>
<td>Class 2</td>
</tr>
<tr class="childrow">
<td collspan = "2">
<table class="childgrid">
<tr class="draggable_tr">
<td>6</td>
<td>Student 6</td>
</tr>
<tr class="draggable_tr">
<td>7</td>
<td>Student 7</td>
</tr>
<tr class="draggable_tr">
<td>8</td>
<td>Student 8</td>
</tr>
<tr class="draggable_tr">
<td>9</td>
<td>Student 9</td>
</tr>
<tr class="draggable_tr">
<td>10</td>
<td>Student 10</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</div>
<div id="table2" class="bitacoratable">
<table>
<thead>
<tr>
<th>ID</th>
<th>ClassName</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Class 1</td>
</tr>
<tr class="childrow">
<td>
<table class="childgrid">
<tr class="draggable_tr">
<td>1</td>
<td>Student 1</td>
</tr>
<tr class="draggable_tr">
<td>2</td>
<td>Student 2</td>
</tr>
<tr class="draggable_tr">
<td>3</td>
<td>Student 3</td>
</tr>
<tr class="draggable_tr">
<td>4</td>
<td>Student 4</td>
</tr>
<tr class="draggable_tr">
<td>5</td>
<td>Student 5</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>2</td>
<td>Class 2</td>
</tr>
<tr class="childrow">
<td>
<table class="childgrid">
<tr class="draggable_tr">
<td>6</td>
<td>Student 6</td>
</tr>
<tr class="draggable_tr">
<td>7</td>
<td>Student 7</td>
</tr>
<tr class="draggable_tr">
<td>8</td>
<td>Student 8</td>
</tr>
<tr class="draggable_tr">
<td>9</td>
<td>Student 9</td>
</tr>
<tr class="draggable_tr">
<td>10</td>
<td>Student 10</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</div>
Script:
$("#table1 .childgrid tr, #table2 .childgrid tr").draggable({
helper: 'clone',
revert: 'invalid',
start: function (event, ui) {
$(this).css('opacity', '.5');
},
stop: function (event, ui) {
$(this).css('opacity', '1');
}
});
$("#table1 .childgrid, #table2 .childgrid").droppable({
drop: function (event, ui) {
$(ui.draggable).appendTo(this);
}
});
$(document).on("click", ".childgrid tr", function () {
$(this).addClass("selectedRow");
});
CSS:
table
{
border-collapse:collapse;
}
table, td, th
{
border:1px solid black;
}
.bitacoratable {
height: 400px;
overflow-y: auto;
width: 220px;
float:left;
}
#table1 {
margin-right: 100px;
}
.selectedRow {
background-color: #E7E7E7;
cursor: move;
}
How to do it for mutilple rows?
Regards,
Karthik.
You could use draggable's helper function. There's a nice implementation here.
Here's how it looks using the above as a guideline for your particular code:
JsFiddle Demonstration:
Explanation of what's going on:
(1) If there's only one selected, then we'll just treat this as a single drag and drop. Because it was not clicked yet (mouse holding down and dragging right away), we'll manually add the selectedRow class to ensure it gets properly removed from its original location.
(selected.length === 0) {
selected = $(this).addClass('selectedRow');
}
(2) Make a temporary container to store all the rows as one unit, as if we were dragging one item.
var container = $('<div/>').attr('id', 'draggingContainer');
container.append(selected.clone().removeClass("selectedRow"));
return container;
(3) You can modify the CSS so that we're always clicking on the items before it shows the move cursor. I already did, but feel free to change it as you like.
(4) Now we append all the table rows in our temporary divider into the .childgrid we chose to drop into and remove all elements that originally were selected.
$("#table1 .childgrid, #table2 .childgrid").droppable({
drop: function (event, ui) {
$(this).append(ui.helper.children());
$(this) is what we chose, and we're appending the elements inside our temporary divider that the helper returns, which are the table rows.
$('.selectedRow').remove();
}
Now to get rid of those table rows that we selected earlier.
});
Let me know if there are any bugs and I'll try my best to sort them out. It works on my end. Since you can highlight the text in the table rows, there could possibly be some issues if you drag and drop too fast and you're highlighting text rather than selecting the row itself.

Categories

Resources