Fixed html table header while scrolling - javascript

I have the following table structure:
<table>
<thead>
<tr>
<th colspan="4">Current</th>
<th colspan="4">New/Requested</th>
</tr>
<tr>
<th nowrap="nowrap">RSD </th>
<th nowrap="nowrap">CRSD </th>
<th nowrap="nowrap">MSD </th>
<th nowrap="nowrap">Open QTY </th>
<th nowrap="nowrap">CRD </th>
<th nowrap="nowrap">CRSD </th>
<th nowrap="nowrap">MSD </th>
<th nowrap="nowrap">Open QTY </th>
<th nowrap="nowrap">Action</th>
<th nowrap="nowrap">Reason</th>
<th nowrap="nowrap">Action Code Status </th>
</tr>
<tbody>
<tr>
<td></td>
<td></td>
.....plenty of rows
</tr>
</tbody>
</thead>
</table>
I am trying to fix the header so that if I scroll down it stays visible.
I looked at this post but couldn't understand it. How can I do this?

I have written the following code in order to achieve my goal (as asked in question)-
Here is the plugin i have written.
(function ($) {
$.fn.scrollbarTable = function (i) {
var o = {};
if (typeof (i) == 'number') o.height = i;
else if (typeof (i) == 'object') o = i;
else if (typeof (i) == 'undefined') o = {
height: 300
}
return this.each(function () {
var $t = $(this);
var w = $t.width();
$t.width(w - function (width) {
var parent, child;
if (width === undefined) {
parent = $('<div style="width:50px;height:50px;overflow:auto"><div style="height:50px;"></div></div>').appendTo('body');
child = parent.children();
width = child.innerWidth() - child.height(99).innerWidth();
parent.remove();
}
return width;
}());
var cols = [];
var tableCols = [];
$t.find('thead th,thead td').each(function () {
cols.push($(this).width());
});
$t.find('tr:eq(1) th,thead td').each(function () {
tableCols.push($(this).width());
});
var $firstRow = $t.clone();
$firstRow.find('tbody').remove();
$t.find('thead').remove();
$t.before($firstRow);
$firstRow.find('thead th,thead td').each(function (i) {
$(this).attr('width', cols[i]);
});
$t.find('tr:first th,tr:first td').each(function (i) {
$(this).attr('width', tableCols[i]);
});
var $wrap = $('<div>');
$wrap.css({
width: w,
height: o.height,
overflow: 'auto'
});
$t.wrap($wrap);
})
};
}(jQuery));
How to use:
$(document).ready(function(){
$('table#tabss').scrollbarTable();
}
hope it will help someone somewhere..
Any way thanks to all of you for your kind support... :)

try this approach but it may not be the best way
<table style="top: 0px; position: fixed; z-index: 1; background-color: White">
<tr>
<th colspan="4">Current</th>
<th colspan="4">New/Requested</th>
</tr>
<tr>
<th nowrap="nowrap">RSD </th>
<th nowrap="nowrap">CRSD </th>
<th nowrap="nowrap">MSD </th>
<th nowrap="nowrap">Open QTY </th>
<th nowrap="nowrap">CRD </th>
<th nowrap="nowrap">CRSD </th>
<th nowrap="nowrap">MSD </th>
<th nowrap="nowrap">Open QTY </th>
<th nowrap="nowrap">Action</th>
<th nowrap="nowrap">Reason</th>
<th nowrap="nowrap">Action Code Status </th>
</tr>
</table>
<table>
<tbody>
<tr>
<td></td>
<td></td>
.....plenty of rows
</tr>
</tbody>
</table>
what I did is just created another table for header and gave it fixed position

Using css
.fixhead
{
position:relative
overflow:auto;
}
And call this class in or in gridview headerrowstyle tag.

