Release Notes

Build Tools

With this releaase of Tabulator the build tools have been updated to use Gulp 4

Commands

To make it easier to build your own version of Tabulator, the build tools are now packaged with the library.

There are now two new build commands for custom builds of your table

Build Code

To run a one off build open a console window in the root folder of Tabulator and run the following command:

npm run build

This command will take all the files in the /src folder and build them into their distribution files in the /dist folder

Watch For Changes

When using the watch command, gulp will watch your source code for changed (when you save a file) and will then automatically run the build command for you.

To run the watcher, open a console window in the root folder of Tabulator and run the following command:

npm run watch

This command will watch all the files in the /src folder and build them into their distribution files in the /dist folder when any of the files change

Build Guide

There is now improved documentation on how to create Custom Tabulator Builds

Layout

A new table layout mode is available that resizes the table container to fit the data

Fit Table and Columns to Data

The fitDataTable layout mode, will set the column withs in the same way as the fitData mode, but it will also then resize the width of the table to match the total width of the columns

var table = new Tabulator("#example-table", {
    layout:"fitDataTable",
});

Downloads

The download module has been completely rebuilt in this release and is now based on the exports module to bring it inline with the clipboard and print modules. This means that a number of the download properties have changed in this release and all downloaders have been redesigned to work with the next Export List mechanic

Download Contents

The download table will contain column header groups, row groups, data trees and column calculations.

You can choose to remove any of these from the output data by setting the values in the printConfig option in the table definition:

var table = new Tabulator("#example-table", {
    downloadConfig:{
    columnHeaders:false, //do not include column headers in downloaded table
    columnGroups:false, //do not include column groups in column headers for downloaded table
    rowGroups:false, //do not include row groups in downloaded table
    columnCalcs:false, //do not include column calcs in downloaded table
    dataTree:false, //do not include data tree in downloaded table
},
});

Availabilitity
Not all downloaders support column header groups, row groups and column calculations, see the documentation for each downloader for full information.

Row Range

By deafault, only the active rows (rows that have passed filtering) will be included in the download the downloadRowRange option takes a Row Range Lookup value and allows you to choose which rows are included in the download output:

  • visible - Rows currently visible in the table viewport
  • active - Rows currently in the table (rows that pass current filters etc - default)
  • selected - Rows currently selected by the selection module (this includes not currently active rows)
  • all - All rows in the table reguardless of filters
var table = new Tabulator("#example-table", {
    downloadRowRange:"selected", //change default selector to selected
});

You can override the downloadRowRange option when dowloading a file but passing the Row Range Lookup value into the optional fourth argument of the download function:

table.download("csv", "data.csv", {}, "visible"); //include only rows visible in the table viewport in the download output

Grouped Data
The all option is not available for grouped data. This is because grouping is carried out after filtering in Tabulators data processing pipeline, so only filtered data ever makes it into groups.

Data Trees
The all option is not available for nested data. This is because child row geneation is carried out after filtering in Tabulators data processing pipeline, so only filtered data ever makes it into groups.

Column Header Titles

When downloading you may want to apply a different columnheader title from the one usualy used in the table. You can now do this using the titleDownload column definition option, which takes the same inputs as the standard title property.

var table = new Tabulator("#example-table", {
    columns:[
    {title:"Age", titleDownload:"User Age", field:"age"},
    ]
});

Custom File Formatter

If you want to create a custom file type from the table data then you can pass a function to the type argument, instead of a string value. At the end of this function you must call the setFileContents function, passing the formatted data and the mime type.

//custom file formatter
    var fileFormatter = function(list, options, setFileContents){
    //list - an array of export rows representing one row of data for the table;
    //options - the options object passed from the download function
    //setFileContents - function to call to pass the formatted data to the downloader

    var fileContents = [];

    //itterate over rows
    list.forEach((row) => {
    var item = [];

    switch(row.type){
    case "header":
    //handle header rows

    case "group":
    //handle group header rows

    case "calc":
    //handle calculation rows

    case "row":
    //itterate over the columns in a row
    row.columns.forEach((col) => {
    if(col){
    item.push(col.value);
}
});

fileContents.push(item.join(delimiter));
break;
}
});

//trigger file download, passing the formatted data and mime type
setFileContents(names.join(", "), "text/plain");
}

//trigger file download
table.download(fileFormatter, "test.txt");

