Skip to content
This repository has been archived by the owner on Nov 4, 2023. It is now read-only.

tsaxking/tables-js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tables.js Version 1.1.x

Note: This is a work in progress. If you find any bugs, please report them on the GitHub repository.

Description

The power of tables.js comes from the dynamic nature of the Table class. While jQuery Datatables is a great tool, and it's customizable, I want to expand on its functionality. You can combine datatables with this tool by just setting options.datatable = true or options.datatable = { ...datatableOptions }. I have added state management and independent cell/row/column rendering through the object the Table class creates. My goal is for you to have full customizability over your tables

Installation

<!-- Most recent version -->
<script src="https://cdn.jsdelivr.net/npm/tables-js/tables.min.js"></script>

<!-- Specific version -->
<script src="https://cdn.jsdelivr.net/npm/tables-js/1.1/tables.min.js"></script> <!-- Uses Table Class -->
<script src="https://cdn.jsdelivr.net/npm/tables-js/1.0/tables.min.js"></script> <!-- Uses setTable -->

It is recommended that tables.js be used with Bootstrap, jQuery, jQuery Datatables, and Material Icons, but it is not required. If you want to use tables.js with Bootstrap, jQuery, and jQuery Datatables, you can use the following code:

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.2.1/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="https://cdn.datatables.net/1.10.24/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.10.24/js/dataTables.bootstrap4.min.js"></script>  
<script src="https://cdn.jsdelivr.net/npm/js-tables/1.1/tables.js"></script>

Usage

Initialize the table with the following code:

const table = document.getElementById("my-table");
const headers = ["Name", "Age", "Favorite Color"]; // these can be objects as well
const data = [
    {
        Name: "John",
        Age: 20,
        "Favorite Color": "Blue"
    },
    {
        Name: "Jane",
        Age: 21,
        "Favorite Color": "Red"
    }
];
const options = { // optional
    // options go here
};

const myTable = new Table(table, headers, data, options);

Generating from Various Data Types

JSON

const myTable = Table.from(table, json, options, 'json'); // 'json' may not be necessary as the function attempts to detect the type of data.
// or
const myTable = Table.fromJSON(table, json, options);

CSV

const myTable = Table.from(table, csv, options, 'csv'); // 'csv' may not be necessary as the function attempts to detect the type of data.
// or
const myTable = Table.fromCSV(table, csv, options);

TSV

const myTable = Table.from(table, tsv, options, 'tsv'); // 'tsv' may not be necessary as the function attempts to detect the type of data.
// or
const myTable = Table.fromTSV(table, tsv, options);

HTML

const myTable = Table.from(table /* already populated table */, null /* Data is in the prerendered table */, options, 'html'); // 'html' may not be necessary as the function attempts to detect the type of data.
// or
const myTable = Table.fromHTML(table, options);

Custom Table Classes

Table

class Table {
    /* properties */
    el // the table element
    headers // the headers
    data // the data
    originalData // data before any filters/sorting/inserting/deleting
    options // the options
    states // the Table_StateStack object
    rows // the array of TableRow objects
    tableHeaders // the array of TableHeader objects
    columns // the array of TableColumn objects

    /* public methods */
    render() // renders the table
    destroy(deleteData: Booean) // destroys the table (deleteData removes all data from the Table object)
    
    /* public static methods */
    static fromHTML(table: HTMLElement, options: Object) // creates a Table object from a populated html table
    static fromJSON(table: HTMLElement, json: String, options: Object) // creates a Table object from a JSON string 
    static fromCSV(table: HTMLElement, csv: String, options: Object) // creates a Table object from a CSV string
    static fromTSV(table: HTMLElement, tsv: String, options: Object) // creates a Table object from a TSV string

    static from(table: HTMLElement, data: Object | null, options: Object | null, type: String | null) // autodetects the type of data and creates a Table object from your inputs

