Building Modules
- Overview
- Module Structure
- Extending Other Modules
- Internal Components
- Registration
- Options
- Internal Events
- External Events
- Data & Display Handlers
- Localization
- Popups
- Alerts
- Inter-Table Communication
- Column Layout
Overview
Modules allow anyone to add custom functionality to Tabulator. By subscribing to internal table events and registering functions on the table and its components you can extend tabulator in any way you like.
This section will explain all the standard features of a module, although without practical demonstration they may seem a bit abstract. You should use this section as a reference for your module building, but consult the Example Modules Guide to see how these features are applied in practice to build a functioning module.
Import The Module Base Class
Building a modules starts by importing the Module class from the Tabulator library.
import {Tabulator, Module} from 'tabulator-tables';
Basic Structure
To create a custom module you need to extend the base Module class and then provide a minimum of two functions inside the class, the constructor and the initialize functions
class CustomModule extends Module{ static moduleName = "custom"; //module name static moduleInitOrder = 10; //when to initialize the module compared to other modules constructor(table){ super(table); //register table options //register column options //register table functions //register component functions } initialize(){ //subscribe to internal events //register data handlers } }
Module Name
The static moduleName property must be declared on the class (not an instance of the class), and be a camelCase name for the module, this is used internally by the table to act as a unique identifier for the module.
Initialization Order
The optional static 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.
The Constructor
The constructor is called as the module is being instantiated and is where your module should start to tell tabulator a little about itself. The constructor takes one argument, the table the module is being bound to, it should pass this to the super function so that it is available for the module to bind to its internal helper functions.
It is very important that you do not try any access any parts of the table, any events or other modules when the constructor is called. at this point the table is in the process of being built and is not ready to respond to anything. The constructor should be used to register any external functionality that may be called on the module and to register andy setup options that may be set on the table or column definitions.
Initialization
When the structure of the table is complete and the setup options have been parsed, the initialize function is called on each module. In this function you should check to see if your module has been enabled by the setup options provided to the table constructor, initialize your module configuration based on these options and subscribe to any internal table events you may need.
One of the key concepts with modules, is that they only subscribe to events if they need to use them, keeping the amount of processing needed to a minimum, so it is really important that you check that properties enabling your module in the table options have been set before you subscribe to internal events.
Registering the Module
Once you have built out your module, you need to register it with Tabulator using the registerModule function. Makse sure that you do this before you instantiate your first table, or the module will not be available
Tabulator.registerModule(CustomModule);
Extending Other Modules
The module structure provides a way for you to extend the default settings of other modules if you need to enhance their functionality to fit with your custom module. For example if your new module required a new formatter to be made available in the format module for instance.
This helps keep all new functionality related to a module contained in that module, making the codebase easier to maintain.
This works in a similar way to the Extending Module functionality that is available outside of a module, and is available to alter all the same settings outlined in the documentation for that functionality.
Inside a module this is done using the optional static moduleExtensions property.
In this example we are extending the format module, and adding bold and uppercase formatters to the formatters property:
class CustomModule extends Module{ static moduleName = "custom"; //module name static moduleExtensions = { format:{ //module you want to extend formatters:{ //property you want to extend bold:function(cell, formatterParams){ //new bold property return "" + cell.getValue() + ""; //make the contents of the cell bold }, uppercase:function(cell, formatterParams){ //new uppercase property return cell.getValue().toUpperCase(); //make the contents of the cell uppercase } } } } constructor(table){ ... } }
The moduleExtensions option takes an object as its value. The properties of that object should be the names of any modules you want to extend. In the example above this is the format property. Each of these properties should have an object assigned to them.
Each of those objects should have properties for each of the modules properties that you want to extend which in-turn also contain an object. In the example above this is the formatters property.
Each of those objects should have properties for the elements you want to add to that property. In the example above this is the bold and uppercase properties.
Static Extension
Because modules can only be extended before the table has been instatiated, these extensions must be defined statically and cannot be altered based on table configuration. Attempting to alter these after a table has been instantiated may result in unpredictable behaviour.
Missing Modules
Exenstions will only be applied to modules that have been registered with your Tabulator class. If extensions have been added for a module that has not been registered, they will be safely ignored. For example, in this case if the table did not have a format module, these extensions would be ignored
Internal Components
When building out your module, you will likely need to deal with the rows, columns or cells of the table. In order to do this you will need to work with internal component objects that represent each of these different table components. It is important to note that the internal component objects that will be passed to your module through the various table events are NOT the same as the Component Objects that are available through the public API.
While internal table components have many of the same functions as the external components, they also contain a wide range of properties and functions that are used internally within the table to manage layout and data handling. This section will go over some of the key internal component features that may be needed to build a module.
Module Object
When building a module it may be necessary to store meta information about the module on a specific component (eg. the edited state of a cell). To help with this each component has an object stored on its modules property that can be used to store module specific data without polluting the modules properties.
If you want to store properties on the modules object, they should be stored in another object on a property that matches the name of your object. For example the edit module stores its data on a edit property:
cell.modules.edit = { editable:true, editor:"star", edited:true, }
External Component
While internal table components have many of the same functions as the external components, they also contain a wide range of properties and functions that it is not safe to call from outside the table, it is critical that should you register any public functions, callbacks or events that pass components out to the user, that you pass only the external component. This can be achieved by calling the getComponent function on any internal component:
var externalRow = row.getComponent();
Registration
Modules provide a number of functions to allow registration of table and column options an of public functions that can be called on the table and its components.
Option and function registration should take place in the constructor of a module.
Options
Table Option
Too add an option to the table constructor, you can use the registerTableOption function.
This function takes two arguments, the first is the name of the table option, the second is its default value.
this.registerTableOption("ajaxURL", false);
This will then be available in the options list when the table in instantiated
var table = new Tabulator("#example-table", { ajaxURL:"http://get-my-data.com", });
Option Registration
You must register any options that you want to be available in the options constructor object. If you don't an error will be thrown when a user tries to set the option
Unique Name
Options must have a unique name, if you try and register an option that has already been registered by another module, a console error will be thrown
Column Definition Option
Too add an option to the column definition object, you can use the registerTableOption function.
This function takes two arguments, the first is the name of the table option, the second is its default value.
this.registerColumnOption("download", true);
This will then be available in the column definition options list when the table in instantiated
var table = new Tabulator("#example-table", { columns:[ {title:"Name", field:"name", download:false}, ] });
Option Registration
You must register any options that you want to be available in the column definition object. If you don't an error will be thrown when a user tries to set the option
Unique Name
Options must have a unique name, if you try and register an option that has already been registered by another module, a console error will be thrown
Functions
Table Function
To make a function available on the table object, you can use the registerTableFunction function.
This function takes two arguments, the first is the name of the table function, the second is the function that should be called when that function is called on the table..
this.registerTableFunction("hello", function(){ console.log("Hey There") });
This will then be callable on the table once it has been instantiated
table.hello();
Unique Name
Functions must have a unique name, if you try and register an function that has already been registered by another module, a console error will be thrown
Component Function
Functions can also be registered on any of the Component Objects used by the table, this can be done using the registerComponentFunction function.
This function takes three arguments, the fist is the type of component to register the function against. This can take one of five values:
- row - The row component
- column - The column component
- cell - the cell component
- group - the group component
- calc - the column calc component
The second is the name of the function, the third is the function that should be called when that function is called on the table.
this.registerComponentFunction("cell", "hello", function(){ console.log("Hey There") });
This will then be callable on any matching component
cell.hello();
Unique Name
Functions must have a unique name on the component type it is registered on, if you try and register an function that has already been registered by another module, a console error will be thrown
Options
Once options have been registered during the construction of the module they can then be accessed by any module once the initialize function has been called.
Retreive Option Value
The value of any table option can be retrieved using the options function. This takes the key of the option as its first argument.
var option = this.options("selectableRows");
Nested Data
This function does not handle nested data, to retrieve data stored on nested objects, retrieve the top level object with this function and then navigate the structure as you would normally.
Update Option Value
You can update a table setup option at any point using the setOption function. The first argument should be the key of the option, the second should be the value
this.setOption("selectableRows", false);
It should be noted that changing an option will not automatically update the table to reflect that change, you will likely need to call the refreshData function to trigger the update.
Module Isolation
In order to keep modules isolated from one another it is important that you do not try and alter the options of one module from inside another.
Internal Events
Internal events are used by modules to send and receive data between themselves and the rest of Tabulator. The Event Bus Documentation contains a full list of internal events, and their different type and expected responses.
Module Isolation
Modules should never make direct function calls on one another, they should always communicate through the event bus. This keeps functionality isolated and allows for easy extension of the table
Event Naming
All events in Tabulator are dispatched with names that allow other modules to subscribe to them, by convention internal table event names should follow a kebab-case convention, with the first word in the event being the name of the module where it originated. For example if the menu module had an event for when a menu was opened, it would be named:
menu-opened
Subscribe To An Event
There are hundreds of different internal events dispatched my the Tabulator core and the built-in modules, you can subscribe to any of these events using the subscribe function.
Any arguments passed into the dispatched event will be passed into the subscriber function, a list of arguments sent to each with each event can be found in the Event Bus Documentation.
this.subscribe("example-event", function(arg1, arg2, arg3){ //do something });
There are several different type of event that can be subscribed to, each one has different requirements on what the subscriber is expected to do. For more detals checkout the Event Dispatch Documentation, it contains examples of each type of dispatched event and how to correctly respond to it.
Subscription Order
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
Unsubscribe From An Event
Sometimes after subscribing to an event it may be necessary to unsubscribe from that event to avoid receiving further events. You can do this using the unsubscribe function.
This function takes the name of the event as the first argument and the subscriber function as the second argument. If you are going to be unsubscribing from an event, you will need to store pointers to the original subscriber function in order to unsubscribe from it.
var subscriberFunc = function(arg1, arg2){ //do something } //subscribe to an event this.subscribe("example-event", subscriberFunc); //unsubscribe from an event this.unsubscribe("example-event", subscriberFunc);
Dispatching Events
Internal events can be dispatched in several ways depending on the type of response you want if any.
Dispatch
Dispatched events are simple send and forget notifications which do not return any values. Then can be triggered using the dispatch function.
The first argument is the name of the event, any other arguments after the event are then passed to the subscribers
this.dispatch("example-event", arg1, arg2, arg3);
The subscribing function will then receive the event like this:
this.subscribe("example-event", function(arg1, arg2, arg3){ //do something });
Example
An example usage case of this is when a row is deleted, the row dispatches a row-deleted event that lets modules know that a row has been deleted so they can carry out any needed housekeeping functions.
Chain
Chain events are used when you want to receive a response to an event, they can be used to request feedback from other modules to the result of an event.
Because any number of modules can be subscribed to an event, this isnt a simple call and response. Each subscriber is called in turn an passed the results of the last to subscriber and should return its own response combined with with that of the previous subscribers. When the last subscriber returns the result is returned to the dispatching module.
The first argument is the name of the event, The second argument is an array of arguments to be passed to the subscriber function. The third argument is the initial value to be passed into the previous value argument of the first subscriber. The fourth argument is the fallback value that will be returned if their are no subscribers to the event, this can either be a value or a callback function that is called in the event of no subscribers, that should return the fallback value,
var result = this.chain("example-event", [arg1, arg2, arg3], {}, {noparams:true})
Subscribers to a chain event will receive the arguments passed in the arg array followed by the returned response of the previous subscriber, or if they are the first subscriber the initial value passed into the chain function. The subscriber should then return the previous value amended with any changes the module wants to introduce.
this.subscribe("example-event", function(arg1, arg2, arg3, prevValue){ prevValue.myProp = "value"; return prevValue; });
When the last subscriber returns, it is this return value that is returned from the chain function
Example
An example usage case of this when the data loader dispatches the data-params event to retrieve a list of ajax parameters for a request. the filter, sort and pagination modules then add their parameters to the params object and pass it back to the data loader.
Confirm
The confirm event should be used to check if other modules are happy for something to proceed, if any module returns to to the event it will return true, otherwise it will return false.
The first argument is the name of the event, any other arguments after the event are then passed to the subscribers
var success = this.confirm("example-event", arg1, arg2, arg3);
The subscribing function will then receive the event like this and should return true if it wished to confirm the event:
this.subscribe("example-event", function(arg1, arg2, arg3){ return true; });
Example
The data loader dispatches a data-load confirm when it starts to load data, to allow modules to take control of the loading process and for example make an ajax request instead of the data being loaded from an array.
Subscription Check
By default Tabulator will check if any anyone has subscribed to an event before handling a dispatch event, so you can safely call any dispatch event without consideration for who has subscribed.
In some cases you may be doing a lot of work to generate the contents to pass to the dispatcher, and may want to check if anything is subscribed to the event before carrying out the work. To do this Tabulator provides a couple of helper functions
Subscription Check
The subscribed function can be used to check if anything is subscribed to an event. You should pass in the name of the event as the first argument and it will return true if there are any subscribers.
var isSubscribed = this.subscribed("example-event");
Subscription Change
You can register to be notified if the number of subscribers to a particular event have changed, using the subscriptionChange function.
This function takes the name of the event as the first argument. the second argument should be a callback function that is triggered when the number of subscribers to an event changes.
this.subscriptionChange("example-event", function(added){ //added - true if a subscriber has been added, false if they have been removed });
The callback is passed one argument, a boolean that is true if a subscriber has been added and false if one has been removed.
The callback being passed a false value does not mean that the event has no subscribers, only that one has been removed. You can then use the subscribed function if you need to check if any subscribers are left.
External Events
External events are used by modules to trigger events on the table object that users can subscribe too. The Event Documentation lists all current external events.
Event Naming
All events in Tabulator are dispatched with names that allow other modules to subscribe to them, by convention internal table event names should follow a camelCase convention, with the first word in the event being the name of the module where it originated. For example if the menu module had an event for when a menu was opened, it would be named:
menuOpened
Dispatching Events
Unlike internal events, external events can only be dispatched in one way. They are send and forget style events that do not take any return value from the event callback.
If you want users to be able to respond to an event then you should be setting up a callback using a Table Option.
External events can be triggered using the dispatchExternal function. The first argument is the name of the event, any other arguments after the event are then passed to the subscribers
this.dispatchExternal("exampleEvent", arg1, arg2, arg3);
Subscription Check
By default Tabulator will check if any anyone has subscribed to an event before handling a dispatch event, so you can safely call any dispatch event without consideration for who has subscribed.
In some cases you may be doing a lot of work to generate the contents to pass to the dispatcher, and may want to check if anything is subscribed to the event before carrying out the work. To do this Tabulator provides a couple of helper functions
Subscription Check
The subscribedExternal function can be used to check if anything is subscribed to an event. You should pass in the name of the event as the first argument and it will return true if there are any subscribers.
var isSubscribed = this.subscribedExternal("example-event");
Subscription Change
You can register to be notified if the number of subscribers to a particular event have changed, using the subscriptionChangeExternal function.
This function takes the name of the event as the first argument. the second argument should be a callback function that is triggered when the number of subscribers to an event changes.
this.subscriptionChangeExternal("example-event", function(added){ //added - true if a subscriber has been added, false if they have been removed });
The callback is passed one argument, a boolean that is true if a subscriber has been added and false if one has been removed.
The callback being passed a false value does not mean that the event has no subscribers, only that one has been removed. You can then use the subscribedExternal function if you need to check if any subscribers are left.
Data & Display Handlers
Certain modules may want to alter the number of rows displayed in the table. For example, filtering out rows, sorting data, inserting group headers etc. In order to do this you need to register a handler function, which is called by the row management pipeline when the table is being redrawn.
When registering a pipeline, you pass two arguments into the registration function, the fist is the handler function which should be called when needed, the should accept an array of rows to be processed as its first argument and return an array of processed rows. The second argument of the registration function is the priority value for this handler, which denotes where in the pipeline it will be called, the higher the number the later in the pipeline it will be called.
this.registerDataHandler(function(rows){ return rows.slice(0,10); }, 30);
In the example above we have a data handler that takes all the table rows and returns the top 10. With a priority of 30 this is called after the rows have been filtered (because they both have a priority of < 30)
For an indepth description of the row management pipeline, and to find out the priorities of existing handlers, checkout the Lifecycle Documentation
Pipeline Phases
The row management pipeline is built in two distinct phases, that have their own priority lists. The section below will discuss the differences between the two phases had how to use them
As a general rule you should only register one handler per module.
Data Handlers
Data handlers are called in the first phase of the row management pipeline, and these handler deal with manipulating rows in a way that alters the structure of the data of the table such a filtering and sorting.
These are always called when the underlying data of the table changes, but not when a display event such as chaining row grouping happens.
These can be registered using the registerDataHandler function
this.registerDataHandler(function(rows){ return rows.slice(0,10); }, 30);
Display Handlers
Display handlers are called in the second phase of the row management pipeline, these handlers deal with manipulating the filter/sorted data and augmenting the resulting rows. For example the group module uses a display handler to inject row headers into the output, the tree module uses its handler to inject child rows.
These are called when the display of the table data has changed.
These can be registered using the registerDisplayHandler function
this.registerDisplayHandler(function(rows){ return rows; }, 30);
Refreshing & Redrawing Data
When someone triggers an action on your module, for example they might trigger a sort or change page, then your module needs to be able to tell the table to refresh the current data. To do this you can call the refreshData function.
this.refreshData();
The refresh data function will re-trigger the pipeline from the point of your modules handler registration, so for example if you registered it after the group module, it would not re run the group handler, but it would run your module on the original data from the group module, and then any other modules with a higher priority order. That way Tabulator is not needlessly reprocessing data that hasnt changed.
Refresh In Position
When you trigger a refresh of the data, the scroll position of the table will reset to the top, as this is the desired result in most usage cases.
If you would prefer that the table maintains its vertical scroll position when redrawing then you can pass a value of true to the first argument of the refreshData function
this.refreshData(true); //refresh data in position
Refresh Whole Pipeline
As mentioned above when you trigger a refresh it will run the pipeline from your handler onward. There may be some occasions where you need to rerun the whole piepline again or just rerender the existing data for some reason.
To do this you can pass a second argument to the refreshData function the specifies where in the pipeline to begin the refresh. This can take one of three values:
- all - this will rerun the whole pipeline including all handlers, both data and display
- display - this will run all the display handlers again, but not the data handlers
- end - this will not run any of the handlers again but will trigger a redraw of the current display rows
this.refreshData(false, "display"); //refresh all display handlers
Localization
If your module makes an changes that adds static text to the table ui (for example the pagination module adds buttons with "next" and "prev" text) then you should pull your text from the built in localization system to give users the option to localize their table.
There are several lang functions on a module to help retrieve set the appropriate localized text where needed.
Core Modules
Normaly we would strongly advise against adding functionality that calls directly on other modules because they may not be included by a user in their project. The exceptions to this rule are the lang, layout and comms modules which are considered core to the Tabulator project and included in all tables.
Lang Keys
Each of the lang text functions take the lang key as their first argument, this is a gey that denotes where in the lang values object the value is located. and is a pipe "|" separated list of keys to navigate the nested object properties of the lang object
A full description of the lang values object can be found in the Localization Documentation.
In the case of the pagination "next" button for example the key would be pagination|next because it is the next property of the pagination object in the lang object:
{ pagination:{ next:"next", } }
Default Values
If you are using the lang system, it is recommended that you add your default english language strings to the default lang object located in /src/js/modulesLocalise/defaults/langs.js this will allow users to override the values before the initialize their table.
Lang Functions
Bind Value
In most cases, you are going to set the text on an element and then expect that text to change if the localization of the table changes.
To add text to an element that changes if the localization changes, you can use the langBind function. This function takes two arguments, the first is the lang key as described above, the second is a callback that should set the value on the element. This callback will be called as soon as you call the langBind function, and again any time the table locale changes.
For example if we have a button element assigned to a variable, let's call it "nextBut", we could then set its label with the following code:
this.langBind("pagination|next", (value) => { nextBut.innerHTML = value; });
Text Value
There are some instances where the localized text is only displayed for an instant, such as an ajax loading spinner. In these instances you simply want to get the current lang text the moment the element is added to the DOM.
You can do this using the langText function. This function takes the lang key as its first argument and returns the text value for the key
var label = this.langText("data|loading");
Current Locale
On occasion you may need to know the current locale of the table, for example locale based text sorting. You can use the langLocale function to retrieve the current language locale.
var locale = this.langLocale();
Popups
Sometimes it may be necessary for a module to bring up a popup poistioned above a table element, for example a menu or tooltip. To ensure a consistent behaviour and look and feel of these popups, Tabulator provides the `popup` function.
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
Popup Functions
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();
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 alined with the list item that spawned it.
popup.show(element);
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.
Alerts
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();
Inter-Table Communication
It can sometimes be necessary to trigger functionality on one table from another (moving rows between tables is a great example of this). To achieve this you can use the built in comms functions.
Core Modules
Normaly we would strongly advise against adding functionality that calls directly on other modules because they may not be included by a user in their project. The exceptions to this rule are the lang, layout and comms modules which are considered core to the Tabulator project and included in all tables.
Connections List
Before you can send a message you need to retrieve a list of connections. to do this you pass an array of table identifiers to the commsConnections function. This function will then return an array of connections that match the identifiers provided.
The array of table identifiers should contain either CSS selector strings that identify the tables, DOM nodes for the tables, Tabulator instances, or a combination there of.
var connections = this.commsConnections(["#example-table", "#another-table"]);
If no matching tables are found the function will return false
Send Message
Sending a message to these connected tables can then be achieved using the commsSend function.
Sending a message, is actually the process of triggering a function on a module in the remote table. When calling the commsSend function, the first argument is a list of connections, retrieve with the commsConnections function, the second argument is the name of the module being connected too, the third argument is the function being called on that module, and the fourth argument is any data you want to pass to that function
this.commsSend(connectionList, "moveRow", "connect", {row:row})
In the example, a connection is established to each of the tables in the connection list and the connect function is called on the movable rows module and passed the data object.
Column Layout
It can sometimes be necessary to interact with the column layout of the table when building a module. either by finding out the current layout mode of the table or to trigger a refresh of the column layout after something has been updated.
Core Modules
Normaly we would strongly advise against adding functionality that calls directly on other modules because they may not be included by a user in their project. The exceptions to this rule are the lang, layout and comms modules which are considered core to the Tabulator project and included in all tables.
Get Layout Mode
The layoutMode function will return the name of the current table column layout mode
var layout = this.layoutMode()
This will return a string with one of five possible values from the built in layout modes. If you have registered a custom layout mode then this value will also be available:
- fitData
- fitDataFill
- fitDataTable
- fitDataStretch
- fitColumns
Refresh Layout
If you have altered the contents of a cell or resized a column or the table it may be necessary to refresh the column layout to fit the new table size. You can do this using the layoutRefresh function.
this.layoutRefresh()