Release Notes
- Build Tools
- Layout
- Downloads
- Columns
- Grouping
- Trees
- Movable Rows
- Filtering
- Editing
- Validation
- Formatters
- Pagination
- Localization
- Frozen Rows
- Menus
- Printing
- Clipboard
- HTML Output
- Polyfills
- Bug Fixes
Build Tools
With this release 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 widths 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 default, 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 regardless of filters
var table = new Tabulator("#example-table", { downloadRowRange:"selected", //change default selector to selected });
You can override the downloadRowRange option when downloading 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 generation 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 column header 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 = []; //iterate 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": //iterate 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 object represents a row of data in the table arranged in the order they currently appear. You should iterate 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 alignment 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 column 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 option, 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 edited 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 continue 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 edited. 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 coming 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 function 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 don't 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 continue 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 actively 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 column header 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 column header 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 column header 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