In the first week of the coding period, I spent more time studying for my end semester exams than working on the project itself. But I did work on clearing up some things that I had finished up beforehand.

In the community bonding period, I had worked on adding some basic functions that would detect when a user reaches the bottom of the table and then add the next set of rows to the table.

I initially used the jQuery scrollTop method to detect when the bottom of the table was reached. It looked something like this:

$(table.parentNode).bind('scroll', function(evt) {
    self._adjustDataTableScroll();
    scrollTop = $(this).scrollTop();
    if($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) {
      self._onBottomTable(table, this, evt);
    }
  });

The if condition would only be true when the user has scrolled to the bottom. Once that happens, a new function onBottomTable() is called. This function is quite similar to the onNextPage() function we use and looks like this:

DataTableView.prototype._onBottomTable = function(table, elmt, evt) {
  this._showRowsBottom(table, theProject.rowModel.start);
};

This would then call the showRowsBottom() method, which is similar to the present showRows() method with the only difference being the call for setScroll(). It looks like this:

DataTableView.prototype._showRowsBottom = function(table, start, onDone) {
  var self = this;
  this._totalSize += this._pageSize;
  Refine.fetchRows(start, this._totalSize, function() {
    self.render();

    setScroll();
    if (onDone) {
      onDone();
    }
  }, this._sorting);
};

This functions renders the data table again, with the additional number of rows. And then sets the scroll postion to where it was beforehand through the setScroll() method.

var setScroll = function() {
  $('.data-table-container').scrollTop(scrollTop);
};

The above work had been done in the community bonding period. I spent the first week of June cleaning up this code. The first function to change was the jQuery scrollTop to detect when the bottom was reached. It was better to wait for an element to come into view and then loading the next set of rows. So, I changed the function as follows:

$(table.parentNode).bind('scroll', function(evt) {
    self._adjustDataTableScroll();
    var element = document.querySelector('.load-next-set');
    var position = element.getBoundingClientRect();

    if(position.top >= 0 && position.bottom <= window.innerHeight) {
      console.log('Element is fully visible in screen');
      self._onBottomTable(table, this, evt);
    }
}

getBoundingClientRect() is a javascript method that keeps track of whether an element has come into view by keeping track of the associated position.top and position.bottom values. It made sense to load up the next set of rows a little before the bottom of the table, and hence the row with load-next-set class that it keeps track of is the 50th row from the end.

The next thing to change was the showRowsBottom() function which was re-rendering the entire data table instead of just loading up the next set of rows. To do that, I changed the loop that called renderRow for each row into a function and then called it inside showRowsBottom(). So it changed into this:

DataTableView.prototype._showRowsBottom = function(table, start, onDone) {
  this._totalSize += this._pageSize;
  $('tr.load-next-set').removeClass('load-next-set');

  Refine.fetchRows(start, this._pageSize, function() {
    table.deleteRow(table.rows.length - 1);

    loadRows();
    adjustNextSetClasses();

    if (onDone) {
      onDone();
    }
  }, this._sorting);
};

This loadRows() adds up the next set of rows into the table instead of creating the table again.

Another thing that I worked on was to make the scrollbar height reflect the size of the data set. Reading up about it, I found that a great way to do this is to add an empty row with a given height at the bottom of the table. This height would reflect the predicted height for the remaining data set.

this._sizeRowFirst = $('tr:eq(1)').height();
this._sizeRowsTotal = this._sizeRowFirst * theProject.rowModel.total;

window.adjustNextSetClasses = function() {

  var heightToAdd = self._sizeRowsTotal - ($('tr').length - 1) * self._sizeRowFirst;

  document.querySelector('.data-table').insertRow(self._totalSize);
  $('tr:last').css('height', heightToAdd);
  $('tr:last').addClass('last-row');

  $('tr:nth-last-child(50)').addClass('load-next-set');
}
adjustNextSetClasses();

What this does, is insert a row at the end of the table and apply the calculated height. The height isn’t accurate since it’s calculated using only the height of the first row. But with scrollbars, any change in height is automatically taken care of. So any small plus/minus change in the height would not be noticeable to the user. The heightToAdd is calculated by subtracting the height of the visible rows from the total expected height. This also adds the class load-next-set to the 50th row from the end.

Conclusion

So till now, scrolling in the downward direction loads up the next set of rows to add to the table. This, however, does not work for when a user scrolls too fast. And that’s because in that case, the element that we are waiting to come into view might never come into view as scrolling is done way too fast.