Javascript Library to create scrollable table with infinite rows and columns.

Overview

Fattable

Demo

Checkout the demo here.

What is it?

Fattable is a javascript Library to create table with infinite scroll, with infinite number of rows and number of columns.

Big table (more 10,000 cells) don't do well with DOM. Your scroll will start getting choppy.

Also big tables can rapidly grow in sizes. It is not always possible to have clients download or even retain all of the table data. Fattable includes everything required to load your data asynchronously.

This library is

  • light : no library needed, smaller than 10KB)
  • fast (only visible element are in DOM, the exact same DOM element are recycled over and over, )
  • async friendly : the API makes it simple to fetch your data aysnchronously.
  • powerful and unbloated : Design is up to you. Style the table via css and use your painter to hook up events, and render your content in your cell.

API

var table = fattable({
  "painter": painter,    // your painter (see below)
  "model": model,          // model describing your data (see below)
  "nbRows": 1000000,     // overall number of rows
  "rowHeight": 35,       // constant row height (px)
  "headerHeight": 100,   // height of the header (px)
  "columnWidths": [300, 300, 300, 300] // array of column width (px) 
})  

Painter

painter is an object which role is to fill the content of your cells, and columnHeaders. It is expected to implement the following interface.

var painter = {
    
    "setupHeader": function(headerDiv) {
        /* Setup method are called at the creation
           of the column header. That is during
           initialization and for all window resize
           event. Columns are recycled. */
    }
,
    "setupCell": function(cellDiv) {
        /* The cell painter tells how 
           to fill, and style cells.
           Do not set height or width.
           in either fill and setup methods. */
    }
,
    "fillHeader": function(headerDiv, data) {
        /* Fills and style a column div.
           Data is whatever the datalayer
           is returning. A String, or a more
           elaborate object. */
        colHeaderDiv.textContent = data;
    }
,
    "fillCell": function(cellDiv, data) {
        /* Fills and style a cell div.
           Data is whatever the datalayer
           is returning. A String, or a more
           elaborate object. */
        cellDiv.textContent = data;
    }
,
    "fillHeaderPending": function(headerDiv) {
        /* Mark a column header as pending.
           When using an asynchronous.
           Its content is not in cache
           and needs to be fetched */
        cellDiv.textContent = "NA";
    }
,
    "fillCellPending": function(cellDiv) {
        /* Mark a cell content as pending
           Its content is not in cache and 
           needs to be fetched */
        cellDiv.textContent = "NA";
    }
};

Actually this very simple implementation is the default. And it is available as fattable.Painter, so that you can just override it.

DataLayer

Synchronous Data Layer

Demo

If your data is not too big, you probably can just fetch your data all at once, and then display the table. For this simple use case, the best is probably to extend the SyncTableData object.

You just need to extend fattable.SyncTableModel and implement the following methods

{
  "getCellSync": function(i,j) {
    return "cell " + i + "," + j;
  },
  "getHeaderSync": function(i,j) {
    return "col " + j;
  }
}

Asynchronous and paged async model

Demo

You probably don't want your backend to receive one request per cell displayed. A good solution to this problem is to partition your table into pages of cells.

Queries are only sent when the user stops scrolling.

To use such a system, you just have to extend the PagedAsyncTableModelclass with the following methods. In addition, it include a simple LRU cache.

{
  "cellPageName": function(i,j) {
      // returns a string which stands for the id of 
      // the page the cell (i,j) belongs to.
      var I = (i / 128) | 0;
      var J = (j / 29) | 0;
      return JSON.stringify([I,J]);
  },
  "fetchCellPage": function(pageName, cb) {
      // Async method to return the page of 
      var coords = JSON.parse(pageName);
      var I = coords[0];
      var J = coords[1];
      getJSON("data/page-" + I + "-" + J + ".json", function(data) {
          cb(function(i,j) {
              return {
                  rowId: i,
                  content: data[i-I*128][j-J*29]
              };
          });
      });
  },
  "headerCellPage" : function(j) {
   // Same as for cellPageName but for cells.
  },
  "fetchHeaderPage" : function(j) {
    // Same as for fetchCellPage but for headers
  }
}

Custom async model

If you want to go custom, you can implement your own data model, it just has to implement the following methods :

{
  hasCell: function(i,j) {
    // returns true if getting the data of the cell (i,j )
    // does not require an async call false if it does need it.
  },
  hasHeader: function(j) {
    // ... same thing for column header j
  },
  getCell: function(i,j,cb) {
      // fetch data associated to cell i,j 
      // and call the callback method cb with it
      // as argument
  },
  getHeader: function(j,cb) {
      // ... same thing for column header j
  }
}

Troubleshooting

