How to freeze header and left columns of the table - html

I want to fix header and 3 left columns of my table.
But I found only one suitable solution. Here is link: http://hazaa.com.au/blog/how-to-create-an-html-table-with-frozen-headers-and-columns/
I need to divide my table to 4 independent tables and that's not good.
Also I found plugin http://www.fixedheadertable.com/ (as suggestion in another such question on SO) unfortunately it can freeze only one left column (I need 3 columns).
Are there any other simple ways to implement this feature?

the standard html table does not support frozen columns, even with css.
if you can use a jquery plugin, i suggest you to use http://www.datatables.net/ with the fixedcolumns plugin (just configure and it works as supposed :) )
if not, you will end up with u solution where you havo to split up the table in the one or the other way, and if you want to have scrollable tables you will have to use javascript since css and html do not support such features yet.

Thought I'd share how I've done this. This code is surely somewhat based off other code found on this site but have long since lost exactly where. Requires jQuery. Potentially doesn't support various odd things you might want to do to a table.
<div class='tableFreeze'>
<table>
<thead>
<tr><th>Headers</th><th>Go</th><th>Here</th></tr>
</thead>
<tbody>
<!--table body stuff goes here-->
</tbody>
</table>
</div>
<style>
.tableFreeze {
width: 800px;
max-height: 500px;
position: relative;
overflow: scroll;
}
</style>
<script>
$(document).ready(function(){
//Sets a table to have frozen headers, or both headers and first column
//A div around the table must have a class of 'tableFreeze'
//can also add class 'tableFreeze_headersOnly' to the div to specify only headers should be frozen
//Table inside of div must have one thead and one tbody
//can set the div to have custom CSS defining the width and max height
$('.tableFreeze').each(function(){
var div=$(this);
//get the table in the DIV
var table=div.children('table');
// save original width to table object
var table_original_width=table.width();
//do the same for each td or th in the header
table.find('thead tr td,thead tr th').each(function(){
$(this).attr("data-item-original-width",$(this).width());
});
//do the same for the heights of each first cell on the left
var table_original_height=table.height();
table.find('tr').each(function(){
$(this).find('td,th').eq(0).attr("data-item-original-height",$(this).find('td,th').eq(0).height());
});
//need a copy of the table to strip away and make it just the header
var table_header=table.clone();
//set the whole copy of this table to have the proper width
table_header.width(table_original_width);
//set width of all cells in the header
table_header.find('thead tr td,thead tr th').each(function(){
$(this).width($(this).attr("data-item-original-width"));
});
//remove the tbody
table_header.find('tbody').remove();
//set the width and height of this header bar. add a header class
table_header.css({'width':table_original_width,'height':table_header.find("td,th").first().attr('data-item-original-height'),"position":"absolute","left":0,"top":0}).addClass('tableFreeze_header');
//add to div
div.append(table_header);
//if we have this class, we don't need to do the rest
if ($(this).hasClass('tableFreeze_headersOnly')) return;
//another copy of the table for just the left bar
var table_leftcol=table.clone();
//go through each row (in both tbody and thead)
table_leftcol.find('tr').each(function(){
//remove all but the first cell
$(this).children('td,th').slice(1).remove();
//set the height of each cell to be the original height
$(this).children('td,th').height(($(this).children('td,th').attr("data-item-original-height")*1)+1);
});
//set: the height of the whole table based on the original height we got, the width based on the width set of the first cell, absolutely position it on the left and right, and an id for finding later
table_leftcol.css({'height':table_original_height,'width':table_leftcol.find("td,th").first().attr('data-item-original-width'),"position":"absolute","left":0,"top":0}).addClass('tableFreeze_leftcol');
//add to div
div.append(table_leftcol);
//and finally a similar thing for just the top left cell (a1). That will need to always be on the top left.
var table_a1=table.clone();
//set copy to be original table width
table_a1.width(table_original_width);
//get the width and height of the a1 cell
var table_a1_width=table_a1.find("thead tr td,thead tr th").eq(0).attr("data-item-original-width");
var table_a1_height=table_a1.find("thead tr td,thead tr th").eq(0).attr("data-item-original-height");
//remove all but the first cell in the header
table_a1.find("thead tr td,thead tr th").slice(1).remove();
//and remove the entire tbody
table_a1.find('tbody').remove();
//set the first (and should be only remaining) cell to have the proper width/height
table_a1.find("thead tr td,thead tr th").eq(0).width(table_a1_width).height(table_a1_height);
//table positionin' stuff
table_a1.css({'width':table_a1_width,'height':table_a1_height,"position":"absolute","left":0,"top":0}).addClass('tableFreeze_a1');
//add to div
div.append(table_a1);
});
});
</script>

Related

How to remove padding and border from table cells?

I tried a lot of solutions that I have found here and in Google, but no one of them works.
The table is dynamically generated by jQuery and Javascript.
Question:
How can I remove the padding, border between the cells in this html table ?
This is the HTML code:-
<div class="board">
<table id="tableGame">
</table>
</div>
This is the Css Code
.board{
float:left;
display: inline-block;
}
table{
border-collapse: collapse;
}
table tr, td{
border: 0px;
}
Javascript Code below
function mapGenerate(){
var map=createMap(); // this function returns a 2d array filled of random 1 and 0
/* example
map = [[1,1,1,1,0],
[1,0,0,0,0],
[1,0,1,1,1],
[1,0,0,0,1],
[1,1,1,0,1]]
*/
//loop the 2d array map and change the number with the appropriate img
for(var i = 0; i < map.length; i++) {
var innerArrayLength = map[i].length;
for(var j = 0; j<innerArrayLength; j++){
//loop the nested arrays so i can change the 1 and the 0 with the appropriate img
if(map[i][j] === 0){
map[i][j]="<img class=\"walkble\" src=\"mapTiles/floorResized.png\">"; //you can walk this part of the map
}else{
map[i][j]="<img class=\"nonWalkble\"// you cannot walk This part of the map src=\"mapTiles/volcanoresize.png\">";
}
;
}
$("#tableGame").append("<tr><td>"+ map[i] + "</td></tr>") // Here i print the elements of the array
}
}
mapGenerate();
Link to jsfiddle under here.
The problem is not about the 3rd white line ( it only appears in js fiddle, if I open it in my browser they looking as a normal table).
The problem is only to delete that disturbing padding between the cells.
jsfiddle
In codepen you will see it better, without lines error.
codepen
looks like the problem is on line 80 of your javascript.
$("#tableGame").append("<tr><td>"+ map[i] + "<td></tr>")
you're concat-ing an array (map[i]) into a string. javascript by default "stringify" it by joining it with commas.
The code above is like:
$("#tableGame").append("<tr><td>"+ map[i].join() + "<td></tr>")
since the default joining string is comma, that's equivalent to
$("#tableGame").append("<tr><td>"+ map[i].join(',') + "<td></tr>")
To get rid of the commas you simply joining it with an empty string
$("#tableGame").append("<tr><td>"+ map[i].join('') + "<td></tr>")
In HTML, there are attributes border, cellpadding, and cellspacing on the <table> element. Set them to 0. <table border="0" cellpadding="0" cellspacing="0">.
Border is for the border width.
Cellpadding is for the padding in the table cells.
Cellspacing is for the space between the table cells.
css:
table { border-collapse: collapse; }
table td { padding:0; }

dynamically adding div's as columns in a row with Zurb Foundation

