Making sections of an html table fixed using jQuery - javascript

I have an HTML table which is dynamically populated from data fetched from a server. Since I don't know the schema or the number of rows before hand, I have its, and its row's & cell's position defined as relative.
Now once the table is populated, I want to delete a set of rows from it(specified by an array of row indexes). I am trying for the following animation for these row deletions.
The rows which are supposed to be deleted fade out leaving blank space in the table.->The other rows slide up to fill the space created between them.
I have tried out following things:
Simply fading out or sliding up the rows to be deleted using jquery.
The problem with this is, the animation is jerky, and all I can see is the bunch of rows disappearing at once.
Setting the 'position' of all other rows except the ones to be deleted as fixed, Fading out the rows to be deleted, and then sliding up the rows which were fixed.
The problem with this is - Since the rows were relatively placed, once I make them fixed they all lose all their previous styles, contract, and lose the well defined structure and overwriting each other.
What would be the best way to implement the required kind of animation?
Also, how would one go about specifying a bunch of rows (specified by a list of indexes) for a jQuery selector. Right now I am creating the tr:nth-of-type(i) selector for each element of the list, and concatenating them in a large string separated by ',', and using this as the selector for all the rows. Is there a better way to do this?

jsBin demo
Don't animate table elements. Ever.
Instead animate DIV elements inside your row cells. Once they faded out and animated to height 0, than you're free to remove the parent TR
Example:
$("button").on("click", function(){
// Table with no DIV elements (Animate ROWS)
$("#noDivs tr:eq(1)").animate({opacity:0}, 800, function(){
$(this).slideUp();
});
// Table with DIVs (Animate DIV)
$("#divs tr:eq(1) div").animate({opacity:0}, 800, function(){
$(this).slideUp();
});
});
table{
border-collapse: separate;
border-spacing: 0px;
}
table td{
padding:0; margin:0;
}
table#noDivs td,
table#divs div{
border:1px solid #ddd;
padding:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Delete rows 2</button>
<br><br>
Animate DIV instead:
<table id="divs">
<tr>
<td><div>Cell 1</div></td>
<td><div>Cell 2</div></td>
<td><div>Cell 3</div></td>
<td><div>Cell 4</div></td>
</tr>
<tr>
<td><div>Cell 1</div></td>
<td><div>Cell 2</div></td>
<td><div>Cell 3</div></td>
<td><div>Cell 4</div></td>
</tr>
<tr>
<td><div>Cell 1</div></td>
<td><div>Cell 2</div></td>
<td><div>Cell 3</div></td>
<td><div>Cell 4</div></td>
</tr>
<tr>
<td><div>Cell 1</div></td>
<td><div>Cell 2</div></td>
<td><div>Cell 3</div></td>
<td><div>Cell 4</div></td>
</tr>
</table>
Animate TR (Issue)
<table id="noDivs">
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
<td>Cell 4</td>
</tr>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
<td>Cell 4</td>
</tr>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
<td>Cell 4</td>
</tr>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
<td>Cell 4</td>
</tr>
</table>

you should add/remove a class and use CSS to animate.
here an example (only css for test ONLY) to see how it would/could work
table {
width:600px;
border:solid;
}
td {
border:solid;
}
/* demo purpose , instead js */
td {
pointer-events:none;
font-size:1.2em;
opacity:1;
}
tr:focus td {
font-size:0;
border:solid 0 transparent;
opacity:0;
transition:1s;/*with steps or css animation is fine too */
}
<table>
<tr tabindex="0">
<td>hide</td>
<td>my</td>
<td>row</td>
</tr>
<tr tabindex="0">
<td>hide</td>
<td>my</td>
<td>row</td>
</tr>
<tr tabindex="0">
<td>hide</td>
<td>my</td>
<td>row</td>
</tr>
<tr tabindex="0">
<td>hide</td>
<td>my</td>
<td>row</td>
</tr>
<tr tabindex="0">
<td>hide</td>
<td>my</td>
<td>row</td>
</tr>
<tr tabindex="0">
<td>hide</td>
<td>my</td>
<td>row</td>
</tr>
<tr tabindex="0">
<td>hide</td>
<td>my</td>
<td>row</td>
</tr>
<tr tabindex="0">
<td>hide</td>
<td>my</td>
<td>row</td>
</tr>
</table>

Related

