Release Notes
- Initialization
- Module Building
- Themes
- Resizable Columns
- Mutators
- Pagination
- Menus
- Popups
- Tooltips
- Alerts
- Rows
- Sorting
- Formatting
- Editing
- Validation
- Filters
- Internal Events
- Bug Fixes
Initialization
Initialization
As of version 5.0 Tabulator has moved to using an asynchronous initialization process, allowing a consistent initialization experience between async and synchronous data sources, also allowing binding of the events system to the table before initialization is completed.
The result of this is that you cannot safely call most functions directly on the table before it has finished initializing, when the tableBuilt event has fired.
This has resulted in confusion with some developers when migrating from older versions, as some functionality appears to break without warning.
A console warning message has now been added to all module and table functions that could cause issues if called when the table is initializing.
Initialization Warning
Enabled by default this will provide a console warning if you try and call an unsafe function on the table before it has been initialized.
You can disable this using the debugInitialization option in the table constructor
var table = new Tabulator("#example-table", { debugInitialization:false, //disable option warnings });
Module Building
Initialization Order
When building a custom module, the optional moduleInitOrder property can be used to determine the order in which the module is initialized, by default modules are initialized with a value of 0, if you want your module to be initialized before other modules use a minus number, if you want it inialized after use a positive number.
CustomModule.moduleInitOrder = 10;
Popups
A new internal popup management tool has been added to the Module class to ensure a consistent behaviour and look and feel when creating popup elements for things like menus, tooltips, popups and editors.
To use the popup system you must first build up an element containing the contents of your popup. You then pass this to the popup function on the module, which will return an instance of a Popup class that you can then control with a range of functions:
// Build popup contents var tooltipContents = document.createElement("div"); tooltipContents.classList.add("tabulator-tooltip"); tooltipContents.innerHTML = "Hey, im a tooltip!"; // Create instance of tooltip var popup = this.popup(tooltipContents);
Popup Positioning
By default Tabulator will append the popup element to the body element of the DOM as this allows the popup to appear correctly in the vast majority of situations.
There are some circumstances where you may want the popup to be appended to a different element, such as the body of a modal, so that the popup is contained with that element.
In these circumstances you can use the popupContainer option to specify the element that the popup should be appended to.
var table = new Tabulator("#example-table", { popupContainer:"#modal-div", //append popup to this element });
The popupContainer option can accept one of the following values:
- false - Append popup to the body element (default)
- true - Append popup to the table
- CSS selector string - A valid CSS selector string
- DOM node - A DOM Node
If Tabulator cannot find a matching element from the property, it will default to the document body element.
Container Position
popup elements are positioned absolutely inside their container. For this reason you must make sure that your container has its position defined in CSS
Parent Element
The element you pass into the popupContainer option must be a parent of the table element or it will be ignored
Show Popup
When you are ready to show your popup, you need to call the show function on the popup instance. This function takes its destination as its first argument, which can be one of three types.
Show By Event
If a user is triggering the popup by an event such as a touch or click then you can pass this event to the show function and Tabulator will then place the element with its top left corner at the point of the click event.
popup.show(e);
Show By Element
If you want to show a popup aligned with another element on the table, pass the element itself into the show function and Tabulator will then align the popup with that element. This option is particularly useful when loading submenus, if you pass the element that was clicked on the child element can be aligned with the list item that spawned it.
The first argument is the element to align the popup with, The second argument is optional and is the side of the element to align the popup with, this should be a string and can either be right or bottom. if you leave this value out it will default to right
popup.show(element, "below");
Show By Coordinates
If you want to specify the exact x and y coordinates that the popup should be shown, these can be passed in as the first and second arguments of the show function.
popup.show(200, 250);
It is worth noting that these coordinates are relative to the position of the tables containing element as set on the table popupContainer option. (Defaults to document body)
Hide Popup
To hide a visible popup, call the hide function on the popup instance.
popup.hide();
If the menu has any children, these will also be hidden
Hide Popup On Blur
If you would like your popup to automatically close when it looses focus, you can call the hideOnBlur function immediatly after showing the popup.
popup.show().hideOnBlur();
This function only needs to be called on the parent popup, all other children popups will automatically be hidden when the parent is hidden.
You can optionally pass a callback into the hideOnBlur function that will be triggered when the menu is hidden
popup.show().hideOnBlur(() => { //do something });
Popup Children
If you are building out a navigatable menu system, then you can sometimes want child menus to be spawned from the parent.
Once a popup is visible, if you need to add chidren you can call the child function, passing in the element containing the child menu, this will return a new popup instace for the child that is linked to the parent so if the parent is hidden the child will be too, but not the other way round.
You can then call the show function on the child passing the element inside the parent that called it, the child element will then be positioned relative to that element.
// Build popup contents var menu = document.createElement("ul"); menu.classList.add("tabulator-menu"); // Create instance of menu var popup = this.popup(tooltipContents); // Generate menu items for(let i=1 ; i<5 ; i++){ let item = document.createElement("li"); item.innerHTML = "Item " + i; // Open child menu on click item.addEventListener("click", (e) => { //create child menu var childMenu = document.createElement("div"); childMenu.classList.add("tabulator-menu"); childMenu.innerHTML = "Hey, im a menu!"; //create child and show next to the parent menu item; popup.child(childMenu).show(item); }); } // Show menu popup.show(25, 15);
Single Child Limit
A popup can only have one direct child (children can have children of their own), adding a second direct child to a popup will close the first automatically. in the same way that you can only look at one submenu of a list at the same time.
Popup Function Chaining
Once you have your popup instance, you can then call a range of functions on it to control how it behaves.
Functions can be chained one after the other to make things simpler if needed.
popup.show(200, 150).hideOnBlur();
Alerts
Access to the internal table alert functionality has been added to the Module class to allow modules to more directly message users when needed.
Alerts provide full table modal take over messages, with a semi transparent full table sized backgound and a centered message. These are used for example to show a loading message when the table is loading remote data via ajax request.
Showing an Alert
To show an alert, call the alert function on the module. Passing the message into the first argument of the function.
this.alert("This is an alert!");
The alert function will accept one of several diffrent types alert:
- string - A text string or valid HTML content for the alert
- DOM node - A DOM Node of the element to be included inside the alert
Alert Styles
The alert function also provides a way to style the alert message being presented to the user. There are two built in styles:
- msg - A black border with black text (default)
- error - A red border with red text
You can pass the style into the optional second argument of the alert function:
this.alert("This is an alert!", "error");
Behind the scenes this works by applying the tabulator-alert-state-error class to the .tabulator-alert-msg element. You can therefor provide any string you like to the second argument and then use it to apply custom styles to the alert.
For example if we passed a value of warning to the second argument of the alertfunction the tabulator-alert-state-warning class to the .tabulator-alert-msg element
Clearing an Alert
To clear an active alert, call the clearAlert funtion on the this.
this.clearAlert();
Footer Manager
The footer manager has been decoupled from the modules that use the footer, making it more extensible and easier to manage.
As a result there are now three new functions available to modules to aid in manipulating the table footer.
Append Element
The footerAppend function will append an element to the flex aranged area at the bottom of the footer. each element added to the footer will be spaced out with the other elements. (this is used by the pagination module to add pagination controls)
var button = document.createElement("button"); this.footerAppend(button); //Append button to footer
Prepend Element
The footerPrepend function will prepend an element to above the flex aranged area at the bottom of the footer. (This is used by the column calculations module to add the bottom calcs row)
var label = document.createElement("label"); this.footerPrepend(label); //Prepend button to top of footer
Remove Element
The footerRemove function will remove an element that has previously been added to the footer
var label = document.createElement("label"); this.footerPrepend(label); //Prepend label to top of footer this.footerRemove(label); //Remove label from footer
Themes
Bootstrap 5
This release includes a new theme for the v5 release of the bootstrap framework
This can be included from the dist folder at /dist/css/tabulator_bootstrap5.min.css
Resizable Columns
The ResizeColumns module has been completely rebuilt for this release.
Cell resize handles are now appended between cells in the row using negative margins to shift them over the cells themselves. This allows for continuous resize handles that are not interrupted by the cells borders.
As a result of the resize handles should now render correctly in scenarios where some columns are not resizable, with handles only being shown on columns that can be resized.
The module has also hads its efficiency improved, only binding to internal table events when it detects that a column is resizabe.
Maintain Column Fit When Resizing
If the resizableColumnFit table definition option is set to true, then when you resize a column its neighbouring column has the opposite resize applied to keep to total width of columns the same.
var table = new Tabulator("#example-table", { resizableColumnFit:true, //maintain the fit of columns when resizing columns:[ {title:"Name", field:"name", resizable:true} ] });
Resize Overflow
It is worth noting that should the neighbouring column reach is max or min width while the reszie is occurring, that the next column over will then begin to resize in its place. If the resize runs out of columns then the total width of all the columns will change.
The example below shows the new feature in action, try resizing one of the columns:
Mutators
Linked Mutators
You may want to make a column that calculates its value based on the value of other columns, for example:
[ {title:"a", field:"a"}, {title:"b", field:"b"}, {title:"c", field:"c", mutator:function(value, data){ return data.a + data.b; }}, ]
In this case it is likely that you would want the value in column c to be updated when the user changes the value in columns a or b. But this wont happen by default. Mutators are only run when the data is initially loaded into the table, and when the value of a specific cell is changed.
To keep processing to a minimum, Tabulator will only run mutators on cells with changed values, not all cells in a row.
You can use the mutateLink option on a column definition to tell it to trigger the mutation of another column when its value has changed. You can pass in a string of the field name of the column to be mutated, or an array of field name strings if you want more than one mutator triggered.
[ {title:"a", field:"a", editor:"number", mutateLink:"c"}, //trigger "c" column mutator when edited {title:"b", field:"b", editor:"number", mutateLink:"c"}, //trigger "c" column mutator when edited {title:"c", field:"c", mutator:function(value, data){ return data.a + data.b; }}, ]
Pagination
Events
Page Size Changed
Whenever the page size of the table is set or changed the pageSizeChanged event is called, passing the number of rows per page as an argument.
table.on("pageSizeChanged", function(pagesize){ //pagesize - the number of rows per page });
Menus
Menu Container
As a result of the introduction of the built in popup functionality in this release, the menu module is no longer responsible for creation of its own popups.
For this reason the module specific menuContainer has been replaced with the table wide popupContainer option.
var table = new Tabulator("#example-table", { popupContainer:true, //show menus and other popups relative to the table element });
Column Header Menu Icon
When you insert a header menu, Tabulator will add a button to the header element with an ⋮ icon. You can now change the contents of this button using headerMenuIcon column definition option
The headerMenuIcon option will accept one of three types of value. You can pass in a string for the HTML contents of the button
{title:"Name", field:"name", headerMenuIcon:"<i class='fas fa-filter'></i>", headerMenu:headerMenu}
Or you can pass the DOM node for the button. Though be careful not to pass the same node to multple columns or you may run into issues.
//define element var buttonContents = document.createElement("span"); buttonContents.innerText = "Filter"; //column definition {title:"Name", field:"name", headerMenuIcon:buttonContents, headerMenu:headerMenu}
Or you can define a function that is called when the column header is rendered that should return either an HTML string or the contents of the element. This funtion is passed the column component as its first argument
{title:"Name", field:"name", headerMenuIcon:function(component){ //component - column component for header return "<i class='fas fa-filter'></i>"; }}
Popups
A new Popup module has been added in this release. Popups work in a similar way to menus, but instead of only displaying lists of menu items then allow you to fill them with any custom content you like, text, input elements, forms, anything you fancy.
The example below has two type of popup, if you click on a row you will see a popup with more row details, and if you click on the filter icon in the column header you will see a popup that lets you filter the column data:
Defining a Popup
When definind a popup you can pass one of three types of value into the option. You can pass in a string for the HTML contents of the button
{title:"Name", field:"name", clickPopup:"Hey, Im a Popup!"}
Or you can pass the DOM node for the button. Though be careful not to pass the same node to multple columns or you may run into issues.
//define element var popupContents = document.createElement("span"); popupContents.innerText = "Hey Im a Popup!"; //column definition {title:"Name", field:"name", clickPopup:popupContents}
Or you can define a function that is called when the popup is rendered that should return either an HTML string or the contents of the element. This funtion is passed the mouse/touch event as its first argument and the component of the element that triggered the popup as the second argument
{title:"Name", field:"name", clickPopup:function(e, component, onRendered){ //e - the mouse/touch event that triggered the popup //component - column/row/cell component that triggered this popup //onRendered - function to call when the formatter has been rendered return "Hey Im a Popup!"; }}
The onRendered callback function passed into the third argument allows you to register a callback that will be triggered when the popup has been added to the DOM but before its position is confirmed. This can be useful when you are trying to use a 3rd party library that needs the element to be visible before it can be instatiated
To use this function you need to pass a callback that runs any of your required code as the only argument. The example below uses the jQuery sparkline widget to add a small chart to the popup
{title:"Name", field:"name", clickPopup:function(e, component, onRendered){ //e - the mouse/touch event that triggered the popup //component - column/row/cell component that triggered this popup //onRendered - function to call when the formatter has been rendered var element = document.createElement("div"); onRendered(function(){ $(element).sparkline(component.getValue(), {width:"100%", type:"bar"}); }); return element; }}
Close On Blur
Popups will automatically close when focus on the popup element is lost.
Column Header Popups
Column Header Popup
You can add a popup to any column by passing the popup contents to the headerPopup option in that columns definition.
Adding a header popup will cause a ⋮ button to appear to the left of the column header title. clicking on this button will open the popup.
var table = new Tabulator("#example-table", { columns:[ {title:"Name", field:"name", headerPopup:"Im a Popup"}, //add popup button to this column header ] });
Column Header Popup Icon
When you insert a header popup, Tabulator will add a button to the header element with an ⋮ icon. You can change the contents of this button using headerPopupIcon column definition option
The headerPopupIcon option will accept one of three types of value. You can pass in a string for the HTML contents of the button
{title:"Name", field:"name", headerPopupIcon:"<i class='fas fa-bars'></i>"}
Or you can pass the DOM node for the button. Though be careful not to pass the same node to multple columns or you may run into issues.
//define element var buttonContents = document.createElement("span"); buttonContents.innerText = "Popup"; //column definition {title:"Name", field:"name", headerPopupIcon:buttonContents}
Or you can define a function that is called when the column header is rendered that should return either an HTML string or the contents of the element. This funtion is passed the column component as its first argument
{title:"Name", field:"name", headerPopupIcon:function(component){ //component - column component for header return "<i class='fas fa-bars'></i>"; }}
Column Header Context Popup
You can add a right click popup to any column by passing the popup contents to the headerContextPopup option in that columns definition.
var table = new Tabulator("#example-table", { columns:[ {title:"Name", field:"name", headerContextPopup:"Im a Popup"}, //add context popup to this column header ] });
Mobile Devices
When used on a mobile device the context menu will be triggered by a long press on the element
Row Popups
Row Click Popup
You can add a click popup to any row by passing the popup contents to the rowClickPopup option in the table constructor object.
var table = new Tabulator("#example-table", { rowClickPopup:"Im a Popup" });
Row Context Popup
You can add a right click popup to any row by passing the popup contents to the rowContextPopup option in the table constructor object.
var table = new Tabulator("#example-table", { rowContextPopup:"Im a Popup" });
Mobile Devices
When used on a mobile device the context menu will be triggered by a long press on the element
Cell Popups
Cell Click Popup
You can add a click popup to any cell by passing the popup contents to the clickPopup option in that columns definition.
var table = new Tabulator("#example-table", { columns:[ {title:"Name", field:"name", clickPopup:"Im a Popup"} //add cell click popup ] });
Cell Context Popup
You can add a right click popup to any cell by passing the popup contents to the contextPopup option in that columns definition.
var table = new Tabulator("#example-table", { columns:[ {title:"Name", field:"name", contextPopup:"Im a Popup"} //add cell context popup ] });
Group Popups
Group Header Click Popup
You can add a click popup to any group header by passing the popup contents to the groupClickPopup option in the table constructor object.
var table = new Tabulator("#example-table", { groupClickPopup:"Im a Popup" });
Group Header Context Popup
You can add a right click popup to any group header by passing the popup contents to the groupContextPopup option in the table constructor object.
var table = new Tabulator("#example-table", { groupContextPopup:"Im a Popup" });
Popup Events
A couple of popup events have been added to help track when popup functionality is in use
Popup Opened
The popupOpened callback is triggered when a popup is opened.
table.on("popupOpened", function(component){ //component - the component the popup has been opened on (could be cell, row or column depending on popup) });
Popup Closed
The popupClosed callback is triggered when a popup is closed.
table.on("popupClosed", function(component){ //component - the component the popup has been closed for (could be cell, row or column depending on popup) });
Tooltips
Tooltip functionality has been moved into its own module, and now uses the internal table popup functionality to generate tooltips instead of the browser based title attribute on the cell elements.
The major benifit of this approach is that tool tips are now fully customisable, you can style them as you like using the new tabulator-tooltip class, and they now support full HTML content.
Tooltip Generation Mode
As a result of this migration the tooltipGenerationMode table option has been removed as tooltips are now always generated at the moment they are displayed.
Cell Tooltips
You can set tooltips to be displayed when the cursor hovers over cells, these can contain any value and be formatted in any way you like.
Tooltips can either be set per column in the column definition object
//column definition object in the columns array {title:"Name", field:"name", tooltip:true},
Or globally in the columnDefaults object:
var table = new Tabulator("#example-table", { columnDefaults:{ tooltip:true, } });
The tooltip parameter can take three different types of value
- boolean - a value of false disables the tooltip, a value of true sets the tooltip of the cell to its value
- string - a string that will be displayed for all cells in the matching column/table.
- DOM Node - a DOM node for the tooltip
- function - a callback function that returns either the html/text contents for the tooltip, or a DOM node for the contents of the tooltip:
The function accepts three arguments, the first is the mouseover event object that triggered the tooltip, the second is CellComponent for the cell the tooltip is being generated for, the third argument is the onRendered function that allows you to register a callback that will be triggered when the popup has been added to the DOM but before its position is confirmed.
This function wil also allow you to style the tooltip by applying styles to the returned element if desired
var table = new Tabulator("#example-table", { columnDefaults:{ tooltip:function(e, cell, onRendered){ //e - mouseover event //cell - cell component //onRendered - onRendered callback registration function var el = document.createElement("div"); el.style.backgroundColor = "red"; el.innerText = cell.getColumn().getField() + " - " + cell.getValue(); //return cells "field - value"; return el; }, } });
Column Header Tooltips
It is also possible to set tooltips to display on the column headers. This is particularly useful when your columns are too narrow to display full header names.
Header tooltips can either be in a columns definition object:
//column definition object in the columns array {title:"name", field:"name", headerTooltip:true},
The tooltip headerTooltip can take three different types of value
- boolean - a value of false disables the tooltip, a value of true sets the tooltip of the column header to its title value.
- string - a string that will be displayed for the tooltip.
- DOM Node - a DOM node for the tooltip
- function - a callback function that returns either the html/text contents for the tooltip, or a DOM node for the contents of the tooltip:
The function accepts three arguments, the first is the mouseover event object that triggered the tooltip, the second is ColumnComponent for the column header the tooltip is being generated for, the third argument is the onRendered function that allows you to register a callback that will be triggered when the popup has been added to the DOM but before its position is confirmed.
This function wil also allow you to style the tooltip by applying styles to the returned element if desired
var table = new Tabulator("#example-table", { columnDefaults:{ headerTooltip:function(e, cell, onRendered){ //e - mouseover event //cell - cell component //onRendered - onRendered callback registration function var el = document.createElement("div"); el.style.backgroundColor = "red"; el.innerText = column.getDefinition().title; return el; }, } });
Alerts
This release provides access to Tabulators alert system. Alerts provide full table modal take over messages, with a semi transparent full table sized background and a centered message. These are used for example to show a loading message when the table is loading remote data via ajax request.
Click the buttons on the example below to see alerts in action
Showing an Alert
To show an alert, call the alert function on the table. Passing the message into the first argument of the function.
table.alert("This is an alert!");
The alert function will accept one of several diffrent types alert:
- string - A text string or valid HTML content for the alert
- DOM node - A DOM Node of the element to be included inside the alert
Alert Styles
The alert function also provides a way to style the alert message being presented to the user. There are two built in styles:
- msg - A black border with black text (default)
- error - A red border with red text
You can pass the style into the optional second argument of the alert function:
table.alert("This is an alert!", "error");
Behind the scenes this works by applying the tabulator-alert-state-error class to the .tabulator-alert-msg element. You can therefor provide any string you like to the second argument and then use it to apply custom styles to the alert.
For example if we passed a value of warning to the second argument of the alertfunction the tabulator-alert-state-warning class to the .tabulator-alert-msg element
Clearing an Alert
To clear an active alert, call the clearAlert funtion on the table.
table.clearAlert();
Rows
Fixed Row Height
You can use the new rowHeight option to force a height for all rows in the table. This should be set to an integer value in pixels. Setting the value to false will result in the rows resizing to fit their contents
var table = new Tabulator("#example-table", { rowHeight:40, //set rows to 40px height });
Sorting
Date Sorter
The date sorter will now accept a luxon DateTime object as the cell value. If this is the case then you can ignore the format option in the sorterParams.
Time Sorter
The time sorter will now accept a luxon DateTime object as the cell value. If this is the case then you can ignore the format option in the sorterParams.
Date Time Sorter
The datetime sorter will now accept a luxon DateTime object as the cell value. If this is the case then you can ignore the format option in the sorterParams.
Formatting
Link Formatter
The labelField option of the formatterParams object for the link formatter has been updated to handle accessing data in nested column fields. This will use the same seperator as the tables nestedFieldSeparator option.
{title:"Example", field:"example", formatter:"link", formatterParams:{labelField:"address.postcode"}} //set the formatter label to the value in the row data opject for the postcode property of the address object
Money Formatter
The thousand option of the formatterParams object for the money formatter will now accept a boolean value of false to disable the thousand separator
{title:"Example", field:"example", formatter:"money", formatterParams:{thousand:false}} //disable thousand separator
Date Time Formatter
The datetime formatter will now accept a luxon DateTime object as the cell value. If this is the case then you can ignore the inputFormat option in the formatterParams.
Date Time Difference Formatter
Date Humanizing
The humanize option of the formatterParams object for the datetimediff formatter has been restored to functionality in this release, using the toHuman functionality introduced in the 2.3 release of Luxon.
As a result of this the unit option will now also accept an array of units that can be used to define how the diference will be humanized
{title:"Example", field:"example", formatter:"datetimediff", formatterParams:{ units:["months", "days", "hours"], humanize:true, }}
Luxon DateTime Input
The datetimediff formatter will now accept a luxon DateTime object as the cell value. If this is the case then you can ignore the inputFormat option in the formatterParams.
TickCross Formatter
The tickCross formatter has a new trueValue param that allows you to define the exact value that causes the tick to be shown
{title:"Example", field:"example", editor:"tickCross", editorParams:{ trueValue:"car", //show a tick if the cells value is the string "car" }}
Editing
Contents Selection on Focus
The input, number and textarea editors have been update to include the new selectContents editor param.
When the selectContents parameter is set to true the editor will automatically select its text contents when its cell is focused.
{title:"Example", field:"example", editor:"input", editorParams:{selectContents:true}}
Checkbox Editor
The tickCross editor has had two new params added. The trueValue and falseValue options allow you to define that values retured from the editor
{title:"Example", field:"example", editor:"tickCross", editorParams:{ trueValue:"car", //return a value of "car" if the checkbox is ticked falseValue:"bike", //return a value of "bike" if the checkbox is unticked }}
Select Editor
The select editor has been removed and replaced with the new list editor
Autocomplete Editor
The autocomplete editor has been removed and replaced with the new list editor
List (Select/Autocomplete)
The new list editor replaces the existing select and autocomplete and provides a wide range of options for all your list based editing needs.
The editor creates a dropdown list to allow the user to select from some predefined options, by default it functions as a select list type element but can also be configured to function as an autocomplete.
{title:"Example", field:"example", editor:"list", editorParams:{ //Value Options (You should use ONE of these per editor) values:["red", "green", "blue", "orange"], //an array of values or value/label objects valuesURL: "http://myvalues.com", //a url to load the values from valuesLookup:"active", //get the values from the currently active rows in this column //Value Lookup Configuration (use these with valuesLookup Option) valuesLookupField:"color", //the field to lookup values from //General Options clearable:true, //show clear "x" button on editpr itemFormatter:function(label, value, item, element){ //label - the text lable for the item //value - the value for the item //item - the original value object for the item //element - the DOM element for the item return "<strong>" + label + " </strong><br/><div>" + item.subtitle + "</div>"; }, elementAttributes:{ //set attributes on input element maxlength:"10", //set the maximum character length of the input element to 10 characters }, verticalNavigation:"hybrid", //navigate to new row when at the top or bottom of the selection list sort:"asc", //sort direction for the values list defaultValue:"Steve Johnson", //the value that should be selected by default if the cells value is undefined emptyValue:null, //the value that should be asigned to the cell if the editor is left with an empty value maxWidth:true, //prevent width of list item from exceeding width of cell placeholderLoading:"Loading List...", //set custom placeholder when loading list values placeholderEmpty:"No Results Found", set custom placeholder when list is empty //Select Options (only available when autocomplete:false) multiselect:true, //allow selection of multiple items from the list //Autocomplete Options (only available when autocomplete:true) autocomplete:true, //enable autocomplete mode, filterFunc:function(term, label, value, item){ //replace built in filter function with custom //term - the string being searched for //label - the text lable for the item //value - the value for the item //item - the original value object for the item return label === term; }, filterRemote:true, //pass filter term to remote server in request instead of filtering filterDelay:100, //delay in milliseconds after typing before filter begins allowEmpty:true, //allow the user to leave the cell empty listOnEmpty:true, //show all values in the list if the input is empty mask:"AAA-999", //apply input mask to text entry freetext:true, //allow the user to set the value of the cell to a free text entry }}
The editor has many optional properties for the editorParams object:
- values - either an array of values, or value objects (this is explained in more detail in the next section)
- valuesURL - the url to load the values for the list from
- valuesLookup - lookup the values for the list from a column in the table, this option sets which range of data should be loaded, or provides a function to dynamically set the data
- valuesLookupField - the field the values for this list should be looked up from
- clearable - adds a clear button to the right of the editor to allow the user to empty the current value
- itemFormatter - change how the items in the list are displayed
- elementAttributes - set attributes directly on the input element
-
verticalNavigation - determine how use of the up/down arrow keys will affect the editor, this can take three different types of value:
- editor - value selection up and down the list, will not navigate round the table (default)
- table - the arrow keys will navigate to the prev/next row and will not change the selected value in the list
- hybrid - the arrow keys move the value selection up and down the list, when it reaches the end of the list it moves on to the adjacent row
- sort - sort the items in the list, either asc or desc or a custom sorter function
- defaultValue - set the value that should be selected by default if the cells value is undefined
- emptyValue - set the value that will be set on the cell if the user leave the input empty
- maxWidth - the list will by default expand to fit the contents of the list, if you wish to constrain the width of the list, you can either pass an integer for the maximum width of the list in pixels, or the value true which will fit the list to the width of the current cell
- placeholderLoading - set custom placeholder when loading list values, this can either be a text string, a valid HTML string a DOM Element, or a function, that will be called and passed in the cell component and the current list element and should return one of the above valid placeholder values.
- placeholderEmpty - set custom placeholder when list is empty, this can either be a text string, a valid HTML string a DOM Element, or a function, that will be called and passed in the cell component and the current list element and should return one of the above valid placeholder values.
- multiselect - set this to true to allow the user to choose multiple values. With this option enabled the editor will accept and return an array of values. (this option is only available when the autocomplete option is disabled)
- autocomplete - set this to true to allow the user to filter the options list by typing in the input.
- filterFunc - a custom filter function to define how an autocomplete should filter its row values. (this option is only available when the autocomplete option is enabled)
- filterRemote - When using a remote data source like Ajax, this tells hte auto complete to submit the search term as part of the request instead of triggering a local filter function. (this option is only available when the autocomplete option is enabled)
- filterDelay - The delay in milliseconds between a person typing a letter and the filter begginging, used to delay filtering until the user has finished typing. (default value 300 - this option is only available when the autocomplete option is enabled)
- allowEmpty - allow the user to save an empty value to the cell. (this option is only available when the autocomplete option is enabled)
- listOnEmpty - show the whole list of values when the cell is empty. (this option is only available when the autocomplete option is enabled)
- mask - apply a mask to the input to allow characters to be entered only in a certain order (this option is only available when the autocomplete option is enabled) (see Text Input Masking for more information)
- freetext - allow the user to press enter to save a value to the cell that is not in the list (this option is only available when the autocomplete option is enabled)
Values
There are multiple ways you can define the values in list depending on your needs, the sections below outline each detail
Values - Array / Object
You can pass in an array of values to the vaulues param:
{title:"Example", field:"example", editor:"autocomplete", editorParams:{values:["red", "green", "blue", "orange"]}}
In this mode, the value will also be used as the label for the list item.
If you want to show a different label to the value you want to store, you can pass in an object, where the key of each property is the value that will be stored if it is selected, and the value of each property will be the label displayed for it in the list.
{title:"Name", field:"name", editor:"autocomplete", editorParams:{ values:{ "steve":"Steve Boberson", "bob":"Bob Jimmerson", "jim":"Jim Stevenson", } }}
You can alternativly pass an array of value objects, each with a value and label object, if you would like to specify a different label for each value and their order. You can also add custom properties to each of the objects that will be accessible in the sort, filter and layout functions if you want to use other data in your list
With an aray of value objects, you can also create groups of options using the options property on an item and passing an array of value objects to the prop.
In the complex structure you can also use the elementAttributes property to define attributes directly on the list item element
{title:"Name", field:"name", editor:"select", editorParams:{ values:[ { label:"Steve Boberson", value:"steve", keywords:"red, green, blue, orange", // custom field description:"Likes to drive a car", // custom field }, { //option group label:"Men", options:[ //options in option group { label:"Steve Boberson", value:"steve", elementAttributes:{ class:"primary-name", } }, { label:"Bob Jimmerson", value:"bob", }, ] }, { //option group label:"Women", options:[ //options in option group { label:"Jenny Jillerson", value:"jenny", }, { label:"Jill Betterson", value:"jill", }, ] }, {//ungrouped option label:"Other", value:"other", }, ] }}
Values - Lookup From Column
Using the valuesLookup option cause the editor to lookup the unique values from a column on the table.
When using the valuesLookup option, it is used to specify the range of rows that shoul be used for the lookup, and takes any of the standardRow Range Lookup.
It should be used in conjunction with the valuesLookupField option in which you can set the field name for the column you want to lookup the data from.
{title:"Name", field:"name", editor:"autocomplete", editorParams:{ valuesLookup:true, //lookup all unique values valuesLookupField:"people", //lookup all unique values from the people column }}
If you leave out the valuesLookupField option it will lookup the values from the current column:
{title:"Name", field:"name", editor:"autocomplete", editorParams:{ valuesLookup:"active", //lookup filtered unique values in this column }}
Alternativly if you want to generate the content in a different way, you can pass a callback to the valuesLookup option that should return a value array or object. The callback is passed in the Cell Component for the cell being edited, and the currenty value of the input in case you are using the filterRemote option.
{title:"Name", field:"name", editor:"autocomplete", editorParams:{ valuesLookup:function(cell, filterTerm){ //cell - the cell component for the current cell //filterTerm - the current value of the input element return [ { label:"Steve Boberson", value:"steve", }, { label:"Bob Jimmerson", value:"bob", }, { label:"Jenny Jillerson", value:"jenny", }, { label:"Jill Betterson", value:"jill", }, ]; } }}
If you want to carry out an asynchronous function in this callback, like a custom ajax request, then you can return a promise from this function that should resolve with the value array / object.
Values - Remote Ajax Source
If you want to lookup data from a remote ajax source, you can get the table to make a simple AJAX get request to a url by passing it to the valuesURL option.
If you are also using filterRemote then the current value of the input element will aslo be passed in the request as the term parameter.
The request should respond with a JSON encoded values array/object.
{title:"Name", field:"name", editor:"autocomplete", editorParams:{ valuesURL:"http://getdata.fromhere.com", //get value list from URL }}
The valuesURL option is only intended for a simple GET ajax request. If you need to make a different/more complex request, then you should use the valuesLookup option and make the ajax request yourself.
While making the request, a placeholder element will be displayed to the user, the contents of this placeholder can be set using the placeholderLoading option. This can either be a text string, valid HTML, a DOM node or a callback function that will return one of those options. If you use a callback function, the first argument will be the Cell Component for the cell being edited.
{title:"Name", field:"name", editor:"autocomplete", editorParams:{ valuesURL:"http://getdata.fromhere.com", //get value list from URL placeholderLoading:"Loading Remote Data...", //set a custom placeholder text }}
Formatting List
By default, Tabulator will render the values list as a simple list of text values. You can choose to format the list in any way you like, using the itemFormatter option.
This option takes a callback that will be called for each item in the list, it will be passed in the value of the item the first argument, the label for the item as the second argument, the original value object for the component as its third argument, complete with any custom properties that may have been set and the containing element for the list item as the fourth argument incase you wish to directly manipulate it by applying classes etc.
The callback return a text string, valid HTML, or a DOM node for the contents of the item.
{title:"Name", field:"name", editor:"autocomplete", editorParams:{ itemFormatter:function(label, value, item, element){ //label - the text lable for the item //value - the value for the item //item - the original value object for the item //element - the DOM element for the item //return the initial label as a bold line and then second line in regular font weight containing the value of the custom "subtitle" prop set on the value item object. return "<strong>" + label + " </strong><br/><div>" + item.subtitle + "</div>"; }, }}
Sorting List
By default no sort will be applied to the values list. it will appear in the order the items were defined. You can sort the list using the sort option, this can take the string value of asc to sort the list in ascending order by label, or the string value of desc to sort the list in descending order by label.
{title:"Name", field:"name", editor:"autocomplete", editorParams:{ sort:"asc", //sort list in ascending order }}
By default, Tabulator uses an alphanumeric sort on list values. If you would like to apply a custom sort to the list, then you can also pass a callback function into this option. This callback will function in the same way as the comparison function passed to the standard JavaScript sort function, it should return -1 if value "a" is less than value "b", 1 if it is greater than, and 0 if they are equal.
The function is passed in several arguments:
{title:"Name", field:"name", editor:"autocomplete", editorParams:{ sort:(aLabel, bLabel, aValue, bValue, aItem, bItem){ //aLabel - the text lable for item a //bLabel - the text lable for item b //aValue - the value for item a //bValue - the value for item b //aItem - the original value object for item a //bItem - the original value object for item b //sort by numeric values return aValue < bValue ? -1 : (aValue == bValue ? 0 : 1); }, }}
Filtering List
When using the editor with autocomplete enabled, the list will be filtered every time the user types in the input. By default this is accomplished using a case-insensitive string comparison between the value of the input element and the label of the list item.
If you wish to filter in a different way, you can pass a callback to the filterFunc option. This option is passed four aguments, the term being searched for, the label of the item, the value of the item, and the item object. It should return true if the item matches the term and false if it does not
{title:"Name", field:"name", editor:"autocomplete", editorParams:{ filterFunc:(term, label, value, item){ //term - the string value from the input element //label - the text lable for the item //value - the value for the item //item - the original value object for the item //filter strictly against the value of the item return term === value; }, }}
If you are retreiving your data from a remote source using either the valueURL option, or a promise return from a callback on the valuesLookup option, then you can choose to filter your data remotely instead and bypass the local filter.
This can be accomplished using the filterRemote option. With this enabled, the local filter will not be run, instead the remote request will be retriggered with the current search term pass as an argument.
{title:"Name", field:"name", editor:"autocomplete", editorParams:{ valuesURL:"http://getdata.fromhere.com", //get value list from URL filterRemote:true, }}
Validation
Validation Failed Event
The validationFailed event is triggered when the value entered into a cell during an edit fails to pass validation. and now includes a list of failed validators in the third argument to the event callback
table.on("validationFailed", function(cell, value, validators){ //cell - cell component for the edited cell //value - the value that failed validation //validators - an array of validator objects that failed });
The validators argument contains a an array of validator objects for each validator that has failed. each object has a type prop which is the key for that validator (eg. "required"), and parameters prop which contains any props passed with the validator
In the example below, the validation failed on the min validator with its parameter set to 5:
[ { key:"min" parameters:5, } ]
Cell Component Validation
The cell component isValid function has been updated to return a value of true if the cell passes validation, or an array of failed validators if it fails validation.
var valid = cell.isValid();
The cell component validate function already works in this way as of version 5.0.
Filters
Events
in previous releases, the dataFiltering and dataFiltered events were passed an array of current filters that exluded the header filters. In this release this argument has been updated to include both header filters and programatic filters for the dataFiltering and dataFiltered events.
table.on("dataFiltering", function(filters){ //filters - array of all filters currently applied });
Internal Events
Subscription Order
This isnt a new feature but rather one that was missed from earlier documentation. I have included it here to bring this to peoples attention incase it is of use.
Multiple callbacks can be subscribed to the same event, and by default they will be called in the order they are subscribed.
You can pass an integer into the optional third argument of the subscribe function to determine the order that the subscriber is called. By default callbacks are subscibed with an order of 10,000. Values with a lower order are called before those of a higher order, subscriptions of the same order are called in the order that they were subscribed.
this.subscribe("example-event", function(arg1, arg2, arg3){ //do something }, 10001); //ensure this callback is executed after other default subscriptions
Edit Events
The edit module has been decoupled from the validation modules, as a result several new evens have been added in this release
Edit Success
The edit-success event is a chain type event, used by the edit module to check if any other modules consider the attempted edit to be a failure
this.subscribe("edit-success", function(cell, value) => { //cell - cell component being edited //value - proposed new value return true; });
Returningtrue will allow the edit to proceed, returning false with block the completion of the edit
Clearing Editor
The edit-editor-clear event is dispatched when the editor is being cleared after a success or cancel
this.subscribe("edit-editor-clear", function(cell, cancelled) => { //cell - cell component being edited });
Edited State Reset
The edit-edited-clear event is dispatched when the edited state of a cell is being reset
this.subscribe("edit-editor-clear", function(cell, cancelled) => { //cell - cell component being edited //cancelled - true if the clear is caused because of an edit cancel });
Footer Events
A number of new footer events have been added in this release
Footer Redrawn
The footer-redraw event is dispatched when the table footer is redrawn
this.subscribe("footer-redraw", function() => { //do something });
Column Events
A number of new column events have been added in this release
Column Renedered
The column-rendered event is dispatched when a column header is added to the DOM
this.subscribe("column-rendered", function(column) => { //column - internal column component for the rendered column });
Column Height
The column-height event is dispatched when the height of a column header is changed
this.subscribe("column-rendered", function(column) => { //column - internal column component for the column });
Cell Events
Cell Height
The cell-height event is dispatched when the height of a cell is changed
this.subscribe("cell-rendered", function(cell) => { //cell - internal cell component for the cell });
Bug Fixes
v5.2.0 Release
The following minor updates and bugfixes have been made:
- A console warning will be generated if Tabulator is instatiated on an empty table tag instead of a div
- The mouseLeave event now fires with the correct cell component
- Columns loading large amount of data while using frozen columns will no longer take a long time to load
- When adding or updating a column, recalculate frozen column positions so column is added in correct position
v5.2.1 Release
The following minor updates and bugfixes have been made:
- Fixed regression in date time and datetime sorters
- Fixed issue with column resize handles in tables with a fitColumns layout style causing horizontal scrollbars to appear
v5.2.2 Release
The following minor updates and bugfixes have been made:
- Further improved column resize handle styling for last column
- Fixed typo in ISO parsing in datetime sorter
- Fixed exception thrown from list editor when repeatedly switching between editors when used as a header filter
v5.2.3 Release
The following minor updates and bugfixes have been made:
- The renderStarted and renderCompete are now fired for render in place actions like sorting and filtering
- Fixed regression in Validation module, preventing the rowValidate and columnValidate functions from working correctly
- The persistance module will now automatically include column visibility persistence if the columns option is set to true
- Fixed issues on bootstrap 5 theme, with popups, menus and list editors having a transparent background
- Fixed visual corruption of rows outside of virtual render buffer when scrolling with frozen columns
- Grouped column moving has been correctly disabled to prevent visual corruption
- The scrollToRow functionality now correctly positions the row when there are variable height rows and the top position is used
- Child rows are now redrawn when the table.redraw(true) function is called
v5.2.4 Release
The following minor updates and bugfixes have been made:
- Grouped column calculations are now correctly updated when a data tree child row has a cell edited
- When using autoColumns and remote mode sorting or filtering, the columns will not be regenerated on a change in filter or sort, preventing an incorrect reset of the current sort/filter values
- Fixed context issue in the list editor
- Fixed regression in the resize columns module that was preventing resizing of frozen columns if there were more than one
v5.2.5 Release
The following minor updates and bugfixes have been made:
- Fix null comparison logic issues in modules
- Fixed file import issue in interaction module
- Fixed error in list editor when used as a headerFilter with the muliselect headerFilterParams option
- Fixed padding issue in bootstrap5 theme when used with table-sm class
- Fixed row styling issues in the bootstrap5 theme
- Fixed popup and list editor styling on bulma theme
- The aria-sort attribute on column headers is now set to the correct values
- Removed unneeded rowgroup aria tag from .tabulator-tableholder element
- Fixed regression in the scrollToRow function, preventing the bottom mode from working correctly
- Column header click and tap event bindings in the column definition are now correctly called only once
- Resize handles are no longer appended to the DOM for hidden columns
- Popups are now hidden when the table is destroyed
v5.2.6 Release
- Fixed regression in previous release that prevented column header sort arrows from being styled correctly
v5.2.7 Release
- Fix cell transparency issue in bootstrap 5 theme
- Fixed issue with popups persisting after table destruction if triggered at same time as destroy function call
- Fixed issue with list editor when in autocomplete mode, the enter key will now behave correctly as a submit action when clicked
- Fixed issue with list editor in multiselect mode where clicking into another editor would clear the current editor value.
- Fixed issue with the list editor where freetext values were not loading into the input when edit started