DataTables / DataTables/Scroller

improved handling server side (option "serverWait")

Open
#34 6 comments 0 reactions 0 assignees View on GitHub

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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.