Durante los dos últimos años, mi equipo y yo hemos introducido en los proyectos J2EE una librería de tags JSP para la publicación de datos de forma tabular. Se trata de DisplayTag, una librería open source muy potente que nos facilita la visualización de tablas de datos y la ordenación y paginación de los mismos empleando muy poco código. Para incluirla basta con añadir en la página JSP el tag <display:table>, indicarle el nombre de las columnas, así como el nombre de la colección de datos que enviamos desde el servidor en la respuesta. La librería se encarga de generar el código html para presentar los datos en la tabla, generar los controles de paginación y enlaces de ordenación de las columnas.

Una de las funcionalidades que no incluye esta librería es la utilización de AJAX, que nos acerca una serie de técnicas de programación para la creación de aplicaciones interactivas. Cada vez que pulsamos para ordenar la tabla o para pasar a la siguiente página de resultados se realiza una petición al servidor y éste devuelve una nueva página recargando la anterior con la nueva información. Sería conveniente que por cada petición de ordenar o cambiar la página de resultados se recargase únicamente la información de la tabla de forma asíncrona y no toda la página.
Solución con Ajax Tags
La librería Ajax Tags es un conjunto de tags JSP que simplifica el uso de la tecnología AJAX en las páginas JSP. Además incorpora un tag específico para permitir y habilitar AJAX en las Displaytags comentadas más arriba. Para utilizarlo basta con envolver la tabla con el tag <ajax:displayTag> de manera que sólo se refresque el área contenida en éste y no toda la página:
<ajax:displayTag id="displayTagFrame" ajaxFlag="displayAjax">
<display:table name="service.allCars" pagesize="10" scope="page"
defaultsort="1" defaultorder="descending" export="true" id="row"
excludedParams="ajax">
<display:column property="make" title="Make" sortable="true"
headerClass="sortable" />
<display:column property="model" title="Model" sortable="true"
headerClass="sortable" />
<display:column title="Link" media="html">
<a href="http://www.${row.make}.com">${row.make} Web Page</a>
</display:column>
<display:column title="Link" media="excel xml"> www.${row.make}.com </display:column>
</display:table>
</ajax:displayTag>
¿Cómo funciona? Engloba todo el código html de la tabla en un div con el id indicado como parámetro, sobreescribe el método onclick de cada enlace de la tabla por un código que se encarga de realizar la llamada al servidor y recargar únicamente el div indicado con el código de la tabla (obviando todo el código que no sea la tabla).
Aun resultando así de fácil nos hemos encontrado dos problemas:
- Nosotros utilizamos Struts/Tiles para componer la maquetación de las páginas (aunque nuestro framework sea Spring), de manera que dividimos la página en varias JSPs (cabecera, menú, pie y contenido). Cómo hemos dicho anteriormente ajaxtags obvia el código que no sea de la tabla pero únicamente lo hacía para el contenido, por lo que en el div volvía a aparecer la cabecera, el pie, etc. La solución fue crear una definición en la configuración de Tiles que sólo incluyese el contenido y si en la petición venía cierto parámetro, redirigir desde el servidor a ésta.
- Ajaxtags sobreescribe el evento onclick de los enlaces, pero también sobreescribe el atributo href con un javascript://nop/. Esto nos supone un problema si el sitio tiene alguna restricción de accesibilidad, puesto que en navegadores que no tengan javascript activo (o no soporten js) no funcionará la paginación y ordenación de la tabla.
Solución con jQuery
jQuery es una librería Javascript que simplifica el desplazamiento entre documentos, manipulación del DOM, la gestión de eventos, los efectos y animaciones y la interacción mediante Ajax para un rápido desarrollo web. Esta solución se basa en la funcionalidad load de jQuery, la cual permite cargar html externo desde una fuente remota e inyectarlo en el DOM.

Vamos a verlo más fácil con el siguiente ejemplo:
<div id="tablaresultados">
<display:table name="modelo.resultado"
requestURI="/catalog/busquedaTexto.do" pagesize="10" cellspacing="0"
decorator="es.displaytag.decorator.BuscaTextoTableDecorator"
id="resultados">
<display:column title="Título" property="titulo" sortable="true" />
<display:column title="Signatura" property="signatura" sortable="true" />
<display:column title="Fechas" property="fecha" style="text-align:center" sortable="true" />
</display:table>
</div>
El único requisito en la tabla será que la contenga una capa con el id que deseemos. En esta solución sí que es necesario introducir código javascript en la página:
<script>
if (!com) var com = {};
es.displaytag= {
onPeopleTableLoad: function() {
// Se llama cuando se cargan los datos
$("table#resultados th.sortable").each(function() {
// Itera sobre cada cabecera de columna conteniendo la clase sortable, de manera
// que
// podemos sobreescribir la gestión de click via ajax, en lugar de
// permitir al navegador seguir un enlace normal
$(this).click(function() {
// "this" es el elemento th ordenable
var link = $(this).find("a").attr("href") + " #tablaresultados";
$("div#tablaresultados").load(link, {}, es.displaytag.onPeopleTableLoad);
// Paramos la propagación de eventos, sin permitir que el navegador ejecute el
// href
return false;
});
});
$("div#tablaresultados .pagelinks a").each(function() {
// Itera sobre cada enlace de paginación para sobreescribirlo
$(this).click(function() {
var link = $(this).attr("href") + " #tablaresultados";
$("div#tablaresultados").load(link, {}, es.displaytag.onPeopleTableLoad);
return false;
});
});
}
};
$(document).ready(function() {
// Carga inicial cuando el DOM está preparado. Se asume que vas a inyectar
// dentro de un div
// con el id "tablaresultados" que existe en la página.
$("div#tablaresultados").load("/path/remoto/que/genera/tabla/arriba", {}, es.displaytag.onPeopleTableLoad);
});
</script>
Para evitar el problema 1 comentado en la solución con ajaxtags, añadimos a los enlaces el id «#tablaresultados» para indicarle que recargue únicamente la capa que contiene la tabla. El problema 2 no lo tenemos con esta solución puesto que no se sobreescribe el atributo href. En el caso de mostrar la tabla en un navegador que no interprete javascript la tabla funcionará normalmente recargando toda la página.
Conclusiones
Personalmente me inclino por la solución con jQuery, ya que en nuestro caso no es necesario modificar código en el servidor y porque necesitamos cumplir con criterios de accesibilidad.
Seguramente existen multitud de componentes o tablas con Ajax para incorporar a las aplicaciones web, pero si ya tienes una página con displaytag, el código en el servidor que la alimenta y deseas incorporar ajax y mantener lo que tenías, estas dos soluciones son unas muy buenas opciones.
Actualización
(25-03-2011) Posterior a esta entrada se desarrolló un plugin jQuery (displaytag-ajax) que provee la capacidad de refresco AJAX a tablas generadas mediante Display Tag. Debo dar las gracias a Yajairo87 ya que gracias a su comentario pude descargármelo y probarlo (funciona perfectamente). Si tenéis curiosidad y miráis el código comprobaréis que realiza el mismo proceso comentado en esta entrada. Podéis descargarlo en la siguiente dirección: http://joseantoniosaiz.es/samples/displaytag-ajax/displaytag-ajax-1.2_0.zip