Note: You can find out more about data URI's Here.

Export List

The list argument passed into the formatter contains all of the information you should need to layout your table. It is an array of ExportRow objects. Each obvject represents a row of data in the table arranged in the order they currently appear. You should itterate over this array to built each row of your output data.

ExportRow Object

The ExportRow object has 4 properties to describe the row it represents:

  • type - the type of row, this can have one of 4 values:
    • row - A standard row from the table
    • calc - A calculation row
    • group - A row group header
    • header - a row of column headers (column titles)
  • component - The Component Object for the row or group that the ExporRow represents
  • indent - if the row is either a group or a data tree child, this value contains an integer representing which level the row is on, the greater the number the more indented the row should be
  • columns - an array of ExportColumn objects representing the columns on the row.

It takes the following format

{
    type: "row",
    component: RowComponent,
    indent: 0,
    columns: [ExportColumn, ExportColumn, ExportColumn],
}

The columns property of the ExportRow object contains an array of ExportColumn objects representing the columns on the row. in the case of tables with column groups this array can also include null values representing spaces where columns would have been if not for a neighbouring column taking up multiple columns or rows, such as a column group header. These null values are included to help deal with rowspan and colspan alignent and in most cases can be ignored. (an example of where they can come in useful can be found in the built-in xlsx downloader)

{
    type: "row",
    component: RowComponent,
    indent: 0,
    columns: [null, ExportColumn, ExportColumn, null, ExportColumn],
}

When dealing with group type ExportRow objects the columns array will contain only one ExportColumn that represents the value for the group header row

ExportColumn Object

The ExportColumn object has 5 properties to describe the column it represents:

  • value - The value of the cell or title of the column header
  • width - The width in columns, generally this has a value of 1, but when dealing with grouped column headers this describes how many columns wide the column group should be, in the case of group headers this shows as the number of columns in the table to esure the group header is full width
  • height - The height of the cell in rows, generally this has a value of 1, but when dealing with grouped column headers this describes how rows hight the cell should be to allow for neighbouring grouped columun headers
  • depth - This usually has a value of 1, in the case of grouped column headers, this shows how many levels of child columns the group has
  • component - The Component Object for the column that the ExporColumn represent

For a standard cell in a row it would take the following format:

{
    value: "Bob Monkhouse",
    width: 1,
    height: 1,
    depth: 1,
    component: ColumnComponent,
}

For a column group header containing two child rows it would look like this:

{
    value: "Column Group",
    width: 2, //the group header is two columns wide
    height: 1,
    depth: 2, //the group header is made up of two levels, itself and its children
    component: ColumnComponent,
}

For a column header next to a column group header containing two child rows it would look like this:

{
    value: "Age",
    width: 1,
    height: 2, //the column header has a rowspan of 2 to match the height of the conlumn group next to it
    depth: 1,
    component: ColumnComponent,
}

For a cell representing a group header it would take the following format:

{
    value: "Green", //group header title
    width: 7, //total number of columns in table to ensure column header is full width
    height: 1,
    depth: 1,
    component: GroupnComponent, //component object for the group of the header
}

Group Header

When downloading, you may want to apply a different group header from the one usualy used in the table. You can now do this using the groupHeaderDownload table option, which takes the same inputs as the standard groupHeader property.

var table = new Tabulator("#example-table", {
    groupHeader: function(value, count, data, group){
    return value + "<span style='color:#d00; margin-left:10px;'>(" + count + " item)</span>";
},
groupHeaderDownload: function(value, count, data, group){
return value;
},
});

Passing a value of false into groupHeaderDownload will cause the header to show the groups key as plain text

Columns

Column Widths

The Column Component now provides additional functions for manipulating column width

Get Width

The getWidth function returns the width of the column in pixels

var width = column.getWidth();

Set Width

You can set the width of a column using the setWidth function, passing the width of the column in pixes as an integer as the first argument,

column.setWidth(123); // set the column width to 123 pixels

Passing a value of true to the function will resize the column to fit its contents

column.setWidth(true); // set the column width to fit its contents

Check Visibility

The getVisibility function has now been renamed to isVisible to bring it inline with other funcnctions

var visible = column.isVisible();

Grouping

Check Visibility

The getVisibility function has now been renamed to isVisible to bring it inline with other funcnctions

var visible = group.isVisible();

Trees

Add Child Rows

