DataTables logo DataTables

via Ad Packs
Scroller behavior for variable-height table
  • EnigmaEnigma
    Posts: 2
    Hello Allan,

    First off, thanks for a fantastic plugin; really impressive work. I recently switched out infinite scrolling in favor of the Scroller plug-in, but have experienced some unusual behavior for a variable-height table. When I scroll to the bottom of my table, it periodically fails to render the last few rows. My guess is that this is due to the way I have the sScrollY value configured, as the table may not be triggering the last re-render.

    Table Settings:
    "sScrollY": 800,
    "bAutoWidth": false,
    "bDeferRender": true,
    "bFilter": true,
    "bSort": true,
    "fnRowCallback": function (nRow, aData) {
        // Customer column class
        jQuery("td:eq(4)", nRow).addClass("name_column");
    },
    "fnInitComplete": function () {
        // Adjust scroll areas for table
        adjustTable();
    }
    

    If I understand the plug-in correctly, the sScrollY value of 800px is used for the initial scrolling calculation and represents 1/3 of the scrollable area (for a total of 2400px.) If every row in my table is set to a static height of 80px and I want to render 30 rows, then the height of the sScrollY should be 800. Each time the scroll breaks the 1600px mark, an additional 800 pixels are rendered, while the first 800 are "forgotten."

    The resize function called during the InitComplete callback, used to adjust the display area of the table to match the container:
    adjustTable = function () {
      var wrapperHeight = jQuery("#BlockList_Table_wrapper").height();
      var headerHeight = jQuery(".dataTables_scrollHead").height();
      var infoPadding = 20;
      var infoHeight = jQuery("#BlockList_Table_info").height() + infoPadding;
     
      // Adjust scroll area
      jQuery(".dataTables_scroll").height(wrapperHeight - infoHeight);
      jQuery(".dataTables_scrollBody").height(wrapperHeight - headerHeight - infoHeight);
    	        
      // Adjust column sizing
      bController.bList.fnAdjustColumnSizing();
    };
    

    I wouldn't think this resize would affect the scrolling calculation, but I could definitely be wrong. If you (or anyone reading this) could provide some insight, it would be much appreciated. I don't have a mock-up of the table on hand, but would be happy to explain further if my explanation wasn't clear enough.

    Thanks in advance,
    Quinn
  • allanallan
    Posts: 15,537
    I recently switched out infinite scrolling in favor of the Scroller plug-in, but have experienced some unusual behavior for a variable-height table.

    This won't work I'm afraid. As noted on the Scroller "home page" ( http://datatables.net/extras/scroller/ ):

    Note that rows in the table must all be the same height. Information in a cell which expands on to multiple lines will cause some odd behaviour in the scrolling.

    This blog post has more details about how Scroller works: http://datatables.net/blog/Introducing_Scroller_-_Virtual_Scrolling_for_DataTables

    Allan
  • EnigmaEnigma
    Posts: 2
    Hello Allan,

    Thanks for the quick response. Via CSS, I've set all rows to a static height, whereas the table itself is resizable. I'd expect the Scroller calculation would still be fine in this case?

    Thanks,
    Quinn
  • allanallan
    Posts: 15,537
    Yes - as long as all rows are the same height, then that's absolutely fine.

    Allan
  • jcreadyjcready
    Posts: 44
    Hey Allen, I have a similar issue with Scroller's calculation of the visible portion of the table's height.

    I'm making a full page media library (like iTunes) and because I always want the application to fill the entire page I have two divs (#top and #middle) absolutely positioned. The #top div has
    top: 0; right: 0; left: 0; height: 72px
    and the #middle div has
    top: 72px; right: 0; bottom: 0; left: 0
    so that both divs completely fill the screen.

    My DataTable is inside #middle with
    "yScroll" : $("#middle").height()+"px"
    but only WebKit seems to be correctly filling the entire page with rows. Firefox only appears to be filling about half of that space. I think it has to do with the fact that #middle is absolutely positioned and that it doesn't have an explicitly set height property. I'm guessing that's the issue because it worked fine when I wasn't absolutely positioning the table's wrapper, but it's kind of confusing because after looking through oTable.oOptions I can see a "y" property that is correctly set to 870px (the height of #middle). So it clearly is getting the correct height value, but it's not respecting it.

    Any ideas?
  • allanallan
    Posts: 15,537
    Can you link me to your page so I can investigate a bit please?

    Do you have the elements as display:none on initial load?

    Allan
  • jcreadyjcready
    Posts: 44
    In the HTML I have a <table> element with just the header row inside the <thead>. I am populating the DataTable's "aaData" with data stored in localStorage (if it exists). If the data does not exist in localStorage, I make an XHR request to the server and receive back an array of objects. I then parse the data myself into the aaData format I want, save that aaData to localStorage and finally initialize the DataTable with the "aaData" property set.

    Here is all the options I'm initializing it with:

    dom.oTable = $("#list").dataTable({
    
    	"aaData": Temp.aaData,							// Arrays
    	"aaSorting": [[0,'asc'], [2,'asc'], [1,'asc']],
    	"aoColumnDefs": [
    		{ "sType": "song",  "aTargets": [ 0, 1, 2, 3 ] },
    		{ "sType": "numeric", "aTargets": [ 4, 5, 6, 8 ] }
    	],
    	"aoColumns": [
    		{ "sName": "artist", "sClass": "artist" },
    		{ "sName": "title", "sClass": "title" },
    		{ "sName": "album", "sClass": "album" },
    		{ "sName": "genre", "sClass": "genre", "bSortable": false },
    		{ "sName": "dev-origin-id", "sClass": "source", "bSearchable": false, "bSortable": false, "bVisible": true },
    		{ "sName": "length", "sClass": "length", "bSearchable": false, "bVisible": true, "fnRender": function (oObj) { return hhmmss(oObj.aData[oObj.iDataColumn]); }, "bUseRendered": false },
    		{ "sName": "playcount", "sClass": "plays", "bSearchable": false, "bVisible": true },
    		{ "sName": "idhash", "bSearchable": false, "bVisible": false },
    		{ "sName": "art", "bSearchable": false, "bVisible": false }
    	],
    
    	"oScroller": {									// Objects
    		"serverWait": 100,
    		"trace": false
    	}
    
    	"bScrollAutoCss": true,							// Booleans
    	"bDestroy": true,
    	"bInfo": false,
    	"bAutoWidth": true,
    	"bDeferRender": true,
    	"bProcessing": false,
    	"bRetrieve": true,
    	"bStateSave": true,
    
    	"iScrollLoadGap": 100,							// Integers
    	"iDisplayLength": 200,
    
    	"sDom": "RtrS",									// Strings
    	"sScrollY": $('#middle').height()+'px',
    													// Functions
    	"fnStateSave": function (oSettings, oData) { localStorage.setItem('oData', JSON.stringify(oData)); },
    	"fnStateLoad": function (oSettings) { return JSON.parse(localStorage.getItem('oData')); },
    });

    The (LESS) CSS for the portions of the page:

    @navbarHeight: 72px;
    
    #top {
    	position: absolute;
    	top: 0; right: 0; left: 0;
    	height: @navbarHeight;
    	box-shadow: 0 -1px 0 black inset, 0 -2px 0 rgba(255,255,255,.2) inset;
    }
    
    #middle {
    	position: absolute;
    	top: @navbarHeight; right: 0; bottom: 0; left: 0;
    
    	div#list_wrapper {						// DataTable wrapper
    		width: 100%;
    		height: 100%;
    
    		.dataTables_scroll {				// Scroller wrapper
    			.box-sizing(border-box);		// Adds vendor prefixes
    			width: 100%;
    			height: 100% !important			// Override inline styles
    			position: relative;
    		}
    
    		.dataTables_scrollHead {			// Faux fixed header wrapper
    			position: absolute;
    			z-index: 99999;
    			height: 33px;
    			overflow: visible;
    
    			.dataTables_scrollHeadInner {	// Inner wrapper for header
    				width: 100% !important;		// Override inline styles
    			}
    		}
    
    		.dataTables_scrollBody {			// Real table with tbody content
    			height: 100% !important			// Override inline styles
    			
    			thead { display: none }			// No need to have two header rows
    		}
    
    		td.plays,							// Force correct widths for columns
    		td.length,
    		td.source  { width:  6% !important; }
    		td.genre   { width: 10% !important; }
    		td.album   { width: 24% !important; }
    		td.title   { width: 24% !important; }
    		td.artist  { width: 24% !important; }
    
    		th.plays,							  // Could do this in one step if DataTables
    		th.length,							  // used <col>s inside a <colgroup>
    		th.source  { width:  6% !important; } // by only setting the width on each <col>
    		th.genre   { width: 10% !important; }
    		th.album   { width: 24% !important; }
    		th.title   { width: 24% !important; }
    		th.artist  { width: 24% !important; }
    	}
    }
  • jcreadyjcready
    Posts: 44
    Still don't know why it's only rendering in half the available space on Firefox, but I made a one line change in Scroller.js within the fnMeasure function:
    this.s.viewportHeight = $("#middle").height();
    Obviously, that isn't a solution worth committing, but it fixed my problem.
  • allanallan
    Posts: 15,537
    Interesting - thanks for the feedback on this. Good to hear that you've got a fix hat works for you with this. I'll try to replicate the problem in my test environment and see if I can find a fix.

    Allan
This discussion has been closed.
← All Discussions

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Support

Get useful and friendly help straight from the source.

In this Discussion