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>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).
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.
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 install-plugin yui
grails install-plugin bubbling
grails install-plugin grails-ui
grails run-app




52 Comments
Excellent tutorial for an excellent Grails plugin!
But “just unzip and run” won’t work, because you need to install the needed plugins first:
grails install-plugin yui
grails install-plugin bubbling
grails install-plugin grails-ui
Make sure you get the order right …
@Michael Thanks for the note, I’ve updated the post.
How about inline cell-editing? Does the Grails UI plugin support that out of the box?
@Roshan No it doesn’t, but that is an excellent feature request. I have not even looked into doing something like that yet, so it may even be possible using the config pass-through parameters. But I would guess not. I logged a JIRA issue for this to get into 1.1.
Really useful. I initially had left totalRecords out but the reason it was not working was that my domain was in a package - as a result I logged a Jira - http://jira.codehaus.org/browse/GRAILSPLUGINS-628
@boardtc Thanks for logging that JIRA. I’ve assigned it to 1.0.2. :)
How would you add a column that is not in the JSON, say a column that displays an icon, such as a “trash” icon to delete a record?
@Roshan There is really no easy way to do that currently. The best way would be for you to modify your JSON to include all the data you want displayed. You can easily add the some simple markup within the JSON that identifies the row (a span with class and id for example), to which you can add an icon too via CSS. Then in the view, attach listeners to all the spans with that class, which will call the remove URL.
I have an error, “Data error”, I have not rows in table, why?
Thanks
@valmanar In order to help you out, you’ll have to give me more information. Can you paste the tag and the controller method that is populating it?
Hi,
I cannot seem to get pagination working. I have stripped the table down to one id field and i still cant get it to work :( My Tag is:
My Controller action is:
def dataTest = [[id:1],[id:2],[id:3],[id:4],[id:5],[id:6],[id:7],[id:8],[id:9],[id:10],[id:11]] def data = [ totalRecords: dataTest.size(), results: dataTest ] //println data println data as JSON render data as JSONCan anyone help??
Thanks!
The problem is that your “totalRecords” field tells the paginator how many total items can possibly be displayed, but you are telling it how many you are sending back to the table.
For example, if you have 1000 records, but you want to display them 10 at a time, you’ll send a list of ten items in your JSON data, but the totalRecords will say ‘1000′.
Ah i see, i would of never of figured it calls the controller each time. Much appreciated!!!
Is it possible to conditionally highlight a row in the table, say if a column value goes over a certain value then highlight the row red??? If so, what do you think would be the best way to do this?? Thanks again!
I’m sorry I don’t have time to give a more detailed explanation, but I’m packing to leave the country today. I can offer you this advice, however. Take a look at this YUI example of conditional row coloring. You’ll have to create a javascript row formatter like this:
// Define a custom row formatter function var myRowFormatter = function(elTr, oRecord) { if (oRecord.getData('Quantity') < 40) { Dom.addClass(elTr, 'mark'); } return true; };… within script tags, and get the logic right for the condition. You’ll also have to add the CSS for the ‘mark’ class to format the row properly, but you can look at the example and see all that. Create this formatter before you declare your gui:dataTable, then pass it in as an attribute, like formatRow=’myRowFormatter’. This will include your formatter as a config parameter when the data table is created.
Let me know how that works for you!
Thanks Matthew, my Javascript isn’t too great but i will give it a try. Have a safe trip and Happy New Year!
This doesn’t seem to work because when the tagLib renders the property it is rendered as ‘formatRow’: ‘myRowFormatter’ , and the quotes around myRowFormatter probably makes the browser think this is a String rather than a variable (i think). Just to test, I hardcoded ‘formatRow’: myRowFormatter into the tag library and it worked (after i added a reference to the yahoo DOM, “var Dom = YAHOO.util.Dom;” that is).
Could this be considered a bug when adding properties that are JavaScript variables or have I messed up in some way?
Thanks,
John
Seems like a bug to me. There may be a workaround by trying:
YAHOO.util.Event.onDomReady(function() { GRAILSUI.myTableId.formatRow = myRowFormatter; });After the gui:dataTable tag. But I’m not sure if it will work.
I logged the posible bug under http://jira.codehaus.org/browse/GRAILS-3806. Its my first bug report in JIRA, so please let me know if i made a hash of it! Thanks for your help!
Hi,
Try to do it this way:
YAHOO.util.Event.onDOMReady(function() {
GRAILSUI.myTableId.set(”formatRow”, myFormatter);
});
Works pretty fine to me :)
The “formatRow” is not a property, but a “config attribute” - these are set by the set() method of YUI widgets.
Hope that helps!
I do not want to display the ID for a particular row but when I edit the row inline, I need the ID of that particular row so that I can update the correct row in the DB. Is there a way to add a column to the DataSource but not display it so that it populates the RecordSet? I tried removing the column from the ColumnDef but then it does not add that data to the underlying RecordSet.
@Prashant Add hidden=”true” to your columnDefs for id. See the YUI DataTable docs for a full list of applicable columnDef attributes.
Matthew, the problem with hidden=”true” is that it hides the column by reducing the breadth of the column. The table still has that column but it too narrow to display data.The table looks a little odd with such a narrow column.
The way this would work is to provide a column in the DataSource for the table but not provide it in the columnDef. Is there a way to achieve this using GrailsUI?
@Prashant You need to do it this way:
GRAILSUI.myDataTable.getDataSource().responseSchema.fields.push(’id’);
});
It’ll make the responseSchema be aware of the new field (’id’), but it won’t be rendered to the dataTable itself because it’s not declared in the columnDefs.
Of course, your controller has to export the ‘id’ field as well as other fields.
Good luck!
Thanks xis , that works.
Great solution, @xis. So do you think there is a way to better incorporate this requirement into Grails-UI?
Hi all,
A question from a beginner: I used GrailsUI before and it worked. Now when I access the controller, it doesn’t render the data but opens a pop up in Firefox (or IE) and tells me I am trying to open an object which is application/json from http://localhost:8080. If I open this with Firefox it displays the correct data. I can see a text looking like (not complete here):
{”totalRecords”:4,”results”:[{"id":1,"class":"Patient","dob":new Date(160556400000),"firstName":"John","lastName":"Doe","sex":"Male"}, ...
My code is fairly simple:
import grails.converters.JSON
def foo = {
def mPatients = Patient.list()
//return [ patients : patients ]
def data = [
totalRecords: mPatients.size(),
results: mPatients
]
render data as JSON
}
GSP:
Simple GSP page
FYI: Grails 1.0.4 and GrailsUI 1.0.2.
Any idea? Thanks!
Phil
@philcms1 Somehow I lost part of your comment. To find an answer to your question, your best bet is to send a message to the grails user mailing list. More info here.
Hi,
very nice tutorial, thank you very much.
I have the following question, I have a domain class with string properties and they have a maxSize:1000.
The load to the dataTable is ok, but the they are displayed on a single line. I tried to find some settings to apply on the component to make the text (wrap like in Excel) ,but could not find anything related. Maybe making the columns not autoresizeable could do it, but i don’t know how.
could you please suggest a hint on how to do this.
thanks
@alertgn You can find all the options for a DataTable at the YUI docs page. Take a look at the maxAutoWidth column definition option.
Matthew,
Thanks for the response. I already read the documentation and have tried the maxAutoWidth property. This property works for the container, the component itself, but has no effect on the contents. I didn’t find anything that does it automatically, maybe it is in some javascript functions, but I am not good at using javascript.
I achieved the desired effect using string manipulations and formatting in the controller, but I find such solution very ugly and complicated. especially with many datatables and “unpaternable” contents.
Thanks again, I’ll keep digging
@ albertgn You don’t know javascript very well? If you are a UI developer and you trying to do something this complicated with the GUI, I think I have to defer you to a previous post of mine. ;)
@albertgn I had the same issue, large data column that was restricted to one long line. I figured out all the css uses white-space: nowrap, when we want white-space:normal. It’s amazing how many places the css is specified in all the plugins, but I finally found one that expanded the row height based on text. Under \web-app\plugins\grails-ui-1.0.4\css\grailsui\datatable.css, change the following from ‘nowrap’ to ‘normal’.
.yui-skin-sam .yui-dt-liner { white-space:normal; }
Matthew - Excellent article. While working on the text display issue, I tried setting maxAutoWidth. That seems to cause a bug in my table, such that if maxAutoWidthis set on just one column, it adds blank padding to all columns. No matter the width or text inside any column, 60% of the field is blank. Even if I make them resizable, it will always make the columns wider and keep about 60% blank. Happens in Firefox3 and IE7. Not sure if it’s a bug in GrailsUI or YUI, but thought I’d mention it.
Very well written tutorial which covers typical yui table setup with all features (sorting, resize and draggable features). For my table I needed to let one change the number of rows per page. I tried to use “rowsPerPageOptions” option in paginator. The rows combobox shows up but the table is not picking up this new rowsPerPage value.
Very well written tutorial which covers typical yui table setup with all features (sorting, resize and draggable features). For my table I needed to let one change the number of rows per page. I tried to use “rowsPerPageOptions” option in paginator. The rows combobox shows up but the table is not picking up this new rowsPerPage value.
<gui:dataTable
…….
rowsPerPage=”50″
paginatorConfig=”[
rowsPerPage : 50, rowsPerPageOptions : [10,25,50,100],
template : ‘{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}’
]”>
@sans If you continue having this problem, please report it in a JIRA issue. Thanks!
Hi, first, nice tutorial!. Now, my question.
I reach to this post looking for a way to update a table with the Grails UI plugin. This is a more detailed explanation of what I want to do: I have a main page with the more important thing for a student, one of them is a table with the assignments and their deadlines; I also have a table with the most recent events. I want to refresh those tables (automatically, each 5 minutes, for example) in order to add the new assignments or the new events. The question is: can I do this using the dataTable tag (or another tag) of the plugin? If the answer is yes, could it be possible to get an example of how to do it? If the answer is no, is there some other grails’ plugin that allows me to do this?
Thank you in advance.
Ana, see this thread from the Grails mailing list to answer your question.
“Now when I access the controller, it doesn’t render the data but opens a pop up in Firefox (or IE) and tells me I am trying to open an object which is application/json from http://localhost:8080. If I open this with Firefox it displays the correct data.”
I get the same issue as the other user above. Any ideas why this is?
I actually just figured this out in case anyone else comes across this issue. You need two different actions in the controller. One action to call the view page and then another action for the datatable to call the json result.
I had messed with my controller and only had one action that was the same name as the gsp and that action was returning the json.
package com.taleo
import com.taleo.tsc.model.TicLocale;
import com.taleo.LocaleService
import grails.converters.JSON
class LocaleController {
def defaultAction = ‘listLocales’
def localeService
def listLocales = {
List localeList = localeService.listLocales()
[locales : localeList]
}
def dataTableJSON = {
def locales = Locale.list(params)
def data = [
totalRecords: Locale.count(),
results: locales
]
render data as JSON
}
}
I’m constantly getting a data error displayed in the table but no data and this is driving me crazy. Because I have no idea what’s worng. No furher info about the error. Need help.
def AuthorAsJSON = {
def list = []
def authorList = Author.list(params)
def formattedAuthors = authorList.collect {
[
id: it.id,
firstName: it.firstName,
lastName: it.lastName
]
}
def data = [
meTotalRecs: Author.count(),
results: formattedAuthors
]
render data as JSON
}
code of the view somehow got lost in the post above:
Again lost. 3rd try.
Sorry about your code going missing, I don’t know what is wrong with wordpress’s system, but this is a constant problem.
So I would say you need to look into Firebug or another tool that lets you debug your JavaScript in the browser to get a better idea about what the data error is. In most cases, it is that you’ve formatted your server-side JSON incorrectly and the dataTable is not getting what it expects. For example you are using “meTotalRecs” as your count variable, but by default you should use totalRecords. If you want to use a different total records key name for that item, you can specify totalRecordsKey=”meTotalRecs” in your dataTable tag attributes.
I am trying to use the plugin and have gotten the “guidemo-read-only” demo to work. I am having an issue getting the “dataTable” to function properly. The table display correctly, but the functionality does not. It does not paginate, or column sort.
Here is my controller code:
….
def fcHostRPT = {
def foo = params['foo']
def list = []
def fcHostRpt = new Sql(dataSource)
def fchr = fcHostRpt.rows(”select host, port, hba_name, wwnn, wwpn, vendor_name, model, firmware, driver_version, serial_number, hba_type, speed, fcid from hostfc”)
def tRecs = 0
def totalRecs = new Sql(dataSource)
totalRecs.eachRow(”select count(*) from hostfc”) { row ->
tRecs = row[0]
}
response.setHeader(”Cache-Control”, “no-store”)
fchr.each {
list << [
host: it.host,
port: it.port,
hba: it.hba_name,
wwnn: it.wwnn,
wwpn: it.wwpn,
vendor: it.vendor_name,
model: it.model,
firmware: it.firmware,
driver: it.driver_version,
sn: it.serial_number,
type: it.hba_type,
speed: it.speed,
fcid: it.fcid
]
}
def data = [
tRecs: tRecs,
results: list
]
render data as JSON
Here is my GSP/View code.
…..
These are legacy database tables, and do not have the hibernate “id” or “version” fields. Does this make a differenc. These tables are also not controlled by a Domain class.
Thanks,
Geoff
I didn’t get your view code. You shouldn’t need an id or version for this to work. Can you see any JavaScript errors in your browser? Try posting your view code in pre tags or mail the grails-user mailing list (I usually always respond to mailing list questions about GrailsUI).
Me again. Works now. Was an spelling error, eg TestController in controller instead of testController.
My next question is how do I apply a filter? eg. I only want to see records with name = myName where myName = variable.
The GrailsUI DataTable object has three methods to help filtering: addFilter(name, value), clearFilter(name), and clearFilters().
These allow you to add additional query data along with the requests sent to the controller. You can add as many filters as you like, and they will all be sent with the ajax request. You’ll have to handle them on the server side appropriately.
[quote]
These allow you to add additional query data along with the requests sent to the controller. You can add as many filters as you like, and they will all be sent with the ajax request. You’ll have to handle them on the server side appropriately.
[/quote]
ok, consider i’m a complete noobin anything and an idiot, how would you explain it then?
YAHOO.util.Event.onDOMReady(function() {
GRAILSUI.dt2.addFilter(’myColumn’, myValue);
});
is this correct?
Assuming myValue should be ${myDomainClass.myColumn}, how to I get this value into a javascript variable?
What happens to the controller?
Goal: display a yui-table in the the drilldown of the parent yui-table, soemkind of master-detail.
When you call addFilter(), it only tells the dataTable to add some new paramaters to the ajax call it makes to the server to populate itself with data. You don’t have to save anything into a JavaScript variable. Remember when you are rendering JavaScript within a GSP, you are actually programming in 2 languages, so
GRAILSUI.dt2.addFilter(’myColumn’, myValue);
If “myValue” is a Groovy variable, you’ll need to inject it into the JavaScript like this:
GRAILSUI.dt2.addFilter(’myColumn’, ${myValue});
Also, you will all have much more luck posting questions to the mailing list.
4 Trackbacks
[...] issue that is likely of interest to anyone using the YUI CSS foundation (Reset, Fonts, and Grids).Using GrailsUI DataTable Tag: Matt Taylor writes: “The GUI dataTable is the most complicated tag to set up, because there [...]
[...] Using YUI datatable with Grails Install YUI (Yahoo UI) for Grails page_revision: 5, last_edited: 1250024190|%e %b %Y, %H:%M %Z (%O ago) editrate (0)tags history files print site tools+ options edit sections append edit meta who watches backlinks view source parent block rename delete help | terms of service | privacy | report a bug | flag as objectionable Hosted by Wikidot.com — professional wiki solutions Unless stated otherwise Content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License Click here to edit contents of this page. Click here to toggle editing of individual sections of the page (if possible). Watch headings for an “edit” link when available. Append content without editing the whole page source. Check out how this page has evolved in the past. If you want to discuss contents of this page - this is the easiest way to do it. View and manage file attachments for this page. A few useful tools to manage this Site. See pages that link to and include this page. Change the name (also URL address, possibly the category) of the page. View wiki source for this page without editing. View/set parent page (used for creating breadcrumbs and structured layout). Notify administrators if there is objectionable content in this page. Something does not work as expected? Find out what you can do. General Wikidot.com documentation and help section. Wikidot.com Terms of Service - what you can, what you should not etc. Wikidot.com Privacy Policy. _uacct = “UA-5567657-1″; urchinTracker(); _uff = false; _uacct = “UA-68540-5″; _udn=”wikidot.com”; urchinTracker(); _qoptions={ qacct:”p-edL3gsnUjJzw-” }; [...]
[...] The plugin home page has some helpful information about using the DataTable, as does the authors blog. As per usual I started with a crude test to work the kinks out, with the assumption that it could [...]
[...] Using GrailsUI dataTable tag by the plug-in author by Matthew Taylor. [...]