You can now add child rows to a data tree row using the new addTreeChild function on the Row Component

The first argument should be a row data object. If you do not pass data for a column, it will be left empty. To create a blank row (ie for a user to fill in), pass an empty object to the function.

row.addTreeChild({name:"Billy Bob", age:"12", gender:"male", height:1});

The second argument is optional and determines whether the row is added to the top or bottom of the array of child rows. A value of true will add the row to the top of the array, a value of false will add the row to the bottom of the array. If the parameter is not set the row will be placed according to the addRowPos global option.

row.addTreeChild({name:"Billy Bob", age:"12", gender:"male", height:1}, true); //add child row to the top of the array

If you want to add the row next to an existing row you can pass an optional third argument to the function that will position the new row next to the specified row (above or below based on the value of the second argument). This argument will take any of the standard row component look up options. This must be a row that has the same parent as the row you want to add

row.addTreeChild({name:"Billy Bob", age:"12"}, true, 3); //add new row above existing row with index of 3

Delete Child Row

The delete function on the Row Component has been updated to now handle child and parent rows correctly.

row.delete();

Movable Rows

Moving Rows To Non-Tabulator Elements

Tabulator also allows you to move rows between Tabulator tables and any other non-Tabulator elements on the page. To enable this you should supply either a valid CSS selector string or a DOM node for the elements you wish to be able to connect to to the movableRowsConnectedElements option. if you want to connect to multple tables then you can pass in an array of values to this option.

var table = new Tabulator("#example-table", {
    movableRows: true, //enable movable rows
    movableRowsConnectedElements: "#drop-area", //element to receive rows
});

When you start dragging a row, the tabulator-movingrow-receiving class will be applied to all elements supplied to the movableRowsConnectedElements optiton, to allow you to highlight any droppable areas.

When a row is dropped on element from from the movableRowsConnectedElements option the movableRowsElementDrop callback will be triggered. You can use this callback to trigger any changes as a result of the drop

var table = new Tabulator("#example-table", {
    movableRows: true, //enable movable rows
    movableRowsConnectedElements: "#drop-area", //element to receive rows
    movableRowsElementDrop:function(e, element, row){
    //e - mouseup event object
    //element - node object for the element that the row was dropped onto
    //row - row component for the row that was moved

    //add a div to the drop element containing the name property from the row data
    var div = document.createElement("div");
    div.textContent = row.getData().name;
    element.appendChild(div);
},
});

Dropping a row in an element will not directly result in the row appearing inside the element, it will simply trigger the movableRowsElementDrop callback, allowing you to the decide the next action.

Filtering

Filter Params

You can now pass a filter params object to an optional fourth argument on the addFilter and setFilter functions:

table.setFilter("tags", "keywords", "red green blue", {matchAll:true});

Built In Filters

New string comparison filters have been added in this release.

Keywords

The keywords filter displays any rows with data containing any space separated words in the specified string (case insensitive)

table.setFilter("colors", "keywords", "red green blue"); //returns rows with a colors filed containing either the word "red", "green", or "blue"

This filter has two optional params:

  • separator - the separator used between words (default " ")
  • matchAll - the row must contain all the keywords to pass the filter
table.setFilter("colors", "keywords", "red green blue", {matchAll:true}); //returns rows with a colors filed containing ALL the words "red", "green" & "blue"

Starts With

The starts filter displays any rows with data that starts with the specified string. (case insensitive)

table.setFilter("name", "starts", "ste");

Ends With

The ends filter displays any rows with data that ends with the specified string. (case insensitive)

table.setFilter("name", "ends", "son");

Editing

Edit History

Editing of cells is now tracked to make it easier to see which cells have been edited

List Edited Cells

You can get a list of all editited cells in the table using the getEditedCells function. this will return an array of Cell Components for each cell that has been edited.

var editedCells = table.getEditedCells()

Tabulator will continune to add cells to this list until the table in the data is replaced by the setData function or the edited list is cleared.

Check if Cell Has Been Edited

You can call the isEdited function on any Cell Component to see if it has been editied. it will return true if it has been edited or false if it has not.

var edited = cell.isEdited()

Clear Edited Cells

You can clear the edited flag on a cell to prevent ir from commming up in edited lists in future

The clearEdited can be called on a Cell Component to clear the edited flag used by the isEdited function and mark the cell as unedited.