I am trying to dynamically add div's (which will be the target for jqplot graphs) to a tab panel using Foundation 6. I want the divs to be in a column layout in the row. I can get the divs in a row but each div ends up being in a row by itself instead of being a column element in the row.
I want this layout:
Layout I want
I have been using the code below to create the row div in the "graph1" panel:
var dynDivR1 = document.createElement("div");
dynDivR1.id = ("dynRow1");
dynDivR1.class = "row";
document.getElementById("graph1").appendChild(dynDivR1);
I then go into a loop to create the actual images (get the data, create the jqplot graph). Within the loop I create the graph div using the code below:
var dynDiv2 = document.createElement("div");
dynDiv2.id = ("dynDiv2" + divno2);
dynDiv2.class = "small-7 medium-3 large-3 columns";
dynDiv2.style.height = "200px";
dynDiv2.style.width = "200px";
dynDiv2.style.backgroundColor = 'white';
document.getElementById("dynRow1").appendChild(dynDiv2);
var plotInDiv2 = simplePlot(dynDiv2.id, lineDat2, sensorNames);
divno2 +=1;
simplePlot is a function that creates the graph using jqplot. This code works in the sense that divs are dynamically created, the graphs are placed in them. The problem I have is the layout: because I will have many graphs I want them in columns going across the page, not rows down the page (I will eventually have to have rows and columns but for now I am just trying to solve the column problem).
I tried removing the column width and height attributes in the image div but that also did not work (just got full width images / divs).
When I look at the resulting HTML the div's I have created do not seem to contain the class information. So for example the dynRow1 div looks like this (see actual HTML below):
<div id="dynRow1">
It does not have class = row attribute. When I look at the div (console.log) immediately after creation the class = row is there.
I tried inserting an additional column class div in the row like this (and then attach the plot div to that) but it did not work:
<div class="medium-6 columns">
I am stuck and would greatly appreciate any suggestions or pointers others can give.
Thank you very much.
Added 26/12/16 This is the HTML I am getting (I have not included the closing tags - they are there, the page loads and works without error in Firebug:
<div class="tabs-content" data-tabs-content="dy-tabs-2">
<div id="data1" class="tabs-panel" role="tabpanel" aria-hidden="true" aria-labelledby="data1-label">
<div id="graph1" class="tabs-panel is-active" role="tabpanel" aria-hidden="false" aria-labelledby="graph1-label">
<div id="dynRow1">
<div id="dynDiv21" class="jqplot-target" style="height: 200px; width: 200px; background-color: white; position: relative;">
<div id="dynDiv22" class="jqplot-target" style="height: 200px; width: 200px; background-color: white; position: relative;">
Then this is a clip of the screen shot of the resulting HTML
Clipped screen shot from HTML page
Thanks Again
Dear please check the snippet, i have added display:inline-block to your generated div, is this what you need ?
<div class="tabs-content" data-tabs-content="dy-tabs-2">
<div id="data1" class="tabs-panel" role="tabpanel" aria-hidden="true" aria-labelledby="data1-label">
<div id="graph1" class="tabs-panel is-active" role="tabpanel" aria-hidden="false" aria-labelledby="graph1-label">
<div id="dynRow1">
<div id="dynDiv21" class="jqplot-target" style="height: 200px; display:inline-block; width: 200px; background-color: orange; position: relative;"></div>
<div id="dynDiv22" class="jqplot-target" style="height: 200px; display:inline-block; width: 200px; background-color: black; position: relative;"></div>
</div>
</div>
</div>
</div>
Adding a row is <div class='row'> you have <div class='column row'>.
Using both column and row in the class creates a div that is a row 12 columns wide. Any new div columns you add will go to a new row.
Also, you will need to add the width (in grid blocks) that you want for your columns (up to 12 per row).
<div class='small-7 medium-3 large-3 columns'>
This code shows a column div that will be 7 grid spaces on small screen, 3 on medium and 3 on large.
Adding a new div should go as follows... (notice classList.add("row")):
// create a new ROW div
var dv = document.createElement("div");
dv.id = ("newDiv");
dv.classList.add("row");
Here is a codepen example of adding all the content to create a row with several columns and utilizing the foundation classes:
https://codepen.io/cmodesign/pen/woEpEd
http://foundation.zurb.com/sites/docs/grid.html
Thanks to Chris O for the useful suggestions. I have used Chris's suggestions as a basis for the following solution which works.
function staticPlots (selectDataSet) {
/* Function to create row and column div's for each variable in SelectDataSet and then plot
the data for each variable using jqplot line graph.
Temporary data in dataToPlot.
Temporary list of variables in selectVar
*/
// Temporary selection of variables to plot
selectVar = ["R1_","R2_","R3_","R4_","C1_","C2_","C3_","C4_","C5_","C6_","C7_","C8_","C9_","C10_","C11_","C12_"];
/* Create divs and place plots in them
First calculate the number of rows needed with four plots per row
lx is iterator to set unique col ids
*/
var x = selectVar.length;
var y = 4;
var z = Math.ceil(x / y);
var lx = 0;
for(var r=1; r<=z; r++) {
var dv = createRowColDivs();
dv.id = ("newRow"+r);
dv.classList.add("row");
document.getElementById("graph1").appendChild(dv);
var newCol;
for(var i=1; i<=4; i++) {
newCol = document.createElement("div");
newCol.classList.add("small-3");
newCol.classList.add("columns");
newCol.id = "col"+lx;
dv.appendChild(newCol);
var names = selectVar[lx];
// Temporary data for illustration so the database is not used
dataToPlot = [[1,4,5,6,8,2,3],[2,8,7,6,3,2,3]];
var plotInDiv2 = simplePlot(newCol.id, dataToPlot, names);
lx ++;
}
}
};
The createRowColDivs function just creates the row div so I can use it in other processes. Could easily have kept those processes in staticPlots function.
function createRowColDivs() {
// create a new ROW div
var dv = document.createElement("div");
dv.id = ("newDiv");
dv.classList.add("row");
return(dv);
};
This code gives me the row by column plot layout I was after.
Thanks Chris for the snippet that saw me on my way. One thing I had to change in your code was attaching the row div before I defined the col divs. it also took me way too long to figure out I needed to use lx to create unique id's for each plot.
Always appreciate suggestions for improving the code if anyone cares to.

list data in tabular layout

I want my data to have an html that is rendered something like (imagine the headers are aligned above the values)
header1 header2 header3
List item 1
value111 value112 value113
value121 valueb122 valueb123
List item 2
value211 value212 value213
value221 valueb222 valueb223
I want the values to be part of the list block, so I can show/hide the content (collapse) on click. Further, I want the width of each 'column' to be dynamically decided, to accommodate the longest value (perhaps with a min width)
Unfortunately, the HTML table model is so simple that it does not let you enter headers for row groups, which seems to be what the list items would need to be, more or less. We need to fake a little: we form row groups with the tbody element and use the first row in a group as a group header. That row will contain the header in one cell that spans all columns.
The following example has minimal styling and one (rather clumsy) way of making the row group headers controls that can be used so switch off and on the display of data rows in the group. This is just a demonstration to show that such things are doable without mixing list markup with table markup (and, for that matter, without using list markup at all).
function toggleData(el) {
el.parentNode.parentNode.className =
el.parentNode.parentNode.className ? '' : 'hide';
}
tbody > tr:first-child > td:before {
content: '\2022';
padding-right: 0.25em;
}
tbody.hide > tr:not(:first-child) {
display: none;
}
<table border cellspacing=0>
<thead>
<tr><th>header1 <th>header2 <th>header3
</thead>
<tbody>
<tr><td colspan=3 onclick="toggleData(this)">List item 1
<tr><td>value111 <td>value112 <td>value113
<tr><td>value121 <td>valueb122 <td>valueb123
</tbody>
<tbody>
<tr><td colspan=3 onclick="toggleData(this)">List item 2
<tr><td>value211 <td>value212 <td>value213
<tr><td>value221 <td>valueb222 <td>valueb223
</tbody>
</tabe>

How to apply CSS to 2x2 <td> classes?

I have HTML table with 5x5 cells. When hovering on any <td> I need to change the background of a 2x2 block of 4 cells. Here is the code to change the background in the current row.
td.1:hover, td.1:hover + td.1 {
background:#eee;
}
I don't know how to change the background in the row like this:
With CSS only, you could only affect the TD's children or next sibling. I.e., you could extend the background to the TD next to the one you hover but not on another row.
To do what you want to do, you would have to use JavaScript, as you would need to walk up and down the DOM, something CSS does not allow you to do.
To do this with jQuery, for example, try something like this:
$('td').hover(function () {
var t = $(this),
index = t.index(); // the position of the TD in the row, so you can find the one below it
t.addClass('hovered'); // apply hovered class to this TD...
t.next().addClass('hovered'); // ...and to the TD next to it...
t.closest('tr').next().find('td:eq(' + index + ')').addClass('hovered').next().addClass('hovered'); // ...and to the 2 below
}, function () {
// remove the hovered class when no longer hovering
$(this).closest('table').find('td').removeClass('hovered');
});
And in your CSS give whatever styling to the 'hovered' class you want.
DEMO 1
If, however, you want to change the background of the exact same 4 TDs every time you hover over any TD in the table, this can be done purely with CSS. Just give a class name to the 4 cells you want highlighted. Let's call this class 'block2x2' for example. Then your CSS is:
table:hover .block2x2 {
background: #eee; // whatever background style you want
}
DEMO 2

How can I set a <td> width to visually truncate its displayed contents?

I'm trying to set a column width of a table, which works fine until it gets to the point where child elements would be visually truncated ... then it won't size any smaller. ("visually truncated"-what doesn't fit appears to be hidden behind the next column)
Here is some sample code to demonstrate my problem:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<script language="javascript" type="text/javascript">
var intervalID = null;
function btn_onClick()
{
// keep it simple, only click once
var btn = document.getElementById("btn");
btn.disabled = true;
// start shrinking
intervalID = window.setInterval( "shrinkLeftCell();", 100);
}
function shrinkLeftCell()
{
// get elements
var td1 = document.getElementById("td1");
var td2 = document.getElementById("td2");
// initialize for first pass
if( "undefined" == typeof( td1.originalWidth))
{
td1.originalWidth = td1.offsetWidth;
td1.currentShrinkCount = td1.offsetWidth;
}
// shrink and set width size
td1.currentShrinkCount--;
td1.width = td1.currentShrinkCount; // does nothing if truncating!
// set reporting values in right cell
td2.innerHTML = "Desired Width : ["
+ td1.currentShrinkCount
+ "], Actual : ["
+ td1.offsetWidth + "]";
// Stop shrinking
if( 1 >= td1.currentShrinkCount)
window.clearInterval(intervalID);
}
</script>
</head>
<body>
<table width="100%" border="1">
<tr>
<td id="td1">
Extra_long_filler_text
</td>
<td id="td2">
Desired Width : [----], Actual : [----]
</td>
</tr>
</table>
<button id="btn" onclick="btn_onClick();">Start</button>
</body>
</html>
I've tried setting the width in different ways including
td1.offsetWidth = td1.currentShrinkCount;
and
td1.width = td1.currentShrinkCount + "px";
and
td1.style.width = td1.currentShrinkCount + "px";
and
td1.style.posWidth = td1.currentShrinkCount;
and
td1.scrollWidth = td1.currentShrinkCount;
and
td1.style.overflow = "hidden";
td1.width = td1.currentShrinkCount;
and
td1.style.overflow = "scroll";
td1.width = td1.currentShrinkCount;
and
td1.style.overflow = "auto";
td1.width = td1.currentShrinkCount;
I realize, I could probably use DIV's, but I'd prefer not to since the table is being generated from a bound control, and I don't really want to get into rewriting asp.net controls.
Having said that, I thought as a last ditch effort, I could at least wrap each 'td1's contents with a DIV, and the overflow would take care of things, but even replacing
<td id="td1">
Extra_long_filler_text
</td>
with
<td id="td1" style="overflow:hidden;">
<div style="margin=0;padding:0;overflow:hidden;">
Extra_long_filler_text
</div>
</td>
didn't work.
Does anybody know how I can set a width to visually truncate its contents?
BTW-My target browser is IE7. Other browsers are not important right now, since this is an internal app.
I just tried adding table-layout: fixed; to the <table> and it worked for me on IE7.
In a fixed table layout, the horizontal layout only depends on the table's width, the width of the columns, and not the content of the cells
Check out the documentation.
CSS Solution
"Truncate" may not be the word you are looking for. You may just want to hide the overflowing characters. If that is the case, look into the css-property "overflow," which will hide any content extending past the declared limits of its container.
td div.masker {
height:25px;
width:100px;
overflow:hidden;
}
<td>
<div class="masker">
This is a string of sample text that
should be hidden when it reaches out of the bounds of the parent controller.
</div>
</td>
Javascript Solution
If you are indeed wanting to truncate the text within the container, you will have to remove one character from the right, test the width of the parent, and continue to remove characters and testing the parent width until the parent width matches the declared width.
while (parent.width > desiredWidth) {
remove one char from right-side of child-text
}
<td id="td1" style="overflow-x:hidden;">
Should be
<td id="td1" style="overflow:hidden;">
overflow-x is a Microsoft CSS attribute, which is now part of CSS3. I would stick with the older overflow attribute.
EDIT:
As Paolo mentions you also need to add table-layout:fixed; and specify the width of the table. A full example follows.
<html>
<head>
<style>
table
{
table-layout:fixed;
width:100px;
}
td
{
overflow:hidden;
width:50px;
border-bottom: solid thin;
border-top:solid thin;
border-right:solid thin;
border-left:solid thin;
}
</style>
</head>
<body>
<table>
<tr><td>Some_long_content</td><td>Short</td></tr>
</table>
</body>
</html>
As far as I know, a table cell will always stretch to accommodate its contents.
Have you thought about using Javascript to dynamically truncate the data in table cells that have more than a certain amount of content? Alternatively, you could do this more easily server side.
You could use jQuery or plain javascript to surround the content of your cell(s) with div tags and set a fixed width and overflow:hidden on those instead. Not beautiful, but it'd work.
ETA:
<td><div style="width:30px;overflow:hidden">Text goes here</div></td>
Since the DIV is the bounding element, that's where the width should be set.