    /* private methods */
    showInsertRows(TableRow) // shows the insert rows above and below the TableRow (used with reorderable tables)
    hideInsertRows() // hides the insert rows
    renderRows() // renders the rows
    renderHeaders() // renders the headers
    sort() // used with sortable tables
    update() // updates the table
    renderFromContent() // renders the table from the content of the Table object (for use with editable tables)

    /* getters */
    get content() // returns the array of TableRow.content objects
    get json() // returns JSON.stringify(this.content)
}

Table_StateStack

This class is an extension of js-state-stack and is used to keep track of the table's/cell's state. It is used to keep track of the table's state when editing, sorting, etc. It is not recommended to use this class directly.

TableRow

class TableRow {
    /* properties */
    cells // the array of TableCell objects
    el // the tr element
    data // the data passed into header.getData()

    /* private methods */
    render() // renders the row

    /* getters */
    get content() // returns an object of {headerTitle: tableCell.content}
}

TableHeader

class TableHeader {
    /* properties */
    el // the th element
    options // the options (currently unused)

    /* public methods */
    changeContent(content) // changes the content of the header and rerenders the <td> element

    /* private methods */
    render() // renders the header
}

TableFooter

An extension of TableHeader that is used with the footer option. This has all the same properties and methods as TableHeader.

TableColumn

class TableColumn {
    /* properties */
    cells // the array of TableCell objects (includes the header cell)
    header // the TableHeader object

    /* getters */
    get content() // returns an array of the content of each cell in the column (includes the header cell)
}

TableCell

class TableCell {
    /* properties */
    el // the td or th element
    colPos // the column position
    rowPos // the row position
    headerTitle // the header title
    header // the TableHeader object
    editable // the editable object in Table.options
    stack // the Table_StateStack object
    
    /* public methods */
    onChange() // custom function that is called when the cell is changed (used with editable tables)
    onCancel() // custom function that is called when the cell is cancelled (used with editable tables)
    changeContent(content) // changes the content of the cell and rerenders the <td> element

    /* private methods */
    render() // renders the cell
}

ReorderInsertRow

This is only used with reorderable tables. These are the rows that hare hidden and shown when you drag over a row. They are used to insert a row above or below the row you are dragging over.

class ReorderInsertRow {
    el // the tr element
    row // the TableRow object that the insert row is above or below

    /* private methods */
    show() // shows the insert row
    hide() // hides the insert row
}

Parameters

The Table Element

All you need to do is pass in the table element you want to use. This can be done in two ways:

const myTable = new Table(document.getElementById("my-table"));

or

const myTable = new Table("#my-table"); // you can use any selector you wish :)

Headers

The headers parameter is either an object where each key is the header name, or an array of objects or strings that generate each header and subsequent column. If you pass in an array of strings, the headers will be generated with the string as the header text and the data will be generated by row[headerTitle]. If you pass in an array of objects, you must specify the following properties:

  • header.title || header.name || header.key which will be the string that the <th> is populated with
  • header.getData this must be a function that returns either a string to populate inside of the <td> element using td.innerHTML, or an element to populate inside of the <td> using td.appendChild(). If no header.getData is specified, it will return row[header.title || header.name || header.key].

All of these examples will make this in HTML:

<table>
    <thead>
        <tr>
            <th>Name</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>John</th>
        </tr>
    </tbody>
</table>

Object Array Header Example:

const headers = [{
    title: 'Name',
    getData: (row) => {
        return row.name;
    }
}];

const data = [{
    name: 'John'
}];

const myTable = new Table("#my-table", headers, data);

String Array Header Example:

const headers = ['Name'];

const data = [{
    Name: 'John' // notice how this must be the same capitalization as the header
}];

const myTable = new Table("#my-table", headers, data);

Object Header Example:

const headers = {
    Name: {
        getData: (row) => {
            return row.name;
        }
    }
};

const data = [{
    name: 'John'
}];

const myTable = new Table("#my-table", headers, data);

The other properties of the header objects are used to customize the columns. All the properties below are written as header.property. These properties are the same whether you pass in an array of objects or an object.

Changing the <td> Elements

Classes