cell.clearEdited();

Alternativly, the clearCellEdited can be called on the table to clear the edited flag on all cells in the table

table.clearCellEdited();

Or optionally you can pass in a Cell Component or an array of Cell Components to the clearCellEdited function to clear the edited flag on specific cells

table.clearCellEdited([cell1, cell2]);

Editors

Select Editor Multi-Item selection

The new multiselect option for the select editor will allow users to select multiple items from the select list

{title:"Example", field:"example", editor:"select", editorParams:{
    values:true, //create list of values from all values contained
    multiselect:true, //allow multiple entries to be selected
}}

This option can take two different values:

  • true - a boolean value of true will allow the user to select as many item from the list as they like
  • number - if you set an integer for this option that will set the maximum number of items the user can select, if they try and select more than this, earlier selected items will be deselected

Select Editor List Item Attributes

When using complex values lists for the select editor you can now use the elementAttributes property to specify attributes that should be set on the list items element. In the example below we are setting a class on a list item

{title:"Name", field:"name", editor:"select", editorParams:{
    values:[
    {
        label:"Steve Boberson",
        value:"steve",
        elementAttributes:{
        class:"primary-name",
    }
},
]
}}

Autocomplete Editor Values List

You can now pass an array of objects, to the values option for the autocomplete editor to give you more control over the label, value and order of each item in the list.

{title:"Name", field:"name", editor:"autocomplete", editorParams:{
    values:[
    {
        label:"Steve Boberson",
        value:"steve",
    },
    {
        label:"Bob Jimmerson",
        value:"bob",
    },
    {
        label:"Jenny Jillerson",
        value:"jenny",
    },
    {
        label:"Jill Betterson",
        value:"jill",
    },
    ]
}}

Validation

The validation system has had an overhaul to allow greater flexibility in how you validate your table data.

Validation Modes

There are now three different validation modes available to customise the validation experience:

  • blocking - if a user enters an invalid value while editing, they are blocked from leaving the cell until a valid value is entered (default)
  • highlight - if a user enters an invalid value, then the edit will complete as usual and they are allowed to exit the cell but a highlight is applied to the cell using the tabulator-validation-fail class
  • manual - no vaildation is automatically performed on edit, but it can be triggered by calling the validate funtion on the table or any Component Object

The validation mode can be set using the validationMode setup option:

var table = new Tabulator("#example-table", {
    validationMode:"highlight", //highlight cells with validation errors but dont stop the edit
});

Highlight Validation

If you are using the highlight validation mode then Tabulator provides a variety of ways to check the validation state of different cells in the table.

Retrieve Invalid Cells

The getInvalidCells method returns an array of Cell Components for all cells flagged as invalid after a user edit.

var invalid = table.getInvalidCells();

Tabulator will continune to add cells to this list until the table in the data is replaced by the setData function or the invalid list is cleared.

Check Cell as Passed Validation

The isValid can be called on a Cell Component to check if a cell has previously passed a validation check without revalidating it.

var valid = cell.isValid();

This will return a value of true if every cell passes validation, or false if it fails validation.

This function is different from the validate function which activly validates the cell, the isValid function only checks to see if a user has edited the cell and that it has passed validation when that happened

Clear Invalid Validation

You can clear the invalid validation state of a cell in a couple of ways.

The clearValidation can be called on a Cell Component to clear the invalid flag used by the isValid function and mark the cell as valid.

cell.clearValidation();

Alternativly, the clearCellValidation can be called on the table to clear the invalid state on all cells in the table

table.clearCellValidation();

Or optionally you can pass in a Cell Component or an array of Cell Components to the clearCellValidation function to clear the invalid state on specific cells

table.clearCellValidation([cell1, cell2]);

Manual Validation

If you are using the manual validation mode then Tabulator provides a variety of ways to trigger validation of the table.

Table Validation

You can validate the whole table in one go by calling the validate method on the table instance.

var valid = table.validate();

This will return a value of true if every cell passes validation, if any cells fail, then it will return an array of Cell Components representing each cell that has failed validation.

Row Validation

You can validate a row by calling the validate method on any Row Component

var valid = row.validate();

This will return a value of true if every cell passes validation, if any cells fail, then it will return an array of Cell Components representing each cell in that row that has failed validation.

Column Validation

You can validate a column by calling the validate method on any Column Component