CSS PART----
<style type="text/css">
thead tr { position:relative;
top: expression(offsetParent.scrollTop);
}
</style>
HTML PART----
<table width="100%" border="0" cellpadding="0" cellspacing="0" align="center">
<thead>
<tr>
<td width="1%"></td>
<td>ID</td>
<td>Name</td>
</tr>
</thead>
<tbody>
//////////code
</tbody>
<tfoot>
////////code
</tfott>
</table>
Thanks

Set overflow: auto in the tbody's css.

so I had to create a similar component for my work. (Note: admittedly I did this with jQuery but it can still be accomplished without it.)
The solution i came up with was similar and i thought i'd share it as it is much simplier
http://jsfiddle.net/YYaFr/6/
Basically you wrap the table in a div, copy it (the table) and make the first one just a header table (by removing the tbody) and position it absolute.
<div class="containerdiv">
<table class="headerTable">
<colgroup>
<col /> * number of columns
....
</colgroup>
<thead>
<th></th>
....
</thead>
</table>
<table class="dataTable">
<colgroup>
<col /> * number of columns
....
</colgroup>
<thead>
<th></th>
....
</thead>
<tbody>
<td></td>
....
</tbody>
</table>
</div>
and the css
div.containerDiv
{
height: 300px; // Whatever height you need. can be set inline if you wish
}
div.containerDiv table.headerTable
{
position: absolute;
}
div.containerDiv table.dataTable thead
{
visibility: hidden; // This gives the header table room so it doesn't hide the first row.
}
Then the JavaScript basically creates the colgroups (or you can generate them server-side if you need.) Sets the widths and viola. That seems a lot simpler in my head so go ahead and check out the jsfiddle.

I know that I'm late to the party, but the jQuery Fixed Table Header Plugin by Mustafa OZCAN is fantastic. Just include it, as well as jQuery itself, and set it to work on your table like so:
<script type="text/javascript">
$(document).ready(function() {
$('#YourTable').fixedtableheader();
});
</script>
Replace #YourTable with the ID of your HTML table, and the plugin does the rest.

Alas, how I envy people who get to use jQuery. I created a pure javascript and CSS solution for those who are prevented by application limitations from loading a library.
Basically, CSS positions the table and table header row, and tricks the table into behaving like divs. Then javascript manipulates the CSS positioning of the table header row and a "mask" div that hides the moving rows as the table scrolls up (an improvement would be to modify the javascript to detect collision and hide rows that scroll up past the header).
The weakness of this approach is that you now have to set the widths for all the columns.
The relevant components are:
<!-- divs with IDs are manipulated with javascript -->
<div class="fixedTableHolder">
<div class="maskHolder">
<div id="mask" class="mask"> </mask>
</div>
<div class="fixedTable">
<div id="theTable" class="theTable">
<!-- here is the table, header row must have an ID -->
<table border="0" cellspacing="5" cellpadding="5">
<tr id="thFixed" class="thFixed">
<td class="col1">Header cell 1</td>
</tr>
<tr>
<td class="col1">regular cell</td>
</tr>
</table>
</div>
</div>
</div>
Here is a demo in jsFiddle: http://jsfiddle.net/deborah/Msvvr/

Well, hoping someone will be reading this, and save some time with it :)
My goal was to make a small(as small as possible) js, that will take tableID , and put headers as fixed.
It differs from what is given here with that it recalculates width with window.resize, so it allows tables to be resized dynamically, and no fixed sizes used from the start. And in theory - suppose to work with any table... (that was my case...)
function HeadsUp()
{
var headers = $("#TheGrid tr").first();
headers.css("margin-top", ((headers.height()+1)*-1)+"px");//edit +1 with what you want...
headers.css("position", "absolute");
}
function ResizeHeaders()
{
var grid = $("#TheGrid");
var headers = $("#TheGrid tr").first();
var firstdatarow = $("#TheGrid tr:nth-child(2)");
headers.width(grid.width());
var s = firstdatarow.children("td");
var d = headers.children("th");//replace with td if you use it there
for(i=0; i<s.length; i+=1) {
d[i].width = s[i].clientWidth;
}
}
$(function () {
HeadsUp();
ResizeHeaders();
});
$( window ).resize(function() {
ResizeHeaders();
});

