I have a HTML like so:
<table>
<tr>
<th>colA heading</th>
<th>colb heading</th>
</tr>
<tr>
<td>colA content</td>
<td>colb content</td>
</tr>
<tr>
<th>colC heading</th>
<th>colD heading</th>
</tr>
<tr>
<td>colC content</td>
<td>colC content</td>
</tr>
</table>
That products the following output:
colA heading colB heading
colA content colB content
colC heading colD heading
colC content colD content
what I want to do is detect using presumably JavaScript, if the page is wide enough, dynamically change my table look like so:
colA heading colB heading colC heading colD heading
colA content colB content colC content colD content
How can I do that using HTML (and JavaScript/CSS if need be)?
Thanks
If I understand your question correctly, this is achievable by splitting your table into two tables, like so:
<head>
<style>
.bigBox {
margin: 0px;
padding: 0px;
float: left;
clear: right;
display: inline;
border: 1px solid black;
}
</style>
</head>
<body>
<table class="bigBox">
<tr>
<th>colA heading</th>
<th>colb heading</th>
</tr>
<tr>
<td>colA content</td>
<td>colb content</td>
</tr>
</table>
<table class="bigBox">
<tr>
<th>colC heading</th>
<th>colD heading</th>
</tr>
<tr>
<td>colC content</td>
<td>colC content</td>
</tr>
</table>
</body>
The border is for ease of testing only. All you have to do to test is set the contents of one of the cells to something like "colb headingggggggggggggggggggggggggggggggggggggg."
How would you determine that the table should be able to fit in one table?
Are you starting from two tables, going to one table, or from one -> 2?
It would be easiest to either start with one table, and if the scrollbars are active then do something like the following tiny snippet. You should use firebug, in firefox, to examine the dom attributes of the table, to determine the properties to use.
var tableelem = document.createElement('table');
var thead = document.createElement('thead');
for(var t = 0; t < 2; t++) {
var trow = document.createElement('tr');
var tdata = document.createElement('td');
tdata.appendChild(document.createTextNode('header'));
thead.appendChild(trow);
}
tableelem.appendChild(thead);
You will need to use document.getElementById to get the table you will be pulling from, and then the header will be in table.rows[0], so you can parse the cells in that row and get the values where I put header above.
You will then need to add the tableelem to the div using the appendChild function.
Related
I am trying to lock certain amount of rows to be "fixed" when scrolling a table. The problems:
1) The number of rows to be locked vary (not always only the column headers) so cannot rely on fixed number.
2) The height of each row may vary depend on content, so it is not equally height and not any known value.
3) As the table and content are dynamically created and can be modified on runtime, a responsive solution will be the best.
Given the following CSS (assume all rows in thead are to be "locked"):
thead th{ position:sticky; }
And then the JavaScript approach (tbl is the table element):
var i,j,h=0,r; // Set the "top" of next "locked" rows
for(i=0 ; i<tbl.thead.rows.length ; i++) {
r=tbl.thead.rows[i];
for(j=0 ; j<r.cells.length ; j++)
r.cells[j].style.top=h+"px";
h+=r.offsetHeight;
}
The main issue: I prefer to do it ALL using CSS (if possible).
The best "solution" I have come up can only remove the inner loop, but using dynamically controlled <style> element (assuming stl is the handle to the STYLE element):
var rules="",i,h=0; // Set the "top" of next "locked" rows
for(i=0 ; i<tbl.thead.rows.length ; i++) {
rules+="thead tr:nth-child("+(i+1)+") th{ top:"+h+"px; }\n";
h+=tbl.thead.rows[i].offsetHeight;
}
/*
I know is possible to use stl.sheet.insertRule(),
but as I overwrite ALL rules whenever there is change, I have chosen this way.
*/
stl.innerHTML=rules;
However, that requires as many rules as header rows.
The question: Any solution to make ONE RULE that can create the same effect?
Is it possible to achieve it with pure CSS (responsive solution)?
Note: The table can have any position on page, but is inside a container with overflow:auto.
Thanks a lot
There is a very easy solution, make thead sticky and not the individual rows
.container {
height: 250px;
width: 200px;
overflow: auto;
}
th {
height: 60px;
}
#second {
height: 80px;
background-color: lightblue;
}
thead {
position: sticky;
top: 0px;
}
<div class="container">
<table>
<thead>
<tr>
<th>h row 1</th>
</tr>
<tr>
<th id="second">h row 2</th>
</tr>
</thead>
<tr>
<td>data</td>
</tr>
<tr>
<td>data</td>
</tr>
<tr>
<td>data</td>
</tr>
<tr>
<td>data</td>
</tr>
<tr>
<td>data</td>
</tr>
<tr>
<td>data</td>
</tr>
<tr>
<td>data</td>
</tr>
<tr>
<td>data</td>
</tr>
<tr>
<td>l data</td>
</tr>
</table>
</div>
I have run into trouble while working with Data Tables with jQuery. I have a table with dynamic column header generation (which also determines the colspan value) and the actual complex header text.
I am then populating my data table with the data that I receive from an API.
Problem: Once the data table is loaded, I have used the Button's option show/hide columns but the problem is that I always receive the columns that are not in colspan or have exactly one column.
I wanted a solution where I could show/hide my column(s) based on my complex generated header.
Sample structure:
<table>
<thead>
<tr>
<th>Main Header</th>
<th colspan="2">Main Header 1</th>
<th colspan="5">Main Header 2</th>
<th colspan="3">Main Header 3</th>
</tr>
<tr>
<td>Sub Header</td>
<td>Sub Header 1</td>
<td>Sub Header 2</td>
</tr>
</thead>
<!-- DATA FOR TABLE GOES HERE -->
</table>
So basically my question is that I want to show/hide column based on my Main Header but when I initialize the show/hide feature of data table using Buttons, it always catches the sub headers and only those main headers whose colspan is 0.
Working fiddle: https://jsfiddle.net/k0afsmzt/
I am trying to show/hide columns based on Main Header(s) but the data tables plugin only shows the sub headers when you click the column visibility button.
You try to show/hide the columns but not the headers.
(I assume that because how would the user unhide the columns, if not?)
... there are also not enough examples for reference...
I agree. So I made something I hope you will like.
Since I found that playing with DataTable's column().visible() simply is not rendering the "hidden" columns including the headers, and that is causing more new issues that it solves... I found an alternative way to achieve something close to your needs.
In the demo below, I played with the CSS visibility property. An additionnal advantage is that the table keeps it's original width all the time.
Now on table draw triggered by pagination or search... The columns hiding may not be kept all the time... I'm leaving you that fun to test it out with some real data over more than one dataTable's page.
I think that is a good starter. I coded way more than I should have... Play with it and customize it to your taste. If there is some more issue arising, post another question including what you tried to fix.
Also on CodePen.
Please run the snippet below in full page mode.
$(document).ready(function() {
var myTable = $('#mytable').DataTable({
dom: 'Bfrtip',
buttons: [
'colvis'
],
"drawCallback": function( settings ) {
$("#mytable thead th").show();
}
});
$('#mytable').on("click","th",function(){
console.clear();
// Get the TH column "from"
var colFrom = parseInt($(this).data("col_from"));
//console.log(colFrom);
// Get the TH column "to"
var colTo = parseInt($(this).data("col_to"));
//console.log(colTo);
// Toggle the columns under the TH
for(i=colFrom;i<colTo+1;i++){
//myTable.column( i ).visible( !myTable.column( i ).visible() );
$("#mytable tbody tr").each(function(){
var TD = $(this).find("td").eq(i);
// Toggle visibility
var toggleCol = (TD.css("visibility")=="visible") ? "hidden" : "visible";
console.log("TOGGLING COL# "+i+" to "+toggleCol);
TD.css({"visibility":toggleCol})
});
}
});
});
table{
border:0px !important;
}
th,td{
border:1px solid black !important;
}
thead th{
cursor:pointer;
}
<!--link rel="stylesheet" type="text/css" href="/media/css/site-examples.css?_=19472395a2969da78c8a4c707e72123a"-->
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/buttons/1.5.2/css/buttons.dataTables.min.css">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.5.2/js/dataTables.buttons.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/buttons/1.5.2/js/buttons.colVis.min.js"></script>
<!-- Main Table Structure -->
<table id="mytable">
<thead>
<tr>
<th data-col_from="0" data-col_to="0">Main Header</th>
<th colspan="2" data-col_from="1" data-col_to="2">Main Header 1</th>
<th colspan="4" data-col_from="3" data-col_to="6">Main Header 2</th>
</tr>
<tr>
<td>Sub Header 0</td>
<td>Sub Header 1</td>
<td>Sub Header 2</td>
<td>Sub Header 3</td>
<td>Sub Header 4</td>
<td>Sub Header 5</td>
<td>Sub Header 6</td>
</tr>
</thead>
<tbody>
<tr>
<td>Sample Data 0</td>
<td>Sample Data 1</td>
<td>Sample Data 2</td>
<td>Sample Data 3</td>
<td>Sample Data 4</td>
<td>Sample Data 5</td>
<td>Sample Data 6</td>
</tr>
</tbody>
<!-- DATA FOR TABLE GOES HERE -->
</table>
I'm trying to dynamically set heights across all table headings based on the tallest corresponding div on its index. I will be using MaterializeCSS which responsively makes the headings display block and the content scroll right to left.
I'll use a super simple example.
<thead>
<tr>
<th>Heading 1</th>
<th>Heading 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>This content is 100px</td>
<td>This content is 50px</td>
</tr>
<tr>
<td>This content is 50px</td>
<td>This content is 200px</td>
</tr>
</tbody>
In the example I showed, I'd like to set the height of the th for heading 1 to 100px and the height of th for heading 2 to 200px.
I tried a few things and got completely lost. Maybe I was trying to get too cute with it. The logic I was attempting was:
For each th in thead
Find td with same index as the th within each tr within tbody and get largest height
Set height of th
I get that it would start with $('th').each(function () { //magic goes here });
Here is a Codepen I have to show my progress on it: https://codepen.io/hdwebpros/pen/vjbwyw
Thanks in advance for any help or guidance. I appreciate it!
You could do the following:
for each row tr
for each column td
compute the max height h[c] of every column with the same index
assign the max height to each column with the same index
var h = [];
$("#table tr").each(function(r, tr) {
$(tr).find("td").each(function(c, td) {
if (c == 0) {
h.push($(td).height());
} else {
if ($(td).height() > h[c]) {
h[c] = $(td).height();
}
}
});
});
for (var c = 0; c < h.length; c++) {
$("#table td:eq(" + c + ")").css("height", h[c]);
}
td {
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="table">
<thead>
<th>Heading 1</th>
<th>Heading 2</th>
</thead>
<tbody>
<tr>
<td style="height: 100px;">This content is 100px</td>
<td style="height: 50px;">This content is 50px</td>
</tr>
<tr>
<td style="height: 50px;">This content is 50px</td>
<td style="height: 200px;">This content is 200px</td>
</tr>
</tbody>
</table>
I have a list of names : first and last. The list is long, so I need to have a scroll bar menu. When I scroll, I should only scroll on the names and not on the column header.
I managed to do so but the problem is that the second column elements are not displayed right under the column name as you can see here http://jsfiddle.net/MmLQL/44/.
<table border=1 width=200px >
<tr>
<th>First Name</th>
<th>looong column name </th>
</tr>
</table>
<div class="div_scroll">
<table border=1 width=200px >
<tr>
<td>John</td>
<td>Smith</td>
</tr>
<tr>
<td>John</td>
<td>Doe</td>
</tr>
</table>
</div>
And even if I put the header and the content in the same table, and create a div to wrap the table content and add a class to that div to enable scrolling, it doesn't work http://jsfiddle.net/MmLQL/43/
What am I doing wrong?
You probably don't need javascript for this. Just set the widths of the columns to be equal. Here's a quick example:
th, td {
width: 50%;
}
View it on JSFiddle
You need to set the width of the columns to be the same for each table. Maybe create a css class for each column and apply them to the columns in the tables.
Example CSS classes:
.ColumnOne { width: 40%; }
.ColumnTwo { width: 60%; }
Then apply to the columns:
<table border=1 width=200px >
<tr>
<th class="ColumnOne">First Name</th>
<th class="ColumnTwo">looong column name </th>
</tr>
</table>
<div class="div_scroll">
<table border=1 width=200px >
<tr>
<td class="ColumnOne">John</td>
<td class="ColumnTwo">Smith</td>
</tr>
...
I am a relative newcomer to web programming, so probably I am making some obvious mistake here.
When I am trying to hide a row in a table from javascript like rows[i].style.display = 'none', the table layout is getting completely broken. Originally, the cell content was getting wrapped, and the table width was getting shrunk. I then added style="table-layout: fixed" in the table tag and style="white-space:nowrap" in each td. This stopped the line wrapping, but still the content was not aligned on a line. Cells started moving left if there is space and column width varied from one row to another. I then added a fixed width to each of the th and td element and also to the div containing the table. Still the problem remained.
My current HTML is something like the following.
<div style="width: 300px">
<table id="errorTable" width="100%" cellpadding="5" cellspacing="2" style="table-layout: fixed">
<tr id="HeaderRow">
<th style="width: 100px;">Header 1</th>
<th style="width: 50px;">Header 2</th>
<th style="width: 150px;">Header 3</th>
</tr>
<tr id="DetailRow1">
<td style="white-space:nowrap; width: 100px;">Data 1_1 in Row 1</td>
<td style="white-space:nowrap; width: 50px;">Data 1_2 in Row 1</td>
<td style="white-space:nowrap; width: 150px;">Data 1_3 in Row 1</td>
</tr>
<tr id="DetailRow2">
<td style="white-space:nowrap; width: 100px;">Data 2</td>
<td style="white-space:nowrap; width: 50px;">Data 2</td>
<td style="white-space:nowrap; width: 150px;">Data 2</td>
</tr>
<tr id="DetailRow3">
<td style="white-space:nowrap; width: 100px;">Data 3_1</td>
<td style="white-space:nowrap; width: 50px;">Data 3_2</td>
<td style="white-space:nowrap; width: 150px;">Data 3_3</td>
</tr>
</table>
</div>
When the table is displayed first time, the columns are aligned properly, with width 100, 50 and 150 px respectively. But if a row, say the second one is hidden, the cell width of the remaining two displayed rows are no longer fixed at 100, 50 and 150 and data is no longer aligned vertically. Please note that the overall table width remains 300 px. Data in each cell moves left if there is available space and the additional space is used by the last, in this case, third column.
The following post was helpful but did not solve my problem fully, as you can see.
Hiding table rows without resizing overall width
Any help will be most welcome.
The problem is the display type that you use to make the table-row visible.
To hide a table-row use display="none"
To show a table-row use display="table-row"
I did a sample so you can see these in action.
function show(){
document.getElementById('trB').style.display='table-row';
}
function hide(){
document.getElementById('trB').style.display='none';
}
#import url("https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css");
table{
border: 1px solid #ccc;
}
<table id="myTable" class="table table-striped table-hover">
<thead>
<tr>
<td>#</td>
<td>Letter</td>
</tr>
</thead>
<tbody>
<tr id="trA">
<td>1</td>
<td>A</td>
</tr>
<tr id="trB">
<td>2</td>
<td>B</td>
</tr>
<tr id="trC">
<td>3</td>
<td>C</td>
</tr>
</tbody>
</table>
<button id="showB" onclick="show()">show B</button>
<button id="hideB" onclick="hide()">hide B</button>
Hope this could help who are struggling with the same problem.
Instead of using display: none; I used visibility: collapse; for the hidden rows. This still keeps the width of the columns and the whole layout.
I had the same problem: I tried to hide a column by elem.style.display="none" but when showing again the layout was broken. This display-style worked for me:
columns.item(i).style.display = "table-cell";
Always fix the width of your columns. Would that sole your problem?
.myTable td{ width:33% !important; }
Ideally, you should also enclose header and body sections using thead and tbody
<table>
<thead>
<tr> ... </tr>
</thead>
<tbody>
.
.
.
</tbody>
</table>
I'm having the same problem. I threw a span inside of each table to see if I could force the width and it seems to work. It's ugly though.