Responsive table, possible for nested table cell widths to inherit - javascript

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

Related

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

Determine number of td with specific class in each table row

I use this code to hide all rows in a table that have a td with a class named "hide". This is working fine.
$('.table').find('tr:has(td.hide)').hide();
Now I am trying to hide all all rows in table if the row has n number of td with the class equal to hide. I was not even able to loop on the tr list of the table with thos code
$('.table > tr').each(function() {
console.log("new tr", $(this).text());
});
my html looks as following
<table class='table'>
<tr class='hidable'><td class='hide'> Some text</td> <td class='hide'> Some text</td></tr>
<tr class='hidable'><td class='hide'> Some text</td> <td class='nothide'> Some text</td></tr>
</table>
in this example i want to hide the row if the two tds have the class hide.
When you create a table without tbody, that tag is automatically generated.
Child combinator:
Elements matched by the second selector must be the immediate children of the elements matched by the first selector.
Include tbody as part of the selector. Try $('.table tbody > tr')
$('.table tbody > tr').each(function() {
console.log("new tr", $(this).text());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class='table'>
<tr class='hidable'>
<td> Some text </td>
<td class='hide'> Some text</td>
<td class='hide'> Some text</td>
</tr>
<tr>
<td class='nothide'> Some text</td>
</tr>
</table>
OR: Remove > from the selector
$('.table tr').each(function() {
console.log("new tr", $(this).text());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class='table'>
<tr class='hidable'>
<td> Some text </td>
<td class='hide'> Some text</td>
<td class='hide'> Some text</td>
</tr>
<tr>
<td class='nothide'> Some text</td>
</tr>
</table>
With jQuery I'd suggest using toggleClass():
// here we select the <tr> elements, and chain the toggleClass() method
// to that jQuery collection:
$('tr').toggleClass(function() {
// within the anonymous function 'this' refers to the current <tr>
// element of the collection (the native DOM node not a jQuery $(this))
// we use Element.querySelectorAll() to retrieve all the <td> elements
// with a class of 'hide' and then test the length to see if there
// are more than one. If this is true, we return the 'hideRow' class
// to the method, otherwise we return an empty string. Obviously this
// approach uses a CSS selector ('hideRow') to hide the relevant <tr>
// elements:
return this.querySelectorAll('.hide').length > 1 ? 'hideRow' : '';
});
.hide {
background-color: limegreen;
opacity: 0.5;
}
.hideRow {
/* here we use opacity: 0.5 so that you can visually
see which elements are selected/affected; in production
you should obviously switch to 'display: none' to hide the
elements: */
opacity: 0.5;
}
<table>
<tbody>
<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 class="hide">cell 4</td>
</tr>
<tr>
<td>cell 1</td>
<td class="hide">cell 2</td>
<td>cell 3</td>
<td class="hide">cell 4</td>
</tr>
<tr>
<td>cell 1</td>
<td>cell 2</td>
<td class="hide">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 class="hide">cell 1</td>
<td class="hide">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 class="hide">cell 1</td>
<td class="hide">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>
</tbody>
</table>
JS Fiddle demo.
In native JavaScript — using a contemporary browser — the following would achieve the same thing:
// here we use the spread syntax to conver the iterable NodeList returned by
// document.querySelectorAll() into an Array, we then iterate over that Array
// of Nodes using Array.prototype.forEach():
[...document.querySelectorAll('tr')].forEach(
// we use an anonymous Arrow function - as we don't need to use 'this' - in
// order perform a function on each of the <tr> elements of the Array of
// <tr> elements; the 'tr' passed into the function is a reference to the
// current <tr>:
(tr) => {
// here we use the Element.classList API, with its toggle() method to
// supply a class-name ('hideRow'), and we use the assessment to determin
// whether or not the class-name should be applied. If the assessment
// evaluates to true then the class-name is applied, if false it is not:
tr.classList.toggle('hideRow', tr.querySelectorAll('.hide').length > 1);
});
.hide {
background-color: limegreen;
opacity: 0.5;
}
.hideRow {
opacity: 0.5;
}
<table>
<tbody>
<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 class="hide">cell 4</td>
</tr>
<tr>
<td>cell 1</td>
<td class="hide">cell 2</td>
<td>cell 3</td>
<td class="hide">cell 4</td>
</tr>
<tr>
<td>cell 1</td>
<td>cell 2</td>
<td class="hide">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 class="hide">cell 1</td>
<td class="hide">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 class="hide">cell 1</td>
<td class="hide">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>
</tbody>
</table>
JS Fiddle demo.
As an important addenda to my original answer, the reason that your selector:
$('.table > tr')
doesn't work is because of the child combinator, the >, which would cause jQuery to retrieve the <tr> elements which are children of the <table class=".table"> element. As browsers predictably rescue 'broken' HTML — though a <tbody> is not mandatory according to the spec — they will all automagically insert a <tbody> element to wrap any <tr> elements which are contained within a <table> that aren't already so wrapped.
This has been discussed elsewhere on the site: https://stackoverflow.com/a/5568877/82548
References:
JavaScript:
Array.prototype.forEach().
Arrow functions ((arguments) => { ...statements... }.
document.querySelectorAll().
Element.classList API.
Element.querySelectorAll().
NodeList.prototype.forEach().
Spread (...) syntax.
jQuery:
toggleClass().
You want to hide row if 2 td's have hide class , if this is your requirement then here is tested example
$(".table tr").each(function(){
if($(this).find("td.hide").length == 2) {
$(this).hide();
}
});
Here I loop through each tr and then in each tr I check all td with class "hide" with find("td.hide").length == 2 and if length is equal to two then hide the row.

How to construct this kind of irregular tables with colspan and rowspan?

I need to construct a table which will have complex col and row. How can I construct this kind of table?
I've already tried to construct but it seems that the output is not what I wished for. I want to make a left header which span two rows and the rows will have header and input field.
This is my code that I've already tried. I failed whenever i try to put theader to all the fields.
<table>
<tr>
<td rowspan="2">Flock ID</td>
<td>Field 1</td>
<td>Field 2</td>
<td>Field 3</td>
<td>Field 4</td>
<td>Field 5</td>
</tr>
<tr>
<td>Field 6</td>
<td>Field 7</td>
<td>Field 8</td>
<td>Field 9</td>
<td>Field 10</td>
</tr>
</table>
The table should have a columnn that span two rows. For each row there will be several headers.
This the example pic of my expected table

Simple way to add rowspan in HTML table

I am trying to generate a HTML Table, that has rowSpan (as you see in the picture)
I manage to generate the table for columns 1 and 2 and 3. Here is the code:
<td rowspan="2"> a</td>
<td>bb</td>
<td>d</td>
</tr>
<tr>
<td>c</td>
<td>e</td>
</tr>
but when it gets to column4, I can't figure out what to do. I create a nested table but it doesn't work properly.
Anyone has any idea?
I think you're looking for this - the first column spans 3 rows, the middle columns span just a single row, and the top right column is again 2 rows spanned:
<table border="1">
<tr>
<th>col 1</th>
<th>col 2</th>
<th>col 3</th>
<th>col 4</th>
</tr>
<tr>
<td rowspan="3">a</td>
<td rowspan="2">b</td>
<td rowspan="2">c</td>
<td>f</td>
</tr>
<tr>
<td>g</td>
</tr>
<tr>
<td>h</td>
<td>i</td>
<td>j</td>
</tr>
</table>
See https://jsfiddle.net/gpnx0nqj/
Note that the second row only have two cells (td).

Unexpected Behavior of :even pseudo selector in jquery

I have created this fiddle for problem as you will see there are three tables having zebra strip using jQuery.
Table 1 is showing in correct form as it start tr index from 0 as even. Table 2 is continuing from last table and it is showing 1st row as white instead of dark. I think it is happening due to it is continuing from last table's tr index.
HTML:
<table>
<caption> Table 1</caption>
<tr>
<th>Table Head 1</th>
<td>Table Data 1</td>
</tr>
<tr>
<th>Table Head 2</th>
<td>Table Data 2</td>
</tr>
<tr>
<th>Table Head 3</th>
<td>Table Data 3</td>
</tr>
</table>
<table>
<caption> Table 2</caption>
<tr>
<th>Table Head 1</th>
<td>Table Data 1</td>
</tr>
<tr>
<th>Table Head 2</th>
<td>Table Data 2</td>
</tr>
<tr>
<th>Table Head 3</th>
<td>Table Data 3</td>
</tr>
</table>
<table>
<caption> Table 3</caption>
<tr>
<th>Table Head 1</th>
<td>Table Data 1</td>
</tr>
<tr>
<th>Table Head 2</th>
<td>Table Data 2</td>
</tr>
<tr>
<th>Table Head 3</th>
<td>Table Data 3</td>
</tr>
</table>​
JavaScript:
$('table').find('tr:even').css('background','#d0d0d0');
Fiddle: http://jsfiddle.net/daljir/gryh5/
You can use find() to 'work' with each table separately:
$("table").find("tr:even").css("background", "#d0d0d0");
DEMO: http://jsfiddle.net/gryh5/1/
You are selecting all the <tr> elements in the document, you can use the nth-child to selector to select all the even numbered <tr>s in the document.
$('table tr:nth-child(2n)').css('background','#d0d0d0');
http://jsfiddle.net/Kyle_Sevenoaks/gryh5/7/
This is because you are selecting all the tr's in general (irrespective of the table) and when they are stacked you would get this particular behavior.
Try this:
$('table').find('tr:even').css('background','#d0d0d0');
Check FIDDLE
This works
<table id="t1">
<caption> Table 1</caption>
<tr>
<th>Table Head 1</th>
<td>Table Data 1</td>
</tr>
<tr>
<th>Table Head 2</th>
<td>Table Data 2</td>
</tr>
<tr>
<th>Table Head 3</th>
<td>Table Data 3</td>
</tr>
</table>
<table id="t2">
<caption> Table 2</caption>
<tr>
<th>Table Head 1</th>
<td>Table Data 1</td>
</tr>
<tr>
<th>Table Head 2</th>
<td>Table Data 2</td>
</tr>
<tr>
<th>Table Head 3</th>
<td>Table Data 3</td>
</tr>
</table>
<table id="t3">
<caption> Table 3</caption>
<tr>
<th>Table Head 1</th>
<td>Table Data 1</td>
</tr>
<tr>
<th>Table Head 2</th>
<td>Table Data 2</td>
</tr>
<tr>
<th>Table Head 3</th>
<td>Table Data 3</td>
</tr>
</table>
and JS:
$(function(){
$('#t1 tr:even, #t2 tr:even, #t3 tr:even').css('background','#d0d0d0');
});
jsfiddle: http://jsfiddle.net/SnakeEyes/gryh5/2/
http://jsfiddle.net/gryh5/9/
$('table').each(function(){
$(this).find('tr').filter(':even').css('background','#d0d0d0');
});

Categories

Resources