The best option which worked for me is adding the following css properties to the th class in stylesheet.
th
{
position: -webkit-sticky;
position: sticky;
top: 0px;
z-index: 5;
}

Related

one of the columns in my table is a short paragraph, if it's too long it needs to be abbreviated and expandable with just css js no jquery [duplicate]

This question already has answers here:
Limit text length to n lines using CSS
(17 answers)
Closed 10 months ago.
logic:
If comment exists and not enough room → display comment with abbreviation "..." and a new dropdown button that extends row on click.
Not sure how this logic could be achieved, searches return js libraries instead. Complete newbie :(
Currently when there's too much text in one section the entire row becomes vertically wider. The html code is nothing fancy with no js:
'''
<thead class="thead-dark">
<tr>
<th class = "time_header">Time</th>
<th class = "date_header">Date</th>
<th class = "type_header">Type</th>
<th class = "value Header">Value</th>
<th class = "comment_header">Comment</th>
</tr>
</thead>
<tbody>
{{#each userHistoryData}}
<tr>
<td>{{convert2Time this.date}}</td>
<td>{{convert2Date this.date}}</td>
<td>{{this.type}}</td>
<td>{{this.value}}</td>
<td>{{this.comment}}</td>
</tr>
{{/each}}
</tbody>
</table>
'''
Maybe you can truncate the text by doing something like this so you have an idea. then call the max-width on media screen so they fit on the size you want. Let me know if this is the one you mean. This is the example only since I dont have all your code
td {
max-width: 300px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
td:hover {
white-space:break-spaces;
overflow:visible;
}
#media only screen and (max-wdith:768px){
td {max-width: 300px;}
}
#media only screen and (max-wdith:680px){
td {max-width: 100px;}
}
<table>
<thead class="thead-dark">
<tr>
<th class = "time_header">Time</th>
<th class = "date_header">Date</th>
<th class = "type_header">Type</th>
<th class = "value Header">Value</th>
<th class = "comment_header">Comment</th>
</tr>
</thead>
<tbody>
{{#each userHistoryData}}
<tr>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>THIS is just a sample comment and I want it to fit on my table THIS is just a sample comment and I want it to fit on my tableTHIS is just a sample comment and I want it to fit on my table THIS is just a sample comment and I want it to fit on my table</td>
</tr>
{{/each}}
</tbody>
</table>

HTML: Anchor in table

I was trying to make a table with anchor clickable rows. My first try was this:
<table>
<body>
<table>
<thead>
<tr>
<th>Id</td>
<th>Name</td>
<th>Address</td>
</tr>
</thead>
<tbody>
<a href="https://google.com">
<td> 1 </td>
<td> Google </td>
<td> https://google.com </td>
</a>
</tbody>
</table>
</body>
</table>
When I inspected the result in Chrome and Edge I noticed that the browsers had decided to split the anchor out and throw it behind the table!
So, this is my first question: Why do browsers manipulate the HTML structure?
My second try was using JavaScript:
var tbody = document.getElementsByTagName('tbody')[0];
var anchor = document.createElement("a");
anchor.href = "https://google.com"
var td = document.createElement('td');
td.innerHTML = "1"
anchor.appendChild(td);
td = document.createElement('td');
td.innerHTML = "Google";
anchor.appendChild(td);
td = document.createElement('td');
td.innerHTML = "https://google.com";
anchor.appendChild(td);
tbody.appendChild(anchor);
th {
width: 30%;
text-align: left;
}
a {
display: table-row;
text-decoration: none;
color: black;
}
<body>
<table>
<thead>
<tr>
<th>Id</td>
<th>Name</td>
<th>Address</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
</body>
It works like a charm: the entire row is clickable.
But I don't get why this time, the browsers don't manipulate with DOM? This is my second question.
Any helpful explanation is appreciated.
Why do browsers manipulate the HTML structure?
Because your HTML is invalid.
A <tbody> element is only allowed <tr> children.
The parsing rules browsers follow describe how to deal with invalid HTML in that way.
But I don't get why this time, the browsers don't manipulate with DOM?
The browser isn't building the DOM using the HTML parsing algorithm.
You are manually creating a DOM that represents invalid HTML.
you can able to redirect using data-href="your-link.com"
you can not modify any <table> element but you want to redirect on tr click
Please check working demo
HTML CODE
<table>
<body>
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Address</th>
</tr>
</thead>
<tbody>
<tr class="link" data-href="https://stackoverflow.com/">
<td> 1 </td>
<td> Google </td>
<td> https://google.com </td>
</tr>
</tbody>
</table>
</body>
CSS CODE
td,th{
border:1px solid #ddd;
}
tbody tr:hover{
color:red;
cursor: pointer;
}
table{
border-collapse: collapse;
}
jQuery CODE
$(document).ready(function(){
var link = $(".link").attr("data-href");
$('.link').click(function(){
window.location.href=link;
})
});
So you want the table rows clickable going to a link in that row.
Don't wrap the row with an a tag. It's invalid, and at best will result in unpredictable results.
You will need javascript to make this work. Add an event listener to the table rows. Check for a well formed a tag and redirect to its href attribute.
//Get rows
let rows = document.querySelectorAll(".clickRows tbody > tr");
for (i = 0; i < rows.length; i++) {
//Add Event listener to row
rows[i].addEventListener("click", function() {
//If there is a link
if (this.querySelector("a[href]")) {
//Redirect to it
window.location.href = this.querySelector("a[href]").href;
} else {
console.log("No Link");
}
})
}
th {
width: 30%;
text-align: left;
}
<table class="clickRows">
<thead>
<tr>
<!-- You had mismatched th and td tags here -->
<th>Id</th>
<th>Name</th>
<th>Address</th>
</tr>
</thead>
<tbody>
<tr>
<td> 1 </td>
<td> Google </td>
<td>https://google.com</td>
</tr>
<tr>
<td> 2 </td>
<td> Ding </td>
<td>Ding</td>
</tr>
</tbody>
</table>
If you are willing to drop the HTML table
/*Displat as table*/
.clickRows {
display:table;
width:30%;
}
/*Set appropriate children as rows*/
.clickRows > div, .clickRows > a
{
display:table-row;
}
/*Then set the cells*/
.clickRows > div > div, .clickRows > a > div
{
display:table-cell;
}
.head {
font-weight: bold;
}
<div class="clickRows">
<div class="head">
<!-- You had mismatched th and td tags here -->
<div>Id</div>
<div>Name</div>
<div>Address</div>
</div>
<a href="https://google.com">
<div> 1 </div>
<div> Google </div>
<div>https://google.com</div>
</a>
<div>
<div> 2 </div>
<div> Ding </div>
<div>Ding</div>
</div>
</div>
On a side note your HTML as provided is quite broken. body is not a valid child element for table. Opening and closing td and th must match. For more info on what is and isn't valid for table and it's associated elements, see MDN

How to freeze header table in datagrid, using EasyUI + JQ?

In the listing of orders this table is formed:
<div class="datagrid-header">
<div class="datagrid-header-inner" style="display: block;">
<table class="datagrid-htable" border="0" cellspacing="0" cellpadding="0" style="height: 65px;">
<tbody>
<tr class="datagrid-header-row">
<td field="calculation_id" class="">
This table is like a thead of table below. So oddly creating of grid table from jquery.easyui.js. I need to freeze this header table. Using frozenColumns as written in the manual does not work - becouse in the manual frozenColumns is applied to the usual type of table:
<thead>
<tr>
<th data-options="field:'code'">Code</th>
<th data-options="field:'name'">Name</th>
But what can I do here?
I've solved the problem using JQ:
$(window).scroll(function() {
if ($(window).scrollTop() >= 165) {
$('.datagrid-header').addClass('fixed');
} else {
$('.datagrid-header').removeClass('fixed');
}
});
.fixed {
position: fixed; top: 0;
}

bootstrap-table: th - add on the left an icon

anyone has an idea how to add something to the left in the bootstrap-table header? Like on the picture below I want to add an icon (question mark or whatever) to be a clickable link.
jsFIDDLE
<table id="summaryTable">
<thead>
<tr>
<th data-field="id" data-align="center" data-width="20px" >id</th>
<th data-field="name" data-align="center" data-sortable="true">Name</th>
<th data-field="type" data-align="center" data-sortable="true">type</th>
</tr>
</thead>
</table>
You can add an element to every th:
$('#summaryTable thead th').each(function() {
s = $('<span style="position: absolute; left: 4px; top: 8px; cursor: pointer;">?</span>')
s.click(function(e) {
e.stopPropagation();
alert('Question mark clicked')
});
$(this).append(s)
})
Note the e.stopPropagation(); to make sure the clicks on the question mark will not cause also a click on the entire TH
Here is a fork of your jsfiddle:
https://jsfiddle.net/dekelb/e403uvuh/

Using empty() on tbody keeps resizing width of entire table

I am using jQuery to reload data inside the tbody. However, the header column width keeps resizing event though I put the fixed width for the columns. I am using Firefox.
Simple HTML table:
<table style="width:95%;" border="1" align="center" >
<thead>
<tr>
<td class="header" style="width:20%">ProductFamily
<select onchange="selectCategoryChange()">
<option "1">1</option>
<option "2">2</option>
</select>
</td>
<td class="header" style="width:20%">ProductNum</td>
<td class="header" style="width:30%">ProductDesc</td>
<td class="header" style="width:5%">DT Rate</td>
<td class="header" style="width:5%">List Rate</td>
<td class="header" style="width:5%">Man Hour Unit</td>
<td class="header" style="width:5%">Precall</td>
<td class="header" style="width:5%">SOW</td>
<td class="header" style="width:5%">Box</td>
</tr>
</thead>
<tbody id="tbodyDataRow">
<!-- Data Rows Here -->
</tbody>
</table>
When the tbody.empty(), it automatically resizes the width of the header columns, which make the page looks ugly. and then when I reload the new rows, it resize it back to original width. Here is my Jquery code.
$(document).ready(function() {
selectCategoryChange = function()
{
var tbody = $("#tbodyDataRow");
tbody.empty();
};
});
This works, but I've not tested it in all browsers. Change HTML to:
<table border="1" align="center">
<thead>
<tr>
<th>ProductNum</th>
<th>Product</th>
<th>DT Rate</th>
<th>List Rate</th>
<th>Man Hour Unit</th>
<th>Precall</th>
<th>SOW</th>
<th></th>
</tr>
</thead>
<tbody id="tbodyDataRow">
<!-- tbody Content -->
</tbody>
</table>
You should avoid inline styles anyway. Add this CSS file:
table {
border: 1px solid black;
}
.header {
background-color: #ccc;
font-weight: bold;
min-width: 200px;
}
That'll fix your problem, but again it's not cross-browser tested. You might consider allowing the resize.
Final result Fiddle
Your table style="width:95%;" is the problem. You are expecting a table with 8 X 200px = 1600px width, but your table should has 95% as width, which can be more or less than 1600px. If it be deferent, the headers will be ajusted automatic. I'm sorry about my english.
I had a similar problem with empty() function applied on ul element.
HTML structure :
<table>
<tr>
<td>
<ul id="list"></ul>
</td>
<td>
...
</td>
</tr>
I have a JS timer which call an ajax function responsible to refresh the content of the list (ul). To update the list (ul) I started to empty it with the following code:
$("#list").empty();
At each iteration, the column width was incremented even if content was the same. I finally replaced the content by the initial content by using replaceWith function and this time it was ok:
$("#list").replaceWith('<ul id="list"></ul>');

Categories

Resources