Using <!DOCTYPE html> for using the library with IE >=9. IE < 9 is simply not supported.

The library currently use a huge container with overflow. Browser have a bit of limitation on the size of such a container. Expect some bug appearing at 40000 rows in IE, 500000 rows in other browsers.

Comments
  • Can't scroll left with mac trackpad (goes to prev page instead)

    Can't scroll left with mac trackpad (goes to prev page instead)

    Scrolling right, down, and up works fine, but scrolling left with a macbook trackpad (at least in Chrome 32) only works for a tiny amount and then the previous page action takes over.

    bug 
    opened by patkujawa-wf 5
  • TableView cleanup ScrollBarProxy

    TableView cleanup ScrollBarProxy

    I believe that the ScrollBarProxy cleanup doesn't work for the cleanup method in TableView (line 546 of fattable.coffee):

    cleanUp: ->
        # be nice rewind !
        @eventRegister.unbindAll()
        @ScrollBarProxy?.onScroll = null
    

    After reading over the code, I believe that you were trying to do:

    cleanUp: ->
        # be nice rewind !
        @eventRegister.unbindAll()
        @scroll?.onScroll = null
    
    opened by encodedstephen 4
  • Better scroll event handling

    Better scroll event handling

    I moved the event type detection in the initialization to do it only once and then used a specialized function to return the delta values on scroll. Added the standard WheelEvent detection for modern browser too and fix horizontal scroll for Firefox.

    opened by Amli 3
  • Minor issue when mouseout function in headerContainer

    Minor issue when mouseout function in headerContainer

    In the ScrollBarProxy eventRegister, line 517 needs to be changed to _this.headerContainer.className instead of _this.headerDragging.className so that it correctly resets the classes on the header container.

    Incorrect code pasted below:

    eventRegister.bind(this.headerContainer, 'mouseout', function(evt) {
    if (_this.headerDragging) {
    if ((evt.toElement === null) || (evt.toElement.parentElement.parentElement !== _this.headerContainer)) {
    _this.headerDragging.className = "fattable-header-container";
    }
    return _this.headerDragging = false;
    }
    });
    
    opened by encodedstephen 1
  • Do not prevent default behavior when ...

    Do not prevent default behavior when ...

    End of scroll is reached...

    As spotted by @fterrazzoni

    It you use the scroll wheel inside a scrollable fattable which
    is inside another scrollable element, it doesn't propagate the scrolling to its parent
    
    bug 
    opened by fulmicoton 0
  • Allow expansion of tall rows despite default rowHeight

    Allow expansion of tall rows despite default rowHeight

    The API example shows this: "rowHeight": 35, // constant row height (px)

    Could this be changed dynamically? For example, imagine row content that is actually very "tall", but by default only 1 line of that content is shown in a row. Next, imagine you wanted to let users expand the row so its full content can be seen.

    (How) Can this be done?

    enhancement 
    opened by otisg 1
  • Goto Method seems backwards

    Goto Method seems backwards

    I'm not sure if you intended this, but it seems as though the goTo and the setScrollXY conflict. That is, targetY seems to deal with the columns (inside of goTo) but in setScrollXY, the targetY variable would be used to scroll up and down.

    To get the goTo working, I actually changed the javascript code to (changed targetY and targetX):

    TableView.prototype.goTo = function(i, j) {
        var targetX, targetY;
        targetY = i != null ? this.rowHeight * i : void 0;
        targetX = j != null ? this.columnOffset[j] : void 0;
        return this.scroll.setScrollXY(targetY, targetX);
    };
    
    opened by encodedstephen 0
  • Click scrollwheel to scroll doesn't work

    Click scrollwheel to scroll doesn't work

    When you click your scroll-wheel (cursor changes to circle with an arrow in each direction) to scroll, the page only moves a few pixels in each direction.

    Tested in Chrome.

    bug 
    opened by Grovespaz 3
Owner
Paul Masurel
Rust developer. Creator of @tantivy-search
Paul Masurel
logseq custom.js and custom.css utilities : resize query table columns, hide namespaces...

logseq-custom-files custom.js and custom.css utilities for Logseq. current version v20220331 query table view : add handles on the query table headers

null 44 Dec 7, 2022
A template for buildind scrollable landing pages with Gsap, ScrollTrigger and webgi engine in typescript using parcel bundler.

Threejs + GSAP + WEBGi 100% Free Course This is a template used in my fast course "building scrolable pages with ScrollTrigger and Threejs" for a vani

Anderson Mancini 62 Dec 17, 2022
A small, lightweight JavaScript plugin for placing items in straight rows (jQuery and vanilla JS version) – Demo:

rowGrid.js rowGrid.js is a small, lightweight (~1000 bytes gzipped) jQuery plugin for placing images (or other items) in straight rows. The grid is si

