AJAX y Thymeleaf fragments

Utilizando Thymeleaf junto con Spring MVC, se puede optimizar la carga AJAX de determinados fragmentos de nuestra página web.

Hasta ahora, cuando queríamos actualizar diferentes partes de la página utilizando AJAX, utilizábamos el siguiente procedimiento:

1. Nos definíamos un VO para el objeto que quisiéramos refrescar. Este VO, o a veces una colección de ellos, es lo que se serializaba en la respuesta JSON, por lo que interesaba que el peso fuera lo menor posible. De modo que se utilizaban únicamente los atributos que queríamos “repintar”.

2. Creábamos un método AJAX en el Controller que devolviese la respuesta JSON.

3. Invocábamos la función AJAX desde nuestro código JavaScript.

4. Recorríamos la respuesta, creando nuevo contenido HTML “al vuelo”.

Esta aproximación tiene varios problemas:

– Si la interfaz cambia porque añadimos un nuevo atributo (por ejemplo, añadimos una columna a una tabla), hay que modificar también el VO.

– El Controller tiene que implementar funcionalidad de mapeo, del objeto al VO.

– La maquetación se realiza de manera efectiva en el código JavaScript, con todos los problemas que eso conlleva (previsualización, internacionalización, mantenibilidad en general).

Thymeleaf fragments permite evitar todos estos pasos. Por ejemplo, imaginemos que existe un combo con pedidos, y que cuando se selecciona uno de ellos hay que recargar otro combo con los artículos del pedido. Para ello se puede definir un método refreshItem():


@RequestMapping(value = "/refreshItem", method = RequestMethod.GET)
public String refreshItem(@RequestParam("order") String orderId, Model model) {
    List<Item> itemList = Item.findItemsByOrderId(orderId).getResultList();

    model.addAttribute("itemList", itemList);

    return "myView :: #item";
}

El método recibe un argumento con el ID del pedido que se acaba de seleccionar. Hasta aquí, igual que antes. La diferencia es que en vez de devolver un array de objetos JSON, se obtiene simplemente la lista de artículos y se añade al modelo como “itemList”. No importa que esta colección sea “pesada”, es decir, que tenga atributos que ahora mismo no nos interesan, porque no va a ser enviada al cliente.

Lo que sucede, en cambio, es que al devolver el string “myView :: #item”, Thymeleaf interpreta que tiene volver a evaluar el fragmento de esa plantilla definido por ese id, que en este caso sería un “<select/>”:


<select id="item" name="item">
    <option th:text="#{select_item}">Select item...</option>
    <option th:each="item : ${itemList}" th:value="${item.id}" th:text="${item.description}">My item</option>
</select>

Thymeleaf genera el HTML correspondiente a dicho “<select/>”, pero con los nuevos datos que han sido cargados en el modelo por el Controller, y lo devuelve en la respuesta AJAX. Es cierto que las etiquetas HTML suponen algo de overhead respecto a la situación original en la que se devolvía la colección de VOs, pero a cambio nos hemos quitado de un plumazo todos los problemas antes mencionados.

¿Y para incorporar el nuevo HTML a la página? Con jQuery, podemos hacerlo al mismo tiempo que la llamada AJAX, utilizando “$.load()”:


$("#item").load("refreshItem", $("#order").serialize());

¡Una sola línea de JavaScript para todo este proceso! Decididamente, utilizar esta técnica supone importantes ventajas.

Un comentario

Deja un comentario