header.th.classes is an array of strings that will be added to the <th> element. header.td.classes is an array of strings that will be added to each <td> element in this column. header.td.classTests is an array of objects that will be used to add classes to the <td> element. Each object must have the following properties:

  • test is a function that returns a boolean. If the function returns true, the class will be added to the <td> element.
  • class (OPTIONAL) is a string that will be added to the <td> element if the test function returns true.
  • classes (OPTIONAL) is an array of strings that will be added to the <td> element if the test function returns true.

Example:

const headers = [{
    title: 'Name',
    th: {
        classes: ['my-class', 'my-other-class'] // applies to <th>
    },
    td: {
        classes: ['my-td-class', 'my-other'], // applies to <td>
        classTests: [{
            test: (row) => {
                return row.name === 'John';
            },
            class: 'my-class' // applies to <td>
        }, {
            test: (row) => {
                return row.name === 'John';
            },
            classes: ['my-class', 'my-other-class'] // applies to <td>
        }]
    }
}];
Attributes

header.td.attributes is an array of objects that will be added to the <td> element. Each object must have the following properties:

  • name is a string that will be the name of the attribute.
  • value is a either a string that is the value of the attribute, or a function that returns a string that is the value of the attribute that passes in the row as a parameter. header.th.attributes is an array of objects that will be added to the <th> element. header.th.attrubutes[].value can only be a string, not a function.

Example:

const headers = [{
    title: 'Name',
    td: {
        attributes: [{
            name: 'data-name',
            value: 'John'
        }, {
            name: 'data-name',
            value: (row) => { // row is a TableRow object
                return row.name;
            }
        }]
    },
    td: {
        attributes: [{
            name: 'data-name',
            value: 'John'
        }]
    }
}];
Event Listeners

All lisener arrays are structured the same way. Each object must have the following properties:

  • type is a string that is the name of the event.
  • callback (v1.1.x) is a function that is the listener that passes in the event as a parameter. (Uses a different data structure than v1.0.x)
  • action (v1.0.x) is a function that is the listener that passes in the event as a parameter.

header.th.listeners is an array of objects that will be added to the <th> element. header.td.listeners is an array of objects that will be added to each <td> element in this column.

Example:

const headers = [{
    title: 'Name',
    th: { 
        listeners: [{
            event: 'click', // runs when the `<th>` is clicked
            callback: (event) => { // v1.1.x
                /* 
                    event is an event object with the following expanded property:
                    - event.__row = TableRow object
                */
                console.log(event);
            }
        }]
    },
    td: {
        listeners: [{
            event: 'click',
            action: ({
                event, // event object
                row, // data row (custom data)
                tableRow // TableRow object
            }) => { // v1.0.x
                console.log(event);
            }
        }]
    }
}];
Sorting

header.sort is a sorting function that runs when the header is clicked. It sorts through the data and rerenders the table. This does not change table.originalData, only table.data. Currently, if you click it once, it sorts up, click again, it sorts down, and click again, it sorts back to the original order. This will be changed in the future to allow for more customization.

Example:

const headers = [{
    title: 'Name',
    sort: (a, b) => { // a and b are TableRow objects
        return a.data.name > b.data.name;
    }
}];

<td> Editing (to be used with options.editable) header.editable is a boolean that determines if the <td> element is editable. If true, each <td> element will have a contenteditable attribute.

const headers = [{
    title: 'Name',
    editable: true
}, {
    title: 'Age',
    editable: false
}];

const data = [{
    Name: 'John',
    Age: 34
}];

const options = {
    editable: true
};

Will create

<table>
    <thead>
        <tr>
            <th>Name</th>
        </tr>
        <tr>
            <th>Age</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td contenteditable="true">John</td>
        </tr>
        <tr>
            <td>34</td>
        </tr>
    </tbody>
</table>

Note: Even if a user edits the html, it will not change TableCell.content

Changing the <th> Elements

Minimize

header.minimize is a boolean that determines if the <th> element is minimized. If true, the <th> element will have a minimize class.

const headers = [{
    title: 'Name',
    minimize: true
}, {
    title: 'Age',
    minimize: false
}];

