The GUI dataTable is the most complicated tag to set up, because there is a lot of data configuration required. You have to correctly set up the column definitions in the tag, and you have to set up the controller to serve up the proper data.
Let’s start from scratch with the basic book / author demo.
class Book {
String name
String isbn
static belongsTo = [author:Author]
Date publishDate
}
We want a to create a dataTable tag that will display all the Books I loaded up in Bootstrap.groovy. First off, since we know we’ll be using a dataTable GUI tag in our page, we need to declare this to the resources tag in the page head element. The resources tag will include all the YUI CSS and JavaScript files it knows it will need to build a dataTable.
<gui:resources components="['dataTable']"/>
Now for the dataTable tag. We’ll set up something basic first.
<div class="yui-skin-sam">
<gui:dataTable
controller="book" action="dataTableJSON"
columnDefs="[
[key:'id', label:'ID'],
[key:'name', label:'Name'],
[key:'isbn', label:'ISBN'],
[key:'author', label:'Author'],
[key:'publishDate', label:'Published on']
]"
/>
</div>
Note that I’ve wrapped this whole tag in a div with the yui-skin-sam class. This is necessary if I want to take advantage of the default YUI skin. If you want another skin, it can all be provided in local CSS.
So our dataTable is now expecting at least five fields for each row of data it receives: id, name, isbn, author, and publishDate. We need to set up a controller action that will serve this data in JSON format for us. In the dataTable tag, I’ve already decided the action will be called ‘dataTableJSON’, so let’s code it.
def dataTableJSON = {
def books = Book.list(params)
def data = [
totalRecords: Book.count(),
results: books
]
render data as JSON
}
The dataTable will be calling this method to populate itself with data, so the params will be the dataTable’s filtering information, like how to sort, where to start, etc. The GUI dataTable knows only to send params that can be understood by the Grails list domain class function, so we can just send the params directly into Book.list(params).
By default, the GUI dataTable expects there to be a piece of metaData called “totalRecords” that contains the total amount of records in the entire possible dataset that could be displayed by the table. This is necessary to calculate how many pages of data there are in order to render the pagination controls. If this totalRecords is absent or incorrect, the dataTable pagination will not work properly.
The totalRecords must be the total count of records that might be displayed in the table, not the total count of records that is being passed back by the action.
In the data map above, the ‘results’ key is where the dataTable will look by default for its data. This can be changed in the dataTable tag. For example, if you added resultsList=”myResults” in the dataTable tag, and changed the controller action to return myResults: list instead of results: list, things would work fine.
At this point, we should have something that looks very much like this:

Not bad, but that date looks nasty because it is handled as a String (there is no type formatting in the dataTable yet). And I would really rather see the Author name rather than id. Also, we don’t really want to see the Book id in the table either. So we’re going to have to dig into our controller and take a firmer grip on how the JSON is being created from our domain class.
def dataTableJSON = {
def books = Book.list(params)
// let's convert our book list into an array of maps so we can format
// each value exactly as we want...
def formattedBooks = books.collect {
[
name: it.name,
isbn: it.isbn,
publishDate: new java.text.SimpleDateFormat("MMM dd, yyyy").format(it.publishDate),
author: it.author.name
]
}
def data = [
totalRecords: Book.count(),
results: formattedBooks
]
render data as JSON
}
At this point, we are in total control of the JSON being produced. Grails isn’t converting our domain objects into JSON anymore. We added a custom date format, and we drilled down into the Author to get a name. We also omitted the id field, so we’ll have to go into our tag and omit the id field in the column definitions. If the id field was left in the tag’s columnDefs, there would be an empty column in the table. While we are at it, let’s make all the columns sortable, resizeable, and draggable.
<div class="yui-skin-sam">
<gui:dataTable
controller="book" action="dataTableJSON"
columnDefs="[
[key:'name', label:'Name', sortable: true, resizeable: true],
[key:'isbn', label:'ISBN', sortable: true, resizeable: true],
[key:'author', label:'Author', sortable: true, resizeable: true],
[key:'publishDate', label:'Published on', sortable: true, resizeable: true]
]"
sortedBy="name"
draggableColumns="true"
/>
</div>
Notice that the id column definition is removed, sortable and resizeable were added to each column def, draggableColumns is on, and we added a sortedBy attribute.
The GUI dataTable is sorted by id by default. Because we just removed the id from the column definition, we must explicitly announce how the dataTable should sort upon first render, so the sortedBy=’name’ is absolutely necessary.
Now our table looks like this:

But there is no mention anywhere of how many total records there are! Sure, you can see how many pages, how many rows per page, and do the math, but who wants to do that? So now lets say we want to display 12 rows per page, and show the total amount of records. Well, this doesn’t have anything to do with our data, so the controller action that provides the data will be fine as it is. But we do need to specify some more information to the tag on how to render the paginator.
<div class="yui-skin-sam">
<gui:dataTable
controller="book" action="dataTableJSON"
columnDefs="[
[key:'name', label:'Name', sortable: true, resizeable: true],
[key:'isbn', label:'ISBN', sortable: true, resizeable: true],
[key:'author', label:'Author', sortable: true, resizeable: true],
[key:'publishDate', label:'Published on', sortable: true, resizeable: true]
]"
sortedBy="name"
draggableColumns="true"
rowsPerPage="12"
paginatorConfig="[
template:'{PreviousPageLink} {PageLinks} {NextPageLink} {CurrentPageReport}',
pageReportTemplate:'{totalRecords} total records'
]"
/>
</div>
So we’ve added rowsPerPage, and a paginatorConfig. The rowsPerPage is really a paginatorConfig value, but for the convenience of not having to define the paginatorConfig only for setting rowsPerPage, it was opened up as a main attribute. All the paginatorConfig values are passed through to the dataTable’s YUI Paginator object upon creation. More information on Paginator templates can be found on the YUI Paginator page.
Now we should have a 12-row table with total records displayed:

And there you go. Sortable, resizeable, draggable columns, with a total record count and customized data formatting. If you want to have a hands-on look, here is the source code. Just unzip it, then run:
grails upgrade
grails install-plugin yui
grails install-plugin bubbling
grails install-plugin grails-ui
grails run-app