Scroll Position in a Table Body - javascript

I want to implement infinite scrolling (with an AJAX-based loader) in an HTML table body.
My HTML looks something like this:
<table>
<thead>
<tr><th>Column</th></tr>
</thead>
<tbody>
<tr><td>Row 1</td></tr>
<tr><td>Row 2</td></tr>
</tbody>
</table>
I get a scroll bar on the <tbody> like so:
tbody {
height:10em; /* Otherwise the tbody expands to fit all rows */
overflow:auto;
}
To be able to do anything when the user scrolls to the bottom, I need to be able to get the scroll position of the <tbody>. In all of the (jQuery) infinite scroll implementations I've seen (such as this one), they subtract the content height from the container height and compare it to the .scrollTop() value.
Unfortunately this may not work with <tbody>, which is both the viewport and the container for the scrolled content. $("tbody").height() returns the viewable (ie: "shrunken") size, but I don't know how I can get the full (viewable + hidden) size of the table body. (FWIW, $("tbody").scrollTop() returns a "large" number when scrolled to the bottom, exactly as I would expect it to).
Is there any way to accomplish this?

tbody.scrollHeight works for me.

When you need the hidden height you can set the height to auto, grab it, then return the height to the forced size.
var $tbody = $('tbody');
var initTbodyHeight = $tbody.height();
$tbody.css('height','auto');
var autoTbodyHeight = $tbody.height();
$tbody.css('height',initTbodyHeight);
Even IE should process this fast enough without any flicker visible to human eyes.

Related

jquery get real table height when tbody has lot of elements

