I am trying to implement a table structure in which the header remains fixed when i scroll down. I have used 2 tables for this purpose. The first table has the header values and the second table have the corresponding data(length of data in each column might vary as the data is populated dynamically). The problem is that the header width and data column width are not matching exactly.
I have written some code like shown below to dynamically alter the column width
$('#tdCheckAllBody').width($('#tdCheckAllHead').width());
$('#tdLoginBody').width($('#tdLoginHead').width());
$('#tdStatusBody').width($('#tdStatusHead').width());
$('#tdFNameBody').width($('#tdFNameHead').width());
$('#tdLNameBody').width($('#tdLNameHead').width());
$('#tdCompBody').width($('#tdCompHead').width());
But it doesnt seem to work properly. Any help appreciated.
Use this method
$(window).scroll(function(){
$("#id of the table header").offset({top:$("#id of the control which u placed the scrolling").scrollTop()});
});
Created a working fiddle for this:
http://jsfiddle.net/terjeto/dx7H5/
Offcourse if your case is different, you might need to tweak a litle. In my opinion the problematic areas are if the table use dynamic or % width and coping with the "auto" scrollbar which takes up approx 18px, and offcourse if the table needs horizontal scrollbars it complicates things a litle needing the onscroll event.
Could it be that your exmple is not accurate because of lacking reset-css code?
I use this: http://developer.yahoo.com/yui/reset/
Related
This is a continuation of my previous post found here.
The fixed headers work fine but I'm having a problem on initial load.
When the table first loads it looks like this:
But then once I click on of the column heads to sort it by that value everything snaps into place and ends up looking like this:
Like I said in my previous post, I'm using the anguFixedHeaderTable plugin. The headers stick fine but I'm just getting this glitch. I can provide details on all the resources I use in this project if that helps to debug the problem. I can provide more info but I just don't know what to provide at this point.
Additionally, when I click on the column to sort the list the table flickers in that it expands to full size before coming back to a height of 300px with a scroll bar. If I click it a few more times it sorts without any table flickers. If I click on a new column header to sort by that it again flickers once but a few more clicks of the same header results in a smooth and clean ordering. Any idea what's causing this flicker?
Edit 1:
Based on Code Wizard's advice I took the working code from the demo and put it into the github .js file. Here's what I have now:
function tableDataLoaded() {
// first cell in the tbody exists when data is loaded but doesn't have a width
// until after the table is transformed
return $elem.find("tbody").is(':visible');
/*var firstCell = elem.querySelector('tbody tr:first-child td:first-child');
return firstCell && !firstCell.style.width;*/
}
This actually works perfectly on first load. The only problem is I have two tables that the user can switch between with a click of a button. Those tables are controlled with a simple ng-show expression to detect which view the user selected. So when the table first loads, the look exactly like they should in both views. But then if you keep toggling back and forth the columns start messing up again. Until you click the column to sort it, then it snaps back into place.
Edit 2:
I tried going the css route and I mostly got it working. Only problem is the columns are slightly misaligned. The main issue is that the columns widths aren't dynamic. Here's a plunker to reproduce my issue. As you can see, the first row's first column content spills into the adjacent column. I want the columns to be dynamic and aligned
Since i dont have your code i can only try to help you out by pointing out some issues that might cause this problem.
When HTML engine render out tables it has to loop over all the cells and to calculate the max width of each cell in order to find the max width per table column.
The anguFixedHeaderTable use this code:
function tableDataLoaded() {
// first cell in the tbody exists when data is loaded but doesn't have a width
// until after the table is transformed
var firstCell = elem.querySelector('tbody tr:first-child td:first-child');
return firstCell && !firstCell.style.width;
}
And this function is fired here:
// wait for data to load and then transform the table
$scope.$watch(tableDataLoaded, function(isTableDataLoaded) {
if (isTableDataLoaded) {
transformTable();
}
});
If the table is not loaded yet when this code is executed the table will "fix" its width and it will use the default width which the HTML engine set to it.
What i suggest to do in order to fix it is to load the table and only After its loaded (to be sure that the function is called after the table was loaded) is to use java script code which will append the directive to the table of to re-write this module to fix this issue.
Updates after playing with the code and trying to fix the problem.
Note
On the demo site the code is different than the one in GitHub
Demo code:
- http://pointblankdevelopment.com.au/plnks/angularjs-fixed-header-scrollable-table-directive/app.js
GitHub code
- https://github.com/cornflourblue/angu-fixed-header-table/blob/master/angu-fixed-header-table.js
And the difference is this:
# The working code in the demo
$scope.$watch(function () { return $elem.find("tbody").is(':visible') },
# The "buggy" code on git hub
// wait for data to load and then transform the table
$scope.$watch(tableDataLoaded,
function(isTableDataLoaded) {
if (isTableDataLoaded) {
transformTable();
}
}
);
Grab the code from the demo and it will work as expected.
Good Luck.
have you try adding width:100%; in table and tr ?
table,tr {
width:100%;
}
Demo here
Your issue is mostly fixed, and I think you just need to apply fixes from CSS to complete it. How about we wrap the first column like this:
table tr th:first-child, table tr td:first-child{
word-wrap: break-word;
white-space: inherit!important;
}
Preview on Plunker
The TDs in your table are already responsive, we just need to modify to make the content is not overflow by applying the wrap in every th, td that you might think it would happen.
The above code I applied it to the first child, but you can customize to entire table.
Try adding this CSS:
.table {
width: 100%;
height: 200px;
}
Please see this modified CodePen: CodePen for fixed Header & Footer
I have dynamic data in my table. The amount of data in a cell may change. I have implemented a rowHeightGetter method to calculate the height of a row. When I add content to a cell and rerender my table, the content appears and the cell is larger, but if the additional content caused overflow, scrollbars do not show up. Please see the jsfiddle and click on a row. You'll see that you can no longer access the bottom row of the table until you click a second time.
https://jsfiddle.net/3cooper/ed7Ltc6o/1/
It appears that _calculateState() is not getting the actual row heights from the rowHeightGetter methods when it calls
var scrollContentHeight = this._scrollHelper.getContentHeight()
At this point it is getting the height of the rows by checking the rowHeight property on the table. I see in _calculateState() there are other calls that eventually call this._scrollHelper._updateHeightsInViewport() to properly get the height. Should this be done again. Just really started looking into this today - so I could be missing something obvious. Thanks.
Is there a better way to handle this?
Update:
Also, I notice that once a scrollbar appears so that the contents can scroll, if you click a row again, the table with shift down but the scrollbar will not adjust. Then once you start to scroll up the scroll jumps to the correct position and allows you to scroll the entire table correctly.
I realize this question has been asked quite a bit on Stack Overflow; however, after looking through a number of them, I believe my question has one more requirement. I want to transform a regular html table, into a table that can be scrolled both vertically and horizontally, while the the header remains at the top. The width of this table exceeds the width of the page, so I need the headers to move horizontally as the table is scrolled. I would prefer to use a pure CSS method; however, I will use Javascript if necessary. Have yet to find a solution that does all of this.
This solution might work for you depending on the style of your headers. It's pure CSS.
http://salzerdesign.com/blog/?p=191
Why would you not just use a and set a height and width for it allowing overflow. Then just simply place your table in there and you are good to go.
To me that just seems like the most logic and easiest way to go about it...
well you can use JQuery to do this in few lines of code,
you can see my other post to create a table with fix header
and scrollable body
Create Table with scrollable body
after that lets imagine you have one div for the headers with class name = "Top1" and one div for the body with class name = "Top2", you can bind the scroll of one to the other
$('.Top2').bind('scroll', function(){
$(".Top1").scrollLeft($(this).scrollLeft());
});
$('.Top1').bind('scroll', function(){
$(".Top2").scrollLeft($(this).scrollLeft());
});
jsFliddle demo
Here is a good jQuery plugin, working in all browsers! (check out the demo)
The result is a table with a fixed header, scrolling (for the moment..) only vertically, but with a variable width.
I develop this plugin to meet the problem of fixed header + flexible width.
Check it: https://github.com/benjaminleouzon/tablefixedheader
Has anyone been able to implement a scrollable table in HTML where the TOP row and LEFT columns are frozen, but the rest of the table is scrollable? A perfect example of this is:
Google Squared
I tried to reverse engineer the code for the google squared table, but I have been unsuccessful so far.
Note: I need the ability to FREEZE the TOP ROW and the LEFT COLUMN at the same time.
There's a working example at http://ajaxian.com/archives/freeze-pane-functionality that should be easy to duplicate. Be sure to note the comments -- many of the users have made helpful suggestions for improving the script.
Per #Nirk's request, a direct link to the active demo is at http://www.disconova.com/open_source/files/freezepanes.htm.
Go with a basic structure like this-
table
row
column (blank)
column
table (1 row high, column headers)
row
column
table (1 column wide, row headers)
column
div (fixed height & width, overflow auto)
table (actual data)
Set a fixed table-layout and specify column widths in pixels explicitly. You should be able to achieve the same effect.
i have a version of this in use (for a Gantt-chart style display).
it uses 3 tables: 1 for left column (the rows), 1 for top (columns), and then the data.
you need to work hard to get the cells to match sizes with the ones they match up to (
table layout-fixed can help achieve this).
The tables then are placed in some divs; the left and top divs have (as suggested above) height & width and overflow-auto in their css.
You then hook up some javascript to sync the scrolling of the left / top divs with the inner one...
As I recall there was a fair bit of 'curse-and-try-again', but it can be done with minimal js.
hth
If you use jQuery there's a lot of plugins for tables with fixed head.
You need Scrollable (jQuery plugin)
Demo is here
I have table with multiple rows, showing items for sale. When the user clicks on a row, a Javascript inserts / shows a new row right beneath it with details about the item. The issue is when the description is long, it forces the column widths to readjust / resize. This shifts the columns positions and is really annoying, especially for the user. Right now, I have my table.style.tableLayout: auto. I actually prefer it this way, because the columns are adjusted to the content.
My question is: how do I dynamically "lock" the widths of the columns in my table so that when I insert / show the new row, the columns do not readjust / resize?
I've tried:
dynamically setting the table to temporarily "tableLayout: fixed"
inserting / showing my new row
changing the table back to "tableLayout: auto"
Actions 1 & 2 works in in FireFox, but not in Safari and IE (6 & 7). However, doing all three seems to prevent the columns from shifting too much.
The frustration is unbearable ... loosing lots of sleep ... please help!
Thanks.
For those looking for the code (this is done in jQuery). This also assumes the first row has the proper widths for each cell. Pretty easy changes if needed.
$('table.class_of_table_to_fix tr:first td').each(function() {
$(this).css({'width': $(this).width()+"px"});
});
I would set a percent width on each column simply as a guide. Set it just once on the TH of each column. The browser will still adjust the columns to content if necessary, but the columns will stay in place more consistently.
Next, I would never put css "white-space:nowrap" anywhere on that table. A long description should not break the table layout, it should wrap around properly on multiple lines, and be readable if you set the widths on each column to suit the type of data. Similarly I would keep the use of (non breakable spaces) to dates, times and numbers and allow the text to wrap.
Other than that, I do this at my job on a dialy basis, and there's a time when you need to stop ulling hairs asking the browser to do something it's not designed to do. Content should flow and adapt. Locking column widths to pixels is 99.99999% of the time a bad idea.
PS: If you really, reeally, REALLY need to lock columns, the only solution I'm aware of that works with CSS2 and accross all browsers is to use images. You could insert a 1px high transparent gif image in each column, and counting in the padding of the cells (TD), set a pixel width on each image (IMG), instead of on the columns (TH/TD). You could hide those in the TH for example. You can leave the images at 1 pixel wide and set percent widths on TDs, and when you open a new row, you would get each column width minus TD Padding, and set that to the corresponding IMG. I haven't tried! I just know that in many projects I've worked on, I've used small gif images to lock a minimum vertical spacing between columns, for example.
I had a similar problem when I was implementing a table with groups that could be toggled. I wanted the initial ratio between the columns to stay the same without fixing the widths of the columns. By default the browser would change the widths depending on the visibility of the table's rows, which was undesirable.
I went ahead and followed #faB's suggestion of applying percentages, but doing so using a small script that would calculate the percentages of the th elements and apply them after the initial render. This made my columns stay the same width, even with all rows hidden.
Here's the script, which uses jQuery:
(function($){
var lock_widths = function() {
var total_width = $('table').innerWidth();
var headers = $('table th');
var leftover = 100;
$.each(headers, function(ix, el) {
var header = $(el), width;
// on the last call use the leftover percentage
if (ix == headers.length - 1) {
width = leftover;
} else {
leftover -= width = header.outerWidth() / total_width * 100;
}
header.css({'width': width + '%'});
});
};
$(document).ready(lock_widths);
})(jQuery);
Tested in IE7+, Firefox and Chrome. This works for my special case because I have header columns as a reference, but it could be rewritten to measure some other columns.
You can display the details of the row beneath the clicked one in DIV and set its
style="overflow:auto";
so that details will wrap and scrollbar will be available to display entire text.
I don´t know if you´re familiar with jquery, but that´s what I would use - in combination with a separate class for the column that´s causing resizing in the new row - to:
Calculate / get the with of the column
Set the with of the afore mentioned class
Add the row
I haven´t tried it, but that should do it.
By the way, there are probably other ways to do it, I´m just more familiar with jquery (for point 1. and 2.).