Data Alignment inside Table column

I have one table in that I am repeating data inside column. One column have property and other have value of that property. I am getting problem when data wraps property and value not aligned properly. Below is my example.
My example
<table cellspacing="0" celpadding="0">
<thead>
<tr>
<th>Property</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div>Property 1</div>
<div>Property 2</div>
<div>Property 3</div>
<div>Property 4</div>
</td>
<td>
<div>Value 1</div>
<div>Value 2</div>
<div>Value 3</div>
<div>Value 4</div>
</td>
</tr>
<tr>
<td>Property 2</td>
<td>Value 2</td>
</tr>
<tr>
<td>Property 1</td>
<td>Property 1</td>
</tr>
</tbody>
</table>
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
color:#fff;
}
table{
width:100px
}
table tr td,table tr th{border:1px solid #fff;padding:5px;}
table tr td div{
border-bottom:1px solid #eee;
padding:5px 0;
}
Right now I have given fixed width to table to produce my problem. In this condition what should I do to reolve this issue. I want to align property and value equally with respective values. Please help.
The easiest way to solve your issue is to add a fixed height to your table tr td div rules, so that it aligns properly. So, you could update that specific rule to something like:
table tr td div{
border-bottom: 1px solid #eee;
padding: 5px 0;
height: 48px;
}
However, <div>s are not really supposed to go into tables. Maybe you need to rethink your table's structure, as this will have accessibility issues for sure.
What's wrong with using a classic table with no random divs contained in your td elements? Consider the below:
<table cellspacing="0">
<tr>
<td>Property 1</td>
<td>Value 1</td>
</tr>
<tr>
<td>Property 2</td>
<td>Value 2</td>
</tr>
<tr>
<td>Property 3</td>
<td>Value 3</td>
</tr>
<tr>
<td>Property 4</td>
<td>Value 4</td>
</tr>
</table>
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
color:#fff;
}
table{
width:200px
}
td {
width:100px;
padding:10px;
border:1px solid white;
}
Here is a fiddle: https://jsfiddle.net/8dyxqbkz/2/
You should use <tr><tr/> tag for table row
and <td><td/> tag for table cell.
Let me show an example:
<table cellspacing="0" celpadding="0">
<tr>
<td>
Property 1
</td>
<td>
Property 2
</td>
<td>
Property 3
</td>
<td>
Property 4
</td>
</tr>
<tr>
<td>Value 1</td>
<td>Value 2</td>
<td>Value 3</td>
<td>Value 4</td>
</tr>
<tr>
<td>Property 2</td>
<td>Property 1</td>
</tr>
<tr>
<td>Value 2</td>
<td>Property 1</td>
</tr>
</table>

How to find the first empty row in an HTML table using Javascript

