Complex tables made easy
Introduction
DataTables is a very powerful javascript library for creating tables with complex user interactions. It has dozens of configuration options and can be quite complicated to set up correctly. The Yada Framework implements a Java Fluent API that produces the required javascript configuration and provides the needed backend functionality for server-side data loading.
The current implementation covers all the core DataTables options and the Responsive extension.
A full example is implemented in the YadaExamples project. |
Prerequisites
The DataTables library can either be downloaded locally or from a CDN. In both cases the official download page offers different options to package the required elements into a downloadable zip or a specific CDN url for javascript and CSS. The Yada Framework implementation has been tested with:
Styling framework |
Bootstrap 5 |
---|---|
Packages |
DataTables |
Extensions |
Responsive |
This example is for a downloaded version:
<head>
<link rel="stylesheet" type="text/css" th:href="@{/static/datatables-2.1.8/datatables.min.css}"/>
</head>
...
<script th:src="@{/static/datatables-2.1.8/datatables.min.js}"></script>
The yada.datatables.js
file also needs to be loaded. This is by default automatically
packaged in the war distribution for production but should be added in development:
<script th:if="${@config.developmentEnvironment}" th:src="@{/yadares/js/yada.datatables.js}"></script>
HTML Code
The basic DataTable functionality is implemented just by adding the yada:datatable
tag:
<yada:datatable (1)
yada:configuration="${userTableAttribute}"> (2)
</yada:datatable>
1 | The tag inserts the table at the specified position in the HTML |
2 | The configuration must have been set in the @Controller as a Model attribute, called "userTableAttribute" in this example |
For advanced scenarios where you need to alter the configuration before
creating the table or work with the created table in javascript, two handlers
can be provided via yada:preprocessor
and yada:postprocessor
:
<yada:datatable
yada:configuration="${userTableAttribute}"
yada:preprocessor="userTablePreprocessor" (1)
yada:postprocessor="userTablePostprocessor"> (2)
</yada:datatable>
1 | The preprocessor can alter the configuration before the table is created |
2 | The postprocessor can operate on the table once it has been created |
More details below.
Java Fluent Interface
The configuration for a DataTable is implemented in a YadaDataTable
instance.
This instance can be added to the Model with an attribute that has the same name
used in yada:configuration
, e.g. userTableAttribute
in the example above.
YadaDataTable myDataTable = ...
model.addAttribute("userTableAttribute", myDataTable);
The instance is a singleton identified by a unique id and is produced by yadaDataTableFactory
.
This ensures that the table configuration code is run only once for all HTTP requests
and that the same configuration can be used in the ajax handler that loads the table data.
The current implementation of the ajax handler does not use the table configuration
To create or get an instance the syntax is as follows:
YadaDataTable myDataTable = yadaDataTableFactory.getSingleton("myTableId", locale, ...);
The locale is needed to load the i18n file and can be set to null to use the default locale that is either set in the application XML configuration or taken from the platform. In a multilanguage application it should be taken from a parameter in the @Controller @RequestMapping.
The table configuration is added as a lambda after the locale parameter:
YadaDataTable yadaDataTable = yadaDataTableFactory.getSingleton("userTable", locale, table -> {
table
.dtAjaxUrl("someUrl")
.dt ...
});
Using the lambda ensures that the configuration code is run just once. |
All methods of the fluent interface have the "dt" prefix. This makes IDE suggestions more focused on the useful methods during autocompletion.
When a configuration option has many parameters, the corresponding
method name has the "Obj" suffix because a new object is returned to provide the new
configuration methods.
To "exit" from the current object, the back()
method must be called.
The most basic table configuration requires the setting of the ajax endpoint for data retrieval and of the column definitions, i.e. name and data source. This is shown in the following example:
@RequestMapping("/user")
public String users(Model model) {
YadaDataTable basicTable = yadaDataTableFactory.getSingleton("basicTable", null, table -> {
table
.dtAjaxUrl("/dashboard/user/userProfileTablePage")
.dtStructureObj()
.dtColumnObj("Email", "userCredentials.username").back()
.dtColumnObj("Last Login", "userCredentials.lastSuccessfulLogin").back()
.back();
});
model.addAttribute("basicTable", basicTable);
return "/dashboard/users";
}
The argument of dtAjaxUrl()
is the url for the ajax call that retrieves data
from the backend. It can contain any Thymeleaf expression and will be included
in a standard URL expression like @{/myUrl}
when not already provided.
The dtStructureObj() top method starts configuration of the "structure" of the table using a custom API that can be explored with autocompletion. This API allows the definition of columns and buttons.
The other top method is .dtOptionsObj()
that allows access to the official
DataTables options. For example, the PageLength
option can be set with .dtOptionsObj().dtPageLength(25)
.
All the DataTables core options and the Responsive extension options are available
unless they are deprecated or not applicable in the context of the Yada Framework,
like retrieve.
anything that can’t be done in Java can be done in javascript using pre- and post- processors. |
ajax endpoint row class from the backend full example reference pre- and post- processors