var valid = column.validate();

This will return a value of true if every cell passes validation, if any cells fail, then it will return an array of Cell Components representing each cell in that column that has failed validation.

Cell Validation

You can validate a cell by calling the validate method on any Cell Component

var valid = cell.validate();

This will return a value of true if every cell passes validation, or false if it param validation.

Built In Validators

New string comparison validators have been added in this release.

Starts With

The starts validator allows string values that start with the parameter (case insensitive)

 {title:"Example", field:"example", validator:"starts:bob"} \\value must start with 'bob'

Ends With

The ends validator allows string values that start with the parameter (case insensitive)

 {title:"Example", field:"example", validator:"ends:green"} \\value must end with 'green'

Formatters

Date Time Formatter

The datetime formatter has a new timezone param that can be used to set the timezone for a date time.

{title:"Example", field:"example", formatter:"datetime", formatterParams:{
    outputFormat:"DD/MM/YY HH:ii",
    timezone:"America/Los_Angeles",
}}

It will accept any valid Moment Timezone. In order to use this property you must include the Moment Timezone library in your project, in addition to moment.js

Pagination

Pagination Size Selector Show All Rows

You can now pass pass a boolean value of true into the paginationSizeSelector array, this will show an "All" option that will show all available rows on one page

var table = new Tabulator("#example-table", {
    pagination:"local",
    paginationSize:10,
    paginationSizeSelector:[10, 25, 50, 100, true], //select list with an "all" option at the end of the list
});

Localization

Pagination Size Selector All Option

With the addition of the "All" option for the paginationSizeSelector, there is now a matching localization property to allow customisation of the wording

var table = new Tabulator("#example-table", {
    langs:{
    "en":{
    "pagination":{
    "all":"All",
},
},
},
});

Pagination Page Button Tooltip Option

There is now a page_title localization property to allow customisation of the wording of the tooltip when hovering over page number buttons

var table = new Tabulator("#example-table", {
    langs:{
    "en":{
    "pagination":{
    "page_title":"Show Page",
},
},
},
});

Frozen Rows

Check Row Frozen State

The isFrozen function on a Row Component will return a boolean representing the current frozen state of the row.

var frozen = row.isFrozen();

Menus

Row Group Header Context Menu

You can now add a right click context menu to row group headers passing an array of menu items to the groupContextMenu option in that columns definition.

var table = new Tabulator("#example-table", {
    groupContextMenu:[
        {
            label:"Hide Group",
            action:function(e, group){
                //e - context click event
                //group - group component for group

                group.hide();
            }
        },
    ]
});

Column Group Header Menus

Column header menus can also be added to column groups using the same headerMenu option, but declared in the column group object

//define row context menu
 var headerMenu = [
    {
        label:"Hide Column",
        action:function(e, column){
            column.hide();
        }
    },
]

//add header menu in column definition
var table = new Tabulator("#example-table", {
    columns:[
        {
            title:"Column Group",
            headerMenu:headerMenu, //add a menu to this column header
            columns:[
                {title:"Name", field:"name", width:200},
                {title:"Age", field:"age", width:200}
            ]
        }
    ]
});

Column Group Header Context Menus

Column header context menus can also be added to column groups using the same headerContextMenu option, but declared in the column group object

//define row context menu
 var headerContextMenu = [
    {
        label:"Hide Column",
        action:function(e, column){
            column.hide();
        }
    },
]

//add header menu in column definition
var table = new Tabulator("#example-table", {
    columns:[
        {
            title:"Column Group",
            headerContextMenu:headerContextMenu, //add a context menu to this column header
            columns:[
                {title:"Name", field:"name", width:200},
                {title:"Age", field:"age", width:200}
            ]
        }
    ]
});

If you declare context menu in both column headers and column group headers then which menu appears will depend on where the user clicks.

Printing

Group Header

When printing you may want to apply a different group header from the one usualy used in the table. You can now do this using the groupHeaderPrint table option, which takes the same inputs as the standard groupHeader property.

var table = new Tabulator("#example-table", {
    groupHeader: function(value, count, data, group){
    return value + "<span style='color:#d00; margin-left:10px;'>(" + count + " item)</span>";
},
groupHeaderPrint: function(value, count, data, group){
return value + "<span style='color:#d00; margin-left:10px;'></span>";
},
});

Passing a value of false into groupHeaderPrint will cause the header to show the groups key as plain text