Will create

<table>
    <thead>
        <tr>
            <th>
                <div style="display: flex; justify-content: space-between; align-items: center;">
                    <div>Name</div>
                    <!-- This icon can change with options.minimize.open -->
                    <i class="material-icons">chevron_left</i>
                </div>
            </th>
        </tr>
        <tr>
            <th>Age</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>John</td>
        </tr>
        <tr>
            <td>John</td>
        </tr>
    </tbody>
</table>

Data

The header array is used to represent each row in the table. This is fully customizable because nothing from the Table class reads this data, only your getData does and other custom functions.

Each row's data will be in TableRow.data.

Options

<tr> Event Listeners

options.tr.listeners is the same as header.th.listeners and header.td.listeners except it applies to all <tr> elements.

Attributes

options.tr.attributes is the same as header.th.attributes except it applies to all <tr> elements.

Classes

options.tr.classes is the same as header.th.classes except it applies to all <tr> elements. options.tr.classTests is the same as header.td.classTests except it applies to all <tr> elements.

Jquery DataTable

options.datatable = true or options.dataTable = true will create a Jquery DataTable. This will override all other options except options.editable.

Header Sorting

header.sortable will make every <th> element sortable. This will not override header.sort. The sort function will be the same as the default header sort function ((a, b) => a.el.innerText.localCompare(b.el.innerText);).

Even Columns

options.evenColumns = true will set the width to be the same for every column using percentages.

Minimize

minimize.open is the icon that will be used for the minimize button. The default is <i class="material-icons">chevron_left</i>. minimize.minimized is a boolean that determines if the table is minimized. The default is false.

Caption

options.caption is a caption you can add onto the table. This will be added to the <table> element.

Example:

const options = {
    caption: 'This is a caption'
}

// or

const options = {
    caption: {
        content: 'This is a caption',
        attributes: [], // Attributes onto the <caption> element
        classes: [], // Classes onto the <caption> element
        listeners: [] // Event listeners onto the <caption> element
    }
}

Will create

<table>
    <caption>This is a caption</caption>
    <thead>
        <!-- Your headers -->
    </thead>
    <tbody>
        <!-- Your rows -->
    </tbody>
</table>

Options soon to be implemented

  • Reorder: Drag and drop to reorder rows and columns. Currently working on this, you can try it out by setting options.reorder = true to see what is happening. If you have tips please let me know.
  • Search: Search through the table using fuzzy search
  • Pagination: Different pagination options for the table (ex. using dots, arrows, select, etc.)
  • Insertion: Insert a row or column
  • Deletion: Delete a row or column

Version 1.0.x

Note: This version is deprecated and will not be updated. Please use version 1.1.x. The basics are the same, but the options and headers parameters are different.

Headers

const headers = [{
    title: 'Name',
    getData: (row) => row.name,
    listeners: [{ // applied only to <td> elements
        event: 'click',
        callback: (e) => {
            console.log(e);
        }
    }],
    classes: ['class1', 'class2'], // applied only to <th> elements
    tdClassTests: [{ // applied only to <td> elements
        test: (row) => row.name === 'John',
        classes: ['class1', 'class2']
    }],
    tdClasses: ['class1', 'class2'], // applied only to <td> elements
    tdAttributes: [{ // applied only to <td> elements
        name: 'contenteditable',
        value: 'true' // can be string
        value: (row) => row.name === 'John' ? 'true' : 'false' // or function
    }]
}]

Options

const options = {
    evenColumns: true,
    trAttributes: [{
        name: 'contenteditable',
        value: 'true' // can be string
        value: (row) => row.name === 'John' ? 'true' : 'false' // or function
    }],
    appendTest: (row) => row.name === 'John',
    trClasses: ['class1', 'class2'],
    trClassTests: [{
        test: (row) => row.name === 'John',
        classes: ['class1', 'class2']
    }],
    trListeners: [{
        event: 'click',
        callback: (e) => {
            console.log(e);
        }
    }]
}

Example

setTable(document.getElementById('my-table'), headers, data, options);

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published