Bruno Joseph 669 Jul 22, 2022
Collection of Rowy's templates for cloud functions cod snippets - including for derivative, action columns and extensions.

Rowy Templates Collection of Rowy's backend templates and code snippets for cloud functions - including for derivative, action columns and extensions.

Rowy 4 Nov 16, 2022
A plugin for the Obsidian markdown note application, adding functionality to render markdown documents with multiple columns of text.

Multi-Column Markdown Take your boring markdown document and add some columns to it! With Multi Column Markdown rather than limiting your document lay

Cameron Robinson 91 Jan 2, 2023
An npm package with Tailwind CSS utility classes for creating responsive grid columns without media queries using auto fit.

Grid Auto Fit for Tailwind CSS A plugin that helps you create a responsive grid layout in Tailwind CSS without using media queries. It uses the auto-f

Thirus 80 Dec 28, 2022
✏️ A small jQuery extension to turn a static HTML table into an editable one. For quickly populating a small table with JSON data, letting the user modify it with validation, and then getting JSON data back out.

jquery-editable-table A small jQuery extension to turn an HTML table editable for fast data entry and validation Demo ?? https://jsfiddle.net/torrobin

Tor 7 Jul 31, 2022
Another table select prompt plugin of inquirer.js, with powerful table render and filters.

inquirer-table-select-prompt Table row selection prompt for Inquirer.js 动机 现有的 inquirer.js 没有支持表格行选中的命令行交互的插件. 社区内能查找到的,只有一个二维数组的 checkbox,eduardobouc

锂电 3 Jan 7, 2023
Unlocks all brainly answers and bypasses one answer per day limit. Gives infinite free answers & unlocks all textbooks 🔐 ∞

Brainly-LockPick ?? Unlocks all brainly answers and bypasses one answer per day limit. Gives infinite free answers & unlocks textbooks ?? ∞ Note: refr

null 7 Dec 9, 2022
An infinite scrolling plugin for jQuery.

jScroll - jQuery Plugin for Infinite Scrolling / Auto-Paging Official site at jscroll.com. Copyright © Philip Klauzinski Dual licensed under the MIT a

Philip Klauzinski 1.1k Dec 29, 2022
infiniteScrollWithTemplate - JQuery plugin for ajax-enabled infinite page scroll / auto paging with template

jQuery Infinite With Template Plugin JQuery plugin for ajax-enabled infinite page scroll with template. If you like jQuery until now, this little libr

이삼구 2 Mar 19, 2021
Create a HTML table from JSON that can be sorted, selected, and post-processed using a simple callback.

Tidy Table Create a HTML table from JSON that can be sorted, selected, and post-processed using a simple callback. Features Extensible HTML/CSS interf

Marc S. Brooks 50 Aug 16, 2022
A vanilla JavaScript library that automatically generates the "Table of Contents" of an HTML document.

DocumentOutline.js DocumentOutline is a vanilla JavaScript library that automatically generates the "Table of Contents" of an HTML document. See a liv

Angelo Faella 3 Jul 12, 2021
Simple modern JavaScript ES6 library that fetches JSON data into an HTML table which displays nicely within a Bootstrap 4 Card.

Simple modern JavaScript ES6 library that fetches JSON data into an HTML table which displays nicely within a Bootstrap 4 Card. Uses simplenotsimpler/modern-table library.

SimpleNotSimpler 6 Feb 17, 2022
JavaScript client-side HTML table sorting library with no dependencies required.

TABLE-SORT-JS. Description: A JavaScript client-side HTML table sorting library with no dependencies required. Demo Documentation. (work in progress)

Lee Wannacott 32 Dec 14, 2022
A regular table library, for async and virtual data models.

A Javascript library for the browser, regular-table exports a custom element named <regular-table>, which renders a regular HTML <table> to a sticky p

J.P. Morgan Chase & Co. 285 Dec 16, 2022
Yunisdev-table2csv - Lightweight library to convert HTML table to CSV file

Installation Add following HTML before body end: <script src="https://yunisdev.github.io/table2csv/table2csv.min.js"></script> <!-- or --> <script src

Yunis Huseynzade 2 Oct 19, 2020
A Leaderscore app that send data to an API created from Postman and allow users to save names and scores in a table. Built with JavaScript

Leaderboard The leaderboard website displays scores submitted by different players. It also allows you to submit your score. All data is preserved tha

Anicet Murhula 11 May 16, 2022
a lightweight, dependency-free JavaScript plugin which makes a HTML table interactive

JSTable The JSTable is a lightweight, dependency-free JavaScript plugin which makes a HTML table interactive. The plugin is similar to the jQuery data

null 63 Oct 20, 2022