I have a <table> element with a lot of rows and a max-height attribute.
I need to find the real height displayed for the <tbody> element. Normally I can just take the difference between <table> height and <thead> height
var tbodyDispalyHeight = $("table").height() - $("thead").height();
This works unless horizontal content is too much and an horizontal scrollbar appears (and can't remove it because... I need it!). I should remove its height from tbodyDispalyHeight but... how can I do?
First problem: I don't really know when this bar is displayed
Second prolbem: Each browser implement scrollbar in a different way
Here is a JSBIN example to understand what I mean. Try to resize page horizontally until the scrollbar appears, there the dislayed tbody height should be lower...
Sounds like you are looking for the clientHeight.
(But this seems to be to easy.)
Have a look to MDN
The Element.clientHeight read-only property is zero for elements with no CSS or inline layout boxes, otherwise it's the inner height of an element in pixels, including padding but not the horizontal scrollbar height, border, or margin.
You may try:
$("table")[0].clientHeight
Currently you have your table with overflow:auto. But you could wrap it with a DIV with "overflow:auto". Then you can simply determine if you have a horizontal scrollbar by comparing the width of your div with the width of your table.

Forcing <table> Columns to a Fixed Width; Prevent Automatic Expand

I generally set fixed column widths via CSS with flawless results:
#tableID thead tr th:nth-child(1){width: 75px;}
#tableID thead tr th:nth-child(2){width: 75px;}
/* etc… */
But now I'm in a situation where I won't know the desired column widths until runtime. Here's an excerpt from the code I'm using to dynamically set the column widths:
var tr=$("<tr>");
var colArr=Home.ColDefs[this.statBatchType].colArr;
for(var i=0;i<colArr.length;i++){
var col=colArr[i];
tr.append(
$("<th>")
.html(col.title)
.css("width",col.width)
);
}
this.jqTHead.append(tr);
Sorry this code is a bit out of context but the bottom line is that I'm adding columns, represented by <th> elements, to a table header and setting each one's width.
What ACTUALLY happens, however, is that Firefox is treating the column width as a minimum and then automatically expanding the column width as the user expands his browser window. Consider a case where my JavaScript code sets the width of each column to 75px. Firefox will ensure each column is at least 75px wide, but if the user maximizes (or enlarges) his browser, provided there is sufficient room, each column will be automatically widened.
This is odd to me since the JavaScript code would seem to be the functional equivalent of what I was doing in CSS. Yet the CSS approach doesn't cause this odd behavior.
Any thoughts?
Fix the width of the <table> this will ensure the table does not take the available size and bump the layout.
table-layout: fixed; on the table does exactly this: columns never expand to fit their contents, and if you give the table itself a width, the extra space is divided equally. The contents of cells don't come into play at all.

need sticky header and footer when content is too large

I created a custom table using div's (was only solution due too complex behaviour). But I have a problem with the header and the footer.
The table htmlis basically simple:
<div class="table">
<div class="header"></div>
<div class="content"></div>
<div class="footer"></div>
</div>
What I need is the following: when the content inside the table is not too large to be viewed without scrollbar the header will just be at the top and the footer just below the content (so not sticky to the bottom of the container).
But when the content of the table expands (either on page load with new data or by expanding some table content using javascript/jQuery) I need the header to stick at the top of the container and the footer stick at the bottom of the container while the content can scroll without overlapping the header/footer.
I searched around a lot on this but haven't found a decent solution, is there a way to solve this (as simple as possible) using css and/or javascript/jquery?
Edit
Here a basic sample of what I mean: jsFiddle
If you click the span in the example the header and footer should become fixed at the top and bottom of the container. But how do I detect the increase in size?
.offset() + .scrollTop() = DISCO
Basically (jsfiddle demo):
function placeHeader(){
var $table = $('#table');
var $header = $('#header');
if ($table.offset().top <= $(window).scrollTop()) {
$header.offset({top: $(window).scrollTop()});
} else {
$header.offset({top: $table.offset().top});
}
}
$(window).scroll(placeHeader);
In other words, if the top of the table is above the scrollTop, then position the header at scrollTop, otherwise put it back at the top of the table. Depending on the contents of the rest of the site, you might also need to check if you have scrolled all the way past the table, since then you don't want the header to stay visible.
And don't forget about $(window).height() for doing the same with the footer.
This is a complete violation of the language's semantics, and as a result it likely completely destroys all accessibility. Use an HTML table instead.
<table id="mahTable" summary="some descriptive summary">
<caption>This descriptive data visually appears outside your table.</caption>
<thead>
<tr><th>Header Cell</th><th>Other header cell</th></tr>
</thead>
<tbody>
<tr><td>data 1</td><td>data 2</td></tr>
</tbody>
<tfoot>
<tr><td colspan="2">footer here</td></tr>
</tfoot>
</table>
To say this is not possible in your current code/programming means you entirely need to rethink your approach. Get the HTML correct first and then figure out presentation later. If you are too busy fretting over presentation before you have addressed the needs or structure of your content then your presentation will likely fail anyways.

How to increse the size of td1 whout affecting td2?

I am work on outlook designing in my menu page.
In that I have done the drag the td and height of td (id="leftContent") is increase, but problem is when I increase the height of td (id="leftContent") then automatically increase the height of td2(id="RightContent").
So how to increse the the height of only left td without affecting the right content.
My sample table code
<table>
<tr>
<td id="leftContent"></td> <!--This is just sample code because original code is very long and in left and right -->
<td id="RightContent"></td> <!--content have many table and TD and tr-->
</tr>
</table>
This is the table html markup.
I tried to solve this problem by taking both td in separate div tags
as following:
<div>
<td id="leftContent">
<div>
<div>
<td id="RightContent">
<div>
but this did not even work .
I tried to change position like absolute, relative, static, and fixed, apply all the property to right content but when I drag the td then automatically increasing the height of right content with left content.
This is just the way tables work. tds within a given tr are always the same height.
(I assume that the lack of closing tags in your example is just an oversight.)

Scrolling a table with multiple fixed table headers

Before I attempt to reinvent the wheel (via jQuery plugin or similar), I'm trying to see if there is an easier way to do this or an existing plugin that users may know of. What I'm looking to do is scroll the body of a table that contains multiple table headers. For example, imagine something of this structure:
<table>
<thead>
<tr>
<td colspan="2"></td>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
</tr>
</tbody>
<thead>
<tr>
<td colspan="2"></td>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</tbody>
</table>
Honestly, I haven't tried out the above syntax to even see if its valid. The actual markup I have does not currently use thead/tbody and instead scrolls the whole parent div (seen below).
What I want to achieve is scrolling of the whole table such that the header of the most relevant section is viewed on top. Currently the header scrolls out of view is there are enough rows.
I know the various techniques used to scroll a table with one header, but what about multiple? Are there any existing ways to achieve this? I'm open to different ideas, but right now I'm thinking of simply displaying the most relevant table header for the content on top.
A few months ago, I wrote some code that did exactly that where I wanted the headers to perform similar to section headers on iOS.
Utilising a Jquery, the solution I ended up with involved creating an onScroll (and onResize for window resizing) event listener that ran a check through all $('table thead') and checked their $(this).position() on the page.
The check was whether the thead had a position which was above the top of the current viewport.
Once I had found the most relevant header (the bottommost thead that was above the viewport), I created a new table, with position: fixed at (0, 0) and copied into it a new column for each column of the headers rows and manually set its width properties to match the original table.
I have put together a Proof of Concept which shows how this all works.
Here is some pseudo-code of how it works:
Check the table is visible
Get a list of all thead sections in the table
Reverse the list
Find the first thead in the array with a top position less than scrollTop of the body element
If we found one:
Create deep copy of the thead
Make a container table
Copy attributes from the original table so the styles get copied
Position the container at [0, originalTable.left]
Set the width equal to the outerWidth of the original table
Set the width of every td found to the width of the matching td from the original table
Add it to the DOM
If none found, remove the existing container from the DOM if there was one
There are some other edge case details that made this even nicer too:
Instead of (0, 0), the origin point for the fixed row was altered based upon whether the "real" header row for the tbody below the one with the fixed header should be pushing it away.
Ensure that previous header rows are deleted before making a new one
Don't recreate the header row if the header you'd be making is the same as what is already there
This approach worked a lot better others I tried such as trying to position:absolute an object due to the fact that Firefox and IE aren't incredibly fast at running the onScroll handler so you tend to see 'juddering'. I also tried mucking with the position attribute of the theads, this just ended in the table column widths jumping about and not matching the data.
thead nodes aren't strictly required for this solution as you can use some other selector to determine which rows are headers etc.
Update: Added example code and pseudo-code
Update: Dropbox changed their system, replaced example with jsfiddle URL

Categories

Resources