Column Header Titles

When printing you may want to apply a different columnheader title from the one usualy used in the table. You can now do this using the titlePrint column definition option, which takes the same inputs as the standard title property.

var table = new Tabulator("#example-table", {
    columns:[
    {title:"Age", titlePrint:"User Age", field:"age"},
    ]
});

Clipboard

Group Header

When copying to clipboard you may want to apply a different group header from the one usualy used in the table. You can now do this using the groupHeaderClipboard table option, which takes the same inputs as the standard groupHeader property.

var table = new Tabulator("#example-table", {
    groupHeader: function(value, count, data, group){
    return value + "<span style='color:#d00; margin-left:10px;'>(" + count + " item)</span>";
},
groupHeaderClipboard: function(value, count, data, group){
return value + "<span style='color:#d00; margin-left:10px;'></span>";
},
});

Passing a value of false into groupHeaderClipboard will cause the header to show the groups key as plain text

Column Header Titles

When copying to clipboard you may want to apply a different columnheader title from the one usualy used in the table. You can now do this using the titleClipboard column definition option, which takes the same inputs as the standard title property.

var table = new Tabulator("#example-table", {
    columns:[
    {title:"Age", titleClipboard:"User Age", field:"age"},
    ]
});

HTML Output

Group Header

When the getHtml function is called you may want to apply a different group header from the one usualy used in the table. You can now do this using the groupHeaderHtmlOutput table option, which takes the same inputs as the standard groupHeader property.

var table = new Tabulator("#example-table", {
    groupHeader: function(value, count, data, group){
    return value + "<span style='color:#d00; margin-left:10px;'>(" + count + " item)</span>";
},
groupHeaderHtmlOutput: function(value, count, data, group){
return value + "<span style='color:#d00; margin-left:10px;'></span>";
},
});

Passing a value of false into groupHeaderHtmlOutput will cause the header to show the groups key as plain text

Column Header Titles

When the getHtml function is called you may want to apply a different columnheader title from the one usualy used in the table. You can now do this using the titleHtmlOutput column definition option, which takes the same inputs as the standard title property.

var table = new Tabulator("#example-table", {
    columns:[
    {title:"Age", titleHtmlOutput:"User Age", field:"age"},
    ]
});

Polyfills

The built in polyfills.js file has bee updated to include pollyfils for the Array.includes, String.includes and Object.assign functions

Bug Fixes

V4.7.0 Release

The following minor updates and bugfixes have been made:

  • Component objects are now singletons to improve memory efficiency and processing speed
  • The autocomplete editor no longer lags when typing when the values property is set to true and the table has a lot of rows
  • The tabNewEndRow option now works correctly when passing in an object as its value.
  • Sorters and formatters involving time, now accept 24 hour time formats by default rather than 12 hour
  • The setPage function now correctly handles the special values of first, next, prev and last
  • The range editor is now correctly exited when using tab or shift+tab keys
  • Escape key can now be used to exit context menus
  • Left and right arrow keys can now be used to move the cursor in the autocomplete editor
  • Fixed issue with star editor where it wasnt loosing focus after a successful edit, preventing the next edit
  • The dataSorted callback is now passed the correct row components when used on a table using data trees

V4.7.1 Release

The following minor updates and bugfixes have been made:

  • cell context menu propagation to row context menu is no longer blocked when the cell context menu generation function returns false
  • select header filter in multiselect mode can now be cleared of value by clicking the cross on the input element
  • values for the select header filter in multiselect mode now persist correctly between edits of the filter value
  • typing in the select header filter in multiselect mode is now blocked
  • fixed regression in select header filter when in single value mode, values can now be correctly selected
  • values are now correctly parsed into select editor on initialization
  • deleting cells no longer causes error if validation is not enabled
  • when deleting cells make sure they are attached to a parent before attempting to remove them
  • the validationFailed callback is now triggered when validation fails in highlight validation mode

V4.7.2 Release

The following minor updates and bugfixes have been made:

  • The table is now horizontally shifted into focus when a cell is being edited
  • A regression with the setDataFromLocalFile function has been fixed
  • Row components are now correctly detached from table modules before being wiped on new table data
  • The dataLoaded callback is now triggered after the table has been rendered when new data is loaded into the table
  • The autocomplete editor now correctly loads its initial value when used as a header filter