The code example below creates a table with 6 rows. The last two rows are empty.
The JavaScript code finds and displays correctly the number of rows in a table.
I would like to find the row number of the first row with empty cells. In this example it will be row (4) (counting from 0). I tried several solutions and they did not work.
Your help is appreciated.
Thanks,
Menachem
<!DOCTYPE html>
<html>
<head>
<style>
table, td {
border: 1px solid black;
}
</style>
</head>
<body>
<table id="myTable">
<tr>
<td>cell 1</td>
<td>cell 2</td>
</tr>
<tr>
<td>cell 3</td>
<td>cell 4</td>
</tr>
<tr>
<td>cell 4</td>
<td>cell 5</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</table>
<br>
<script>
var x = document.getElementById("myTable").rows.length;
alert ("Number of rows in the table is " + x);
</script>
</body>
</html>
You can use combination of :has() and :not().
td:not(:empty) get td which is not empty
tr:not(:has(td:not(:empty))) selects all tr which is not contains any non empty td
tr:not(:has(td:not(:empty))):first gets the first tr from them
var index = $("#myTable tr:not(:has(td:not(:empty))):first").index();
console.log(index);
table,td {
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table id="myTable">
<tr>
<td>cell 1</td>
<td>cell 2</td>
</tr>
<tr>
<td>cell 3</td>
<td>cell 4</td>
</tr>
<tr>
<td>cell 4</td>
<td>cell 5</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</table>
<br>
<script>
var x = document.getElementById("myTable").rows.length;
alert("Number of rows in the table is " + x);
</script>
I would like to find the row number of the first row with empty cells
You can use :has(), adjacent sibling selector + to match td:empty, that has next element sibling that is td:empty, :first, index(). The index of the first tr element which has a child td element without child nodes would be 3
$("#myTable tr:has(td:empty + td:empty):first").index()
<!DOCTYPE html>
<html>
<head>
<style>
table,
td {
border: 1px solid black;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
</head>
<body>
<table id="myTable">
<tr>
<td>cell 1</td>
<td>cell 2</td>
</tr>
<tr>
<td>cell 3</td>
<td>cell 4</td>
</tr>
<tr>
<td>cell 4</td>
<td>cell 5</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</table>
<br>
<script>
var x = document.getElementById("myTable").rows.length;
alert("Number of rows in the table is " + x);
console.log($("#myTable tr:has(td:empty + td:empty):first").index());
</script>
</body>
</html>
$("#myTable tr").find('td').filter(function() {
return $(this).text() == '' ;
}).addClass('empty');
table,
td {
border: 1px solid black;
}
.empty {
background-color: red
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="myTable">
<tr>
<td>cell 1</td>
<td>cell 2</td>
</tr>
<tr>
<td>cell 3</td>
<td>cell 4</td>
</tr>
<tr>
<td>cell 4</td>
<td>cell 5</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</table>
Use .filter()
You can use a test inside a .filter() call that checks the number of empty td's against the number of all td's in a tr. Filter out all those that have any non-empty td, call .first() to find the first one in the filtered set, and .index() to get the index
var index = $("#myTable tr").filter(function(){
return $("td",this).length == $("td:empty",this).length;;
}).first().index();
console.log("Empty row index: "+index);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table id="myTable">
<tr>
<td>cell 1</td>
<td>cell 2</td>
</tr>
<tr>
<td>cell 3</td>
<td>cell 4</td>
</tr>
<tr>
<td>cell 4</td>
<td>cell 5</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</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.

Responsive table, possible for nested table cell widths to inherit

I've got a responsive table, which has different content in each row and a concertina mechanism on each row.
The concertina essentially adds another table row beneath that current row, which has a td with a colspan for the amount of cells in the table.
Inside this concertina I have another table which I need the table cells to line up with the parent table. I appreciate this probably isn't possible with HTML/CSS alone and probably needs to be done with JS?
Or is there another way?
I can't post all my code here but here is a screenshot of what I mean
<table class="parent-table">
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
<td>Cell 4</td>
<td>Cell 5</td>
<td>Cell 6</td>
</tr>
<tr>
<td colspan="6" class="concertina">
<div>
<table>
<tr>
<td>Other 1</td>
<td>Other 2</td>
<td>Other 3</td>
<td>Other 4</td>
<td>Other 5</td>
<td>Other 6</td>
</tr>
</table>
</div>
</td>
</tr>
Short answer would be 'No', not possible just with HTML/CSS. I myself am working on a fixed-header, scrollable table with resizable columns, plus double-click column header border to autofit. It's far from complete, and I can tell you if that is roughly the direction you might be heading, you might want to take a deep breath.
UPDATES BELOW
Judging from the screenshot, have you considered revising the HTML structure?
From the markup below, you have multiple <tbody> sections, each with a first <tr> that contains <th> elements. The rest would be showing details data, rows of <tr> that contains typical <td> elements.
In jQuery, you can use $('tr:has(th)') to select the header row, and $('tr:has(td)') to select the data rows.
The last <th> in the header would house your "More/Less" control, which simply shows/hides the subsequent data rows.
Would this work for you instead?
<table class="master-table">
<tbody class="concertina">
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 3</th>
<th>Header 4</th>
<th>Header 5</th>
<th>Header 6</th>
<th>More</th>
</tr>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
<td>Cell 4</td>
<td>Cell 5</td>
<td colspan="2">Cell 6</td>
</tr>
</tbody>
<tbody class="concertina">
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 3</th>
<th>Header 4</th>
<th>Header 5</th>
<th>Header 6</th>
<th>More</th>
</tr>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
<td>Cell 4</td>
<td>Cell 5</td>
<td colspan="2">Cell 6</td>
</tr>
</tbody>
</table>
Reset your tables using this bit of CSS:
table {
border-collapse: collapse;
border-spacing: 0;
}
Then you will have to set the width of the <td>s

Toggle the <TR>

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";
});
});

Categories

Resources