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
23 respuestas a “Tablas con DisplayTag y Ajax”
¿Hay alguna solución para el segundo problema usando AjaxTags?
Gracias.
Hola Oscar. Por lo que he podido ver es complicado. No hay ningún atributo que indique si se permite sobreescribir el href, lo hace siempre. Si exploras el onclick generado verás que la urlBase va dentro de la llamada javascript, por si la puedes extraer y volver a sobreescribir el href.
A la desesperada siempre puedes descargarte el código fuente de AjaxTags para ver la línea de código en la que se sobreescribe el href por javascript:nop/
[…] todo el documento en la página. Para ello hemos incluido dentro del proyecto la librería jQuery (de la que ya os he hablado anteriormente) y de un plugin para ella que podéis consultar en […]
muy bueno el aprote, yo uso he usado tambien el displayTag y con este tip de tile solucionaste uno de los grandes problemas que he tenido…. muchisimas gracias por el aporte
[…] resultados, el agrupamiento, la exportación de datos, etc., tal cómo ya habíamos comentado en un post anterior. La configuración se realiza mediante un fichero de propiedades que debe localizarse en el […]
[…] posts hablando sobre la librería jQuery, en concreto como resaltar una búsqueda con jQuery y cómo actualizar tablas displaytag con ajax y jQuery. Gracias a esta librería y el plugin iViewer podemos cargar una imagen, visualizarla en pantalla […]
Gracias por tu aporte me ayudo mucho, sin embargo ya se desarrollo un plugin para jQuery que permite Ajaxificar el contenido de información en un displaytag. Les dejo el link:
http://plugins.jquery.com/project/displaytag-ajax
Saludos Cordiales.
Hola Yajairo87,
Agradezco tu comentario y tu enlace. Lo he estado probando y funciona perfectamente bien. He actualizado el post incluyendo un enlace al plugin.
Gracias. Un saludo.
Hola como están, tengo una inquietud lo que sucede es que cuando pagino se me pierden los estilos de la página y la paginación de la misma, mi código es el siguiente:
Agradezco cualquier ayuda que me puedan brindar
Muchas gracias
No sé qué ocurrió pero no se insertó el código. Intenta enviarlo de nuevo para ver si te puedo ayudar.
No consigo descargar display-tag-ajax-1.2.js, alguien la tiene? gracias
En el enlace no esta en la descarga
Hola Jose.
El enlace debe estar roto, prueba a descargarlo desde: http://joseantoniosaiz.es/samples/displaytag-ajax/displaytag-ajax-1.2_0.zip
Raul, puedes descargarla desde http://joseantoniosaiz.es/samples/displaytag-ajax/displaytag-ajax-1.2_0.zip
alguien a implementado la busqueda sobre la paginacion de displaytag con ajax ?? por favor ayuda
Buenas José Antonio,
primero de todo, felicitarte por el contenido del post. Realmente útil 🙂
Segundo…estoy intentando utilizar el plugin de Jquery para ajaxizar la tabla con displaytag pero no acabo de comprender qué le he de devolver a la llamada ajax que realiza.
El código de la llamada ajax es:
function addClickEvent(ctx, element,url){
$(element).click(
function(){
jQuery.ajax(
{
url: url,
success: function(data){
filteredResponse = $(data).find(this.selector);
if(filteredResponse.size() == 1){
$(this).html(filteredResponse);
}else{
$(this).html(data);
}
$(this).displayTagAjax();
} ,
data: ({«time»:new Date().getTime()}),
context: ctx
});
}
);
}
Lo que no me queda claro, es que tipo de data le he de devolver en la llamada. Html? json?
Muchas gracias de antemano!
Jordi
Hola Jordi,
Como comento en el post el comportamiento estándard (sin ajax) de la tabla displaytag es que cada vez que pulsamos sobre un enlace para ordenar la tabla o para cambiar de página en la misma, se realiza una petición al servidor y se sirve de nuevo toda la página, es decir se recarga por completo. Esto es lo que intentamos evitar, que no se refresque toda la página sino sólo la tabla.
Con Ajax, y respondiendo a tu pregunta, el servidor debe devolver toda la página como en el escenario que he descrito (por lo tanto, HTML) pero el plugin jQuery se encarga de extraer de la misma el fragmento de código HTML de la tabla y lo inyecta en la capa que contiene el displaytable de forma automática. Además, con esto aseguramos la accesibilidad, ya que si un navegador no tiene activado javascript, la página seguirá funcionando recargándose por completo.
Espero que haya aclarado tu duda. Muchas gracias por tu amabilidad. Saludos
Muchas gracias José Antonio!
La verdad que me ha quedado muchísimo más claro con tu respuesta 🙂
De nuevo, mil gracias!
Jordi
Muchas gracias por el aporte, estoy empezando a probar el plugin de jquery para el ajax y hasta ahora me esta resolviendo los problemas que tenia el ajax:displaytag.
Excelente página, es justo lo que estaba buscando, consulto a los expertos, alguien sabe como aplicar filtros o búsquedas con displaytag sobre las columnas o algún otro tipo de búsqueda ?? es lo que me falta.
Estoy trabajando con Spring 3 y eclipse Indigo, estoy intentando con jqGrid pero no me funciona JSON en el controller me genera objetos JSON pero no logro mostrarlos en la grilla, tambien estoy trabajando con TILES, y creo este es mi problema, pero ya tenia paginacion con displaytag y buscaba actualizarme para el uso de JQUERY pero esta página me ayudo en este tema pero me falta la búsqueda.
Si alguien me puede ayuda please.
Saludos.
[…] comenzado una actualización. A continuación mediante el método load, de la que ya os hablé en esta publicación anterior, realizo una petición de la página con un número aleatorio como parámetro (para que el […]
Hola que tal.
Me parece interesante el aporte.
Estoy intentando hacer una tabla con display tag, utilizando Ajax, struts 2, tiles y jquery.
La tabla se carga por medio de un ArrayList de objetos bean, generado desde el action que se llama por medio de Ajax-jquery. El tema es que ese action me devuelve un objeto JSON del tipo
{pedidosfacturaCliente:[{nombreCliente:Pablo Perez,pedido:512},{nombreCliente:Juan Alonso,pedido:215}]}, que representa un arrayList de objetos y es lo que utilizo en el name del display:table para rellenar mi tabla.
Cabe decir lo que veo que mucha gente no dice, y es que lo que esta en el name es un atributo arraylist de objetos que forma parte de mi clase action, y para que el display tag me lo reconozca lo debo meter dentro del action en una variable de sesión.
En definitiva me displaya la lista, pero después de dar a actualizar pantalla, y eso no esta bien.
Sospecho que el plugin jquery.displaytag-ajax-1.2.js no funciona bien.
Les pongo lo que tengo en el body de la jsp:
En las cabeceras de la jsp…
$(document).ready(function(){
$( function(){
alert(«hola1»);
$(«#displayTabla»).displayTagAjax();
alert(«hola2»);
});
…….
Llamada a Ajax…
var idCliente=datosCliente.substring(0,datosCliente.indexOf(‘ ‘));
$.ajax({
url: ‘pedidosFacturasClienteAjax.action’,
type: ‘POST’,
cache:false,
data: {«idCliente»:idCliente},
success: function (resp) {
var objeto= JSON.stringify(resp);
$(«#displayTabla»).displayTagAjax();
},
error: function(e) {
alert(‘Erroooor: ‘+e);
}
});//fin $ajax
Llevo varios dias intentando que funciona y que solo se me cargue el div, pero no hay forma de hacerlo.
Agradeceria respuestas interesantes.
Mi correo es jalber78@gmail.com
Gracias y un saludo
estoy trabajando con struts 2 y para presentar mis datos use jqGrid pero al realizar los cambios en la fila no guarda en la base de datos postgresql
si pudieran ayudar con eso se los agradeceria…