- Moves to Tabulator 6.2.0
- Add
mutator
option when using app tables #148
- Move to tabulator 5.4.0
- support models as valid data for a Tabulator component #23
We've moved from tabulator 4.6.x to tabulator 5.x That means that some column definitions may not work as before. If you've made heave use of the JS Tabulator API for column definitions you should check they still work.
The package name has changed from Tabulator
to tabulator
from Tabulator.Tabulator import Tabulator
# too many Tabulators
# becomes
from tabulator.Tabulator import Tabulator
It's no longer possible to call methods on a tabulator object until it's been built.
If you try to call a method too early you'll get an AttributeError
.
There is a new tabulator_built
event that you can use.
The tabulator_built
event will be called after the form_show
event.
If you were previously defining a function as a sorter the call signature has changed:
{"title": "Age", "field": "age", "sorter": lambda a, b, aRow, bRow, asc, **params: a - b}
# becomes
{"title": "Age", "field": "age", "sorter": lambda a, b, **params: a - b}
If you defined a function as a custom formatter the call signature has changed:
def image_formatter(row, **kws):
return Image(source=row["image"], height=50, spacing_above="none", spacing_below="none")
self.tabulator.columns = [
...
{'title': 'Image', 'field':'image', 'formatter': image_formatter},
]
# becomes
def image_formatter(cell, **kws):
return Image(source=cell.get_value(), height=50, spacing_above="none", spacing_below="none")
# Alternatively
self.tabulator.columns = [
...
{'title': 'Image', 'field':'image', 'formatter': Image, 'formatter_params': lambda cell: dict(source=cell.get_value(), height=50, spacing_above="none", spacing_below="none")},
]
If you previously used the 'date'
or 'datetime'
formatter, these would have worked for either date or datetime objects.
Now the cell value must be a date object if using the 'date'
formatter, likewise with datetime.
date and datetime formatter_params
used to support an outputFormat
like "MM/DD/YYYY"
.
This is no longer supported. Instead the format should match what you would use for strftime()
.
Note that the outputFormat
param can be replaced by just format
e.g.
{
"title": "Date Of Birth",
"field": "dob",
"editor": "date",
"sorter": "date",
"formatter": "date",
"formatter_params": {"format": "%d/%m/%Y"},
},
The row_selection_change
event was renamed to row_selection_changed
(since that's what it's called in JS Tabulator).
If you made use of this event you should remove it from the designer view before making the switch.
Once you've made the switch you can hook up the new event name.
If you forget to do this, you can always switch back to v1.0.0
remove it from the designer.
The call signatures for events have now changed. The parameters now match those of JS Tabulator.
e.g.
def row_click(self, row, **event_args):
print(row) # python dictionary
# becomes
def row_click(self, row, **event_args):
print(row) # javascript tabulator row component
print(row.get_data()) # python dictionary
def cell_click(self, field, row, **event_args):
if field == "name":
...
# becomes
def cell_click(self, cell, **event_args):
field = cell.get_field()
data = cell.get_data()
if field == "name":
...
You can reset the call signatures by:
- cutting the function from the code view
- switching back to the design view
- clicking the event handler in the designer view
- pasting the function back
You can also check the possible event_args by going to Tabulator.info and finding the events
Tabulator methods (the ones from the autocomplete) may previously have wrapped a JS Tabulator method. Now calling any Anvil Tabulator method directly calls the underlying Javascript method. This means keywords arguments are no longer supported and you should look through the Tabulator.info docs for the correct call signatures
e.g. add_sort
which previously used ascending=True
now expects a dir
argument to be either "asc"
or "desc"
self.tabulator.set_sort("name", ascending=True)
# becomes
self.tabulator.set_sort("name", "asc")
Some properties were removed from the designer. You should change a few properties in the designer after migration to force the designer spec to update.
The following properties are supported in the designer:
"auto_columns": False,
"header_visible": True,
"height": "",
"index": "id",
"pagination": True,
"pagination_size": 5,
"data" # set at runtime
"columns" # set at runtime
"column_defaults": # set at runtime
Other properties can be added via the options
attribute.
e.g.
self.tabulator.options.update({
"selectable": "highlight",
"pagination_size_selector": [5, 10, 15]
})
# or just
self.tabulator.options = {
"selectable": "highlight",
"pagination_size_selector": [5, 10 ,15]
}
The reason for this change is that something like, pagination_size_selector
, can also take a value of True
.
This can't easily be expressed in the designer view of a property.
If you made use of the row_selectable
column with checkboxes. That feature has been removed as a property.
You will now need to explicitly define the column in your column definition.
from tabulator.Tabulator import row_selection_column
...
self.tabulator.columns = [
row_selection_column,
{"title": "Name", "field": "name", ...},
...
]
self.tabulator.options["selectable"] = "highlight"
Anvil only includes a handful of options to customize in the designer. There are many options available, JS Tabulator and it would be a nightmare to put them all in the designer.
If you find options in the JS Tabulator docs you can add them (as camel or snake case) using the options property
self.tabulator.options["langs"] = {
"fr": {
"columns": {
"name":"Nom",
"progress":"Progression",
"gender":"Genre",
"rating":"Évaluation",
"col":"Couleur",
"dob":"Date de Naissance",
},
}
}
This property can be overridden completely e.g.
self.tabulator.options = {
"selectable": "highlight",
"pagination_size_selector": [1, 2, 5, 10]
}
But to have any effect it must be set before the form show event fires.
Tabulator ships with various themes, or you can write your own (see JS Tabulator Docs).
The default theme is "bootstrap3"
since Anvil ships with bootstrap 3.
You can change the theme:
from tabulator.Tabulator import Tabulator
Tabulator.theme = "midnight" # "standard", "simple", "modern"
# or a custom theme
Tabulator.theme = "/_/theme/my_theme.css"
# or handle theming yourself in native libraries
Tabulator.theme = None
Tabulator 5.x has moved to a module design. Features can be enhanced/redacted by changing the Tabulator modules.
See the full list of available Modules in the JS Tabulator docs. http://tabulator.info/docs/5.1/modules#modules
Anvil Tabulator includes the following optional Modules
Tabulator.modules = {
"Edit",
"Filter",
"Format",
"FrozenColumns",
"FrozenRows",
"Interaction",
"Menu",
"Page",
"ResizeColumns",
"ResizeTable",
"SelectRow",
"Sort",
}
You can adjust these by adding or removing, modules from the set of modules. Or replace the set entirely.
from tabulator.Tabulator import Tabulator
Tabulator.modules.remove("FrozenColumns")
Tabulator.modules.add("Persistance")
Events not included by default can be accessed using self.tabulator.on(event, handler)
.
Unlike other Tabulator methods, this can be called before the table_built
event has fired.
There is also a self.tabulator.off(event, handler=None)
method.
You can find events in the JS Tabulator docs.
Note that when using the on
API the handler call signature should match the call signature from Javascript.
http://tabulator.info/docs/5.1/events
All table option keys can be defined as snake_case. e.g.
self.tabulator.options = {
"paginationSizeSelector": [6, 10, 20]
}
# can be
self.tabulator.options = {
"pagination_size_selector": [6, 10, 20]
}
All column defintion keys and column_default keys can be snake case e.g.
self.tabulator.columns = [
{"title": "Name", "field": "name", "hoz_align": "right"},
...
]
self.tabulator.column_defaults = {
"header_hoz_align": "center"
}
All tabulator events can be snake case
self.tabulator.on("header_click", self.header_click)
All methods of the tabulator instance, cells, columns and rows can be called using snake case
self.tabulator.previous_page() # or self.tabulator.previousPage()
def header_click(self, event, column):
alert(column.get_field()) # or column.getField()
Tabulator defines several pre-defined formatters. The paramters keys must be camel case, e.g.
# labelField, urlPrefix, must be camelCase
{"title":"Example", "field":"example", "formatter":"link", "formatter_params":{
"labelField":"name",
"urlPrefix":"mailto://", # must be camelCase
"target":"_blank",
}}
Tabulator has default options for various properties that can be overriden using self.tabulator.options
attribute.
It's also possible to change these defaults without having to override them with the options
attribute.
from tabulator.Tabulator import Tabulator
Tabulator.default_options.update({"layout": "fitData", "selectable": True})
This is most useful if you have multiple Tabulator components and don't want to repeatedly set options.
The default default_options
are:
Tabulator.default_options = {"layout": "fitColumns", "selectable": False}
(as well as all the JS Tabulator default options)
The default_options
are a class level attribute. default_options
will be applied each time a new Tabulator instance is created.
Changing the default_options
will only affect Tabulator instances that have yet to be created.
Check out the migration documentation for Tabulator 4.9 to 5.0: http://tabulator.info/docs/5.0/upgrade#column-defaults
column defaults can be set at runtime e.g.
self.tabulator.column_defaults = {"resizable": False}
Use the table_built
event to determine when you can start accessing methods on the tabulator instance.
Things like self.tabulator.set_sort(...)
can only be called after the tabulator instance has been built.