Initialising DataTables with Twitter Bootstrap and Spring MVC Ajax


In the previous post I introduced handling Ajax requests from DataTables using Spring MVC.
Spring MVC with restful DataTables

This is only one side of the story though as I left out how I was doing the initialisation on the client side. I’m using DataTables with twitter bootstrap so my initialisation is doing two things, one setting up communication with the back end and two adding twitter bootstrap styling.

Continuing with the customer grid example this is my grid.

<table class="table table-striped table-bordered" id="customers">
  <thead>
    <tr> <th>ID</th> <th>Name</th> </tr>
  </thead>
  <tbody></tbody>
</table>
<script type="text/javascript">
	$(document).ready(function() {
	    $('#customers').dataTable( {
	    	"sAjaxSource": "/Root/customers/get",
	    	"bProcessing": true,
	    	"bServerSide": true,
	    	"sPaginationType": "bootstrap",
	    	"oLanguage": {"sLengthMenu": "_MENU_ records per page",
	    				  "sInfo": "Displaying _START_ to _END_ of _TOTAL_ records"},
	        "aoColumns":[
				{"mDataProp":"id"},
				{"mDataProp":"name"}
				]
	    } );
	} );	
</script>

The first three properties set up the Ajax processing, pagination type gives us bootstrap style paging buttons and oLanguage allows us to change the standard labels. When it came to mapping the columns I had to use the aoColumns property and setting the mDataProp value. In most of the examples online you’ll see a PHP script returning the JSON as an array but since we’re using Jackson we’re returning an object. The difference is this.

Array

{
  "aaData": [
    [
      "1",
      "Ben Thurley"
    ],
    [
      "2",
      "Another Person"
    ]
  ]
}

Object

{
  "aaData": [
    {
      "id" : "1",
      "name" : "Ben Thurley"
    },
    {
      "id" : "2",
      "name" : "Another Person"
    }
  ]
}

If you’re returning an array then you give DataTables the index of the property that matches the column, as we’re returning objects we have to give the name of the property that matches the column. We do this by setting the mDataProp property.

As an added bonus DataTables sends back these mDataProp values on the Ajax request which allows us to convert the sort column index into a meaningful column name.

The rest of the twitter bootstrap styling steps can be found on the DataTables site.
http://datatables.net/blog/Twitter_Bootstrap_2

It’s somewhat work in progress but I have also worked this into a JSP tag file so I don’t need to keep writing the same stuff in my JSP’s. It should in theory make it easy to change the tale plugin if required at a later date. I just added the following two tag files into WebRoot/WEB-INF/tags/table.

table.tag

<%@ tag language="java" %>
<%@ attribute name="id" required="true" %>
<%@ attribute name="datasource" required="true" rtexprvalue="true" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<c:set var="org_languagetool_tags_table_outputmode" value="TABLE" scope="request" />
	<table class="table table-striped table-bordered" id="${id}">
	  <thead>
	    <tr><jsp:doBody /></tr>
	  </thead>
	  <tbody></tbody>
	</table>
<c:set var="org_languagetool_tags_table_outputmode" value="SCRIPT" scope="request" />
<c:set var="org_languagetool_tags_table_firstcolumn" value="TRUE" scope="request" />
	<script type="text/javascript">
		$(document).ready(function() {
		    $('#${id}').dataTable( {
		    	"sAjaxSource": "<c:url value="${datasource}" />",
		    	"bProcessing": true,
		    	"bServerSide": true,
		    	"sPaginationType": "bootstrap",
		    	"oLanguage": {"sLengthMenu": "<spring:message code="table.records.count" />",
		    				  "sInfo": "<spring:message code="table.showing.records" />"},
		        "aoColumns":[
		                   	<jsp:doBody />
		                   	]
		    } );
		} );	
	</script>	

column.tag

<%@ tag language="java" %>
<%@ attribute name="field" required="true" %>
<%@ attribute name="label" required="true" rtexprvalue="true" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<c:choose>
  <c:when test="${org_languagetool_tags_table_outputmode == 'TABLE'}">
    <th><spring:message code="${label}" /></th>
  </c:when>
  <c:when test="${org_languagetool_tags_table_outputmode == 'SCRIPT'}">
    <c:choose>
      <c:when test="${org_languagetool_tags_table_firstcolumn == 'TRUE' }">
        <c:set var="org_languagetool_tags_table_firstcolumn" value="FALSE" scope="request" />
      </c:when>
      <c:otherwise>,</c:otherwise>
    </c:choose>
    {"mDataProp":"${field}"}
  </c:when>
</c:choose>

It’s not required unless you’re putting these in a jar but I also wrote out a tag library descriptor.

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.1" xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd">
  <tlib-version>1.0</tlib-version>
  <short-name>Table</short-name>
  <uri>http://bthurley.org/tags/table</uri>
  
  <tag-file>
    <name>table</name>
    <path>/WEB-INF/tags/table/table.tag</path>
  </tag-file>  
  
  <tag-file>
    <name>column</name>
    <path>/WEB-INF/tags/table/column.tag</path>
  </tag-file>
 
</taglib>

By using a tld I’ve been able to specify a uri for importing and using the tag. Otherwise you can give the path to import the tag.

<%@ taglib prefix="tab" uri="http://bthurley.org/tags/table" %>
<tab:table id="customers" datasource="/customers/get" >
  <tab:column field="id" label="customers.field.id" />
  <tab:column field="name" label="customers.field.name" />
</tab:table>

I guess I’ll be adding to these tags as time goes on and I think of new things.

About these ads

, , , ,

  1. #1 by AdamS on October 9, 2012 - 1:48 PM

    Nice post. I have many tables on my site that are wrapped in a bootstrap span6….so they are narrow tables. The problem I am running in to is the pagination defaults to 10. When I get more than 5 pages of records the pagination wraps to a new line, which is ugly. I added “sDom”: “<'row-fluid'r>t<'row-fluid'>”, which gives the pagination some more room…until I get more than 7 pages of records. Is there a way, using sPaginationType: “bootstrap” to limit how many pages are showed in pagination? I’d rather is display like “”.

    Your post helped me with fixing many things while implementing bootstrap with data tables. Thank you!

    • #2 by Ben on October 16, 2012 - 1:48 PM

      Sorry for the delay, I’ve been occupied with decorating the house! That’s a good point you make. I’ve not had enough records in my tables to run into this problem yet but I guess it’s only a matter of time, depending on table width. I don’t have an answer off the top of my head but I’d be interested to look into it a bit more. I need to do a bit more work on the tables to implement searching anyway. There is a forum on the datatables website, perhaps they would have an answer there?

      • #3 by Simon Braconnier on October 24, 2012 - 2:29 PM

        Based on your previous work, I have implemented searching both from the search field of the DataTable or a more complex search criterias area with several fields. I would be pleased to send you some of my work if it could help you in your investigation. But maybe you prefer to find your own way to implement searching :)

      • #4 by Ben on October 26, 2012 - 12:52 PM

        Sounds interesting, I wouldn’t look a gift horse in the mouth. I want to try and come up with a tag library for adding a search form that’s linked to the datatable. Just haven’t got round to it yet!

      • #5 by Cem on April 29, 2013 - 5:48 AM

        Hi Ben. Thanks for this nice wrapper for datatables.
        I have improved search function using CriteriaQuery and Predicate. You can find an example here for your reference.

        https://github.com/ARIPD/lokman/blob/master/src/main/java/com/aripd/project/lgk/service/impl/TripServiceImpl.java

        One question is that i am unable to localise the labels of Search bar and Paging. I did it using oLanguage.sSearch and oLanguage. oPaginate. Can you please help me how to localise those texts?
        Here the updated tag file

        https://github.com/ARIPD/lokman/blob/master/src/main/webapp/WEB-INF/tags/datatables.tag

        Thanks

      • #6 by Ben on April 29, 2013 - 2:09 PM

        Hi there, it’s great to hear of people using this. Even better if they’re adding improvements. :) I had a quick look at your tag file and the json looks ok to me. Have you checked the html when it gets to the browser? I would have a look in firebug or whatever tool you use and check the text is sent ok.

      • #7 by Cem on April 29, 2013 - 3:22 PM

        Because the problem is not related with json data from server, it is not related with your tag library. There is something need to be improved in DT_bootstrap.js. I am really lost in that file :) and couldn’t find where those label variables get localised strings. You can see the screenshot showing where the problem is.

    • #8 by Simon Braconnier on October 24, 2012 - 2:22 PM

      If I may…

      I do not know which version of DataTables and Twitter Bootstrap you work with but I don’t have this issue and I have more than 5 pages of records. I always have only 5 selectable pages in my pagination area:
      “Previous, 1, 2, 3, 4, 5, Next”,
      and when the page 5 is selected my pagination becomes:
      Previous, 3, 4, 5, 6, 7, Next
      etc…

      I uses DataTables 1.9.4 with Twitter Bootstrap 2.1.1

    • #9 by Cem on April 29, 2013 - 3:23 PM

  2. #10 by paul smith on February 28, 2014 - 4:54 PM

    hi

    i tried your solution but i get

    org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.test.PagingCriteria]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.test.PagingCriteria.()

    on the client side do we need to feed this object (displayStart, displaySize, page number) or it’s one automatically

    i don’t see any code who do that

    • #11 by Ben on March 14, 2014 - 10:52 AM

      I’m not sure what you’ve done but PagingCriteria is immutable so doesn’t have a default constructor. The method parameter is annotated with the custom annotation @TableParam and there’s a bit of code behind this that builds the PagingCriteria object. I guess you’ve missed part of this so spring doesn’t know what to do with it. This is from the previous article showing how the backend works.
      Btw, you don’t see anything on the client side because the point of this is getting datatables talking to spring mvc. Datatables does these ajax requests for you in the background. We’re making spring handle these default format requests.

  1. Spring MVC with restful DataTables « Ben Thurley

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: