DataTables / DataTables/Scroller
improved handling server side (option "serverWait")
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 83
- Forks
- 66
- PR merge metrics
- No merged PRs in 30d
Description
Hello,
I have an improvement propsal.
Having table with data loaded from server. When user quickly scrolls the table and scrolls out of rendered data, nothing is rendered and thus visible until he stops scrolling for at least "serverWait" milliseconds. This is very uncomfortable. Lowering "serverWait" time to may cause too much pending ajax requests and thus long waing time (for user).
I propose to improve this situation by loading new data and rendering (i.e. calling dt.oApi._fnDraw) immediately after getting outside of trigger boundary, but not before the previous ajax request is finished. Next data are loaded when user scrolls outrside of trigger boundary of newly rendered data.
For that purpose I propose following _fnScroll function.
Added lines begin "++", removed lines begin "--"
"_fnScroll": function ()
{
var
that = this,
heights = this.s.heights,
iScrollTop = this.dom.scroller.scrollTop,
iTopRow;
if ( this.s.skip ) {
return;
}
if ( this.s.ingnoreScroll ) {
return;
}
/* If the table has been sorted or filtered, then we use the redraw that
* DataTables as done, rather than performing our own
*/
if ( this.s.dt.bFiltered || this.s.dt.bSorted ) {
this.s.lastScrollTop = 0;
return;
}
/* Update the table's information display for what is now in the viewport */
this._fnInfo();
/* We don't want to state save on every scroll event - that's heavy
* handed, so use a timeout to update the state saving only when the
* scrolling has finished
*/
clearTimeout( this.s.stateTO );
this.s.stateTO = setTimeout( function () {
that.s.dt.oApi._fnSaveState( that.s.dt );
}, 250 );
/* Check if the scroll point is outside the trigger boundary which would required
* a DataTables redraw
*/
if ( iScrollTop < this.s.redrawTop || iScrollTop > this.s.redrawBottom ) {
var preRows = Math.ceil( ((this.s.displayBuffer-1)/2) * this.s.viewportRows );
if ( Math.abs( iScrollTop - this.s.lastScrollTop ) > heights.viewport || this.s.ani ) {
iTopRow = parseInt(this._domain( 'physicalToVirtual', iScrollTop ) / heights.row, 10) - preRows;
this.s.topRowFloat = (this._domain( 'physicalToVirtual', iScrollTop ) / heights.row);
}
else {
iTopRow = this.fnPixelsToRow( iScrollTop ) - preRows;
this.s.topRowFloat = this.fnPixelsToRow( iScrollTop, false );
}
if ( iTopRow <= 0 ) {
/* At the start of the table */
iTopRow = 0;
}
else if ( iTopRow + this.s.dt._iDisplayLength > this.s.dt.fnRecordsDisplay() ) {
/* At the end of the table */
iTopRow = this.s.dt.fnRecordsDisplay() - this.s.dt._iDisplayLength;
if ( iTopRow < 0 ) {
iTopRow = 0;
}
}
else if ( iTopRow % 2 !== 0 ) {
// For the row-striping classes (odd/even) we want only to start
// on evens otherwise the stripes will change between draws and
// look rubbish
iTopRow++;
}
if ( iTopRow != this.s.dt._iDisplayStart ) {
++ // if data are loaded from server
++ if (this.s.dt.oFeatures.bServerSide) {
++ clearTimeout(this.s.drawTO);
++ // if most current ajax call loading DataTable data is not finished
++ if (this.s.dt.jqXHR && this.s.dt.jqXHR.readyState != 4) {
++ // try again after "serverWait" milliseconds
++ this.s.drawTO = setTimeout( function () {
++ that._fnScroll();
++ }, this.s.serverWait);
++ return;
++ }
++ }
/* Cache the new table position for quick lookups */
this.s.tableTop = $(this.s.dt.nTable).offset().top;
this.s.tableBottom = $(this.s.dt.nTable).height() + this.s.tableTop;
var draw = function () {
if ( that.s.scrollDrawReq === null ) {
that.s.scrollDrawReq = iScrollTop;
}
that.s.dt._iDisplayStart = iTopRow;
if ( that.s.dt.oApi._fnCalculateEnd ) { // Removed in 1.10
that.s.dt.oApi._fnCalculateEnd( that.s.dt );
}
that.s.dt.oApi._fnDraw( that.s.dt );
};
++ /* Do the DataTables redraw based on the calculated start point */
-- /* Do the DataTables redraw based on the calculated start point - note that when
-- * using server-side processing we introduce a small delay to not DoS the server...
-- */
-- if ( this.s.dt.oFeatures.bServerSide ) {
-- draw();
-- clearTimeout( this.s.drawTO );
-- this.s.drawTO = setTimeout( draw, this.s.serverWait );
-- }
-- else {
draw();
-- }
if ( this.dom.loader && ! this.s.loaderVisible ) {
this.dom.loader.css( 'display', 'block' );
this.s.loaderVisible = true;
}
}
}
this.s.lastScrollTop = iScrollTop;
this.s.stateSaveThrottle();
},
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the Scroller _fnScroll function and trace its server-side draw and jqXHR handling. The change is done when scrolling outside the trigger boundary redraws promptly after the previous request finishes, while serverWait retries remain effective; verify this with the project's server-side scrolling behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, typescript
- Domain
- frontend
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100