Tags

, , ,

Par Anthony Lopes Barata.

L’objectif de ce tutoriel est de remplacer les tableaux générés par Spring ROO par des composants dynamiques dhtmlxGrid et ainsi permettre d’y ajouter des fonctionnalités en utilisant l’API dhtmlx ou des fonctions Javascript diverses. Nous nous appuierons sur le tutoriel de création d’une application Spring Roo (Pizza Shop) avec Jetty intégré (facultatif).

La dhtmlxGrid intégrée à l'application Spring ROO Pizza Shop

Le composant dhtmlxGrid intégré à l'application Spring ROO Pizza Shop

– Il faut tout d’abord ajouter les fichiers nécessaires au chargement de la dhtmlxGrid dans le répertoire src/main/webapp de l’application (disponibles sur http://dhtmlx.com/docs/products/dhtmlxGrid/index.shtml ).

– Puis créer un fichier alternatif de génération de tableau: dupliquer src/main/webapp/WEB-INF/tags/form/fields/table.tagx et renommer la copie en table_dhtmlxGrid.tagx, dans le même répertoire.

– Dans ce fichier alternatif, supprimer le contenu entre les balises html <table> et </table> (incluses) qui sert à créer une table html classique (que l’on cherche donc à remplacer), et remplacer par le script de la dhtmlxGrid.

Ici:

<link rel="STYLESHEET" type="text/css" href="/Pizza/dhtmlxGrid/codebase/dhtmlxgrid.css"></link>
<link rel="stylesheet" type="text/css" href="/Pizza/dhtmlxGrid/codebase/skins/dhtmlxgrid_dhx_skyblue.css"></link>

<script type="text/javascript" src="/Pizza/dhtmlxGrid/codebase/dhtmlxcommon.js">
<!--Placez ici le code de votre script// -->
</script>
<script type="text/javascript" src="/Pizza/dhtmlxGrid/codebase/dhtmlxgrid.js">
<!--Placez ici le code de votre script// -->
</script>
<script type="text/javascript" src="/Pizza/dhtmlxGrid/codebase/dhtmlxgridcell.js">
<!--Placez ici le code de votre script// -->
</script>

<div id="gridbox" style="width: 500px; height: 270px; background-color: white;"></div>
<script>
mygrid = new dhtmlXGridObject('gridbox');
mygrid.setImagePath("/dhtmlxGrid/codebase/imgs/");
mygrid.setHeader("name");
mygrid.setInitWidths("500");
mygrid.setColAlign("right");
mygrid.setColTypes("ed");
mygrid.setColSorting("str");
mygrid.init();
mygrid.setSkin("dhx_skyblue");
mygrid.load("/Pizza/toppings/json", "json");
</script>

Note: il semble que STS gère mal les balises <script src="..." /> et il faut donc dissocier balise ouvrante et fermante, en plaçant entre les deux au moins une balise de commentaire, afin que le chargement du fichier .js fonctionne.

– Nous allons modifier le tableau de la liste des toppings, accessible en cliquant sur “List all toppings” dans le menu de l’application. Pour que l’application utilise notre nouveau fichier, il faut modifier dans le fichier src/main/webapp/WEB-INF/views/toppings/list.jspx les balises <table:table> en <table:table_dhtmlxGrid> et supprimer la ligne <table:column id="c_com_springsource_roo_pizzashop_domain_Topping_name" property="name" z="hHx0eYgxErmr3HAdqNm5089ZxlI="/> qui ne sert plus. On peut dès à présent constater que le tableau des toppings a été remplacé par une dhtmlxGrid si au moins un topping a été créé.

– Toutefois, on constate qu’aucune donnée présente dans l’application n’est chargée dans la grille. Il faut donc faire le lien entre les deux. Nous allons ici utiliser le format de fichier JSON facilement généré par Spring ROO et lu nativement par la dhtmlxGrid (tout comme le CSV et le format XML). Pour cela, entrer les commandes suivantes dans un shell Roo pour générer les classes de manipulation des données en JSON:

json add --class ~.domain.Topping
web mvc json add --jsonObject ~.domain.Topping --class ~.web.ToppingController

– Il faut récupérer le contrôle sur les fonctions générées automatiquement.

Pour cela, couper les fonctions listJson() et updateFromJsonArray(String) du fichier src/main/java/com/springsource/roo/pizzashop/web/ToppingController_Roo_Controller_Json.aj et les coller dans la classe src/main/java/com/springsource/roo/pizzashop/web/ToppingController.java.

Sous STS, dans le fichier src/main/java/com/springsource/roo/pizzashop/web/ToppingController_Roo_Controller_Json.aj, dans la vue ‘Outline’, faire un clic droit > refactor > push in sur chacune des deux fonctions pour réaliser la même opération.

– Maintenant qu’elles sont accessibles, nous pouvons les modifier:

Ajouter la classe interne ToppingView dans la classe ToppingController et modifier la fonction listJson() comme ceci:

package source.web;

import java.util.ArrayList;

//imports...

@RequestMapping("/toppings")
@Controller
@RooWebScaffold(path = "toppings", formBackingObject = Topping.class)
@RooWebJson(jsonObject = Topping.class)
public class ToppingController {
public class ToppingView{
public long id;
public List<String> data=new ArrayList<String>();
}
@RequestMapping(value="/json", headers = "Accept=application/json") //permet d'appeler fonction avec l'URL <emplacement du projet>/Pizza/toppings/json
@ResponseBody
public ResponseEntity<String> listJson() {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
List<Topping> result = Topping.findAllToppings();
List<ToppingView> collection= new ArrayList<ToppingView>();
for(Topping topping:result){
ToppingView toppingView= new ToppingView();
toppingView.id=topping.getId();
toppingView.data.add(topping.getName());
collection.add(toppingView);
}
String json_result= "{rows: "+new JSONSerializer().exclude("*.class").deepSerialize(collection)+"}";
return new ResponseEntity<String>(json_result, headers, HttpStatus.OK);
}

//.....

}

– Un tableau des données de l’application est maintenant disponible à l’URL http://localhost:8090/pizzashop/toppings/json.
Nous allons donc ajouter dans le fichier src/main/webapp/WEB-INF/tags/form/fields/table_dhtmlxGrid.tagx créé précédemment, la ligne mygrid.load("/Pizza/toppings/json", "json"); après la ligne myGrid.init();.

– Reste à ajouter le lien vers les fonctions présentes dans les tableaux classiques, à savoir la visualisation, l’édition et la suppression d’un topping. Il faut donc modifier le script du fichier src/main/webapp/WEB-INF/tags/form/fields/table_dhtmlxGrid.tagx comme ceci pour y ajouter ces colonnes:

function doOnAfterRowDeleted(id, pid) {
window.alert('id supprime:' + id);
deleteRow(id);
return true;
}

function deleteRow(id) {
url2 = "/Pizza/toppings/" + id;
xmlhttp = new XMLHttpRequest();
xmlhttp.open("DELETE", url2, false);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
// Code si requête OK
}
}
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.send(null);
}

mygrid = new dhtmlXGridObject('gridbox');
mygrid.setImagePath("/dhtmlxGrid/codebase/imgs/");
mygrid.setHeader("name, , , ");
mygrid.setInitWidths("300,30,30,30");
mygrid.setColAlign("left,center,center,center");
mygrid.setColTypes("ro,ro,ro,ro");
mygrid.setColSorting("str,str,str,str");
mygrid.attachEvent("onAfterRowDeleted", doOnAfterRowDeleted);
mygrid.init();
mygrid.setSkin("dhx_skyblue");
mygrid.load("/Pizza/toppings/json", "json");

Remarque: pour insérer une image cliquable dans la dhtmlxGrid, il faut préciser dans la colonne le type link ou str et donner comme valeur le code du lien à utiliser, comme nous allons le voir dans la prochaine étape.

– Nous allons maintenant modifier le fichier de la classe ToppingController pour qu’il alimente ces colonnes avec les bons liens lors du chargement de la dhtmlxGrid (fonction listJson()):

@RequestMapping(value="/json", headers = "Accept=application/json")
@ResponseBody
public ResponseEntity<String> listJson() {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
List<Topping> result = Topping.findAllToppings();
List<ToppingView> collection= new ArrayList<ToppingView>();
for(Topping topping:result){
ToppingView toppingView= new ToppingView();
toppingView.id=topping.getId();
toppingView.data.add(topping.getName());
//view link
toppingView.data.add("<a href="/Pizza/toppings/"+topping.getId() +""><img src="images/show.png" /></a>");
//update link
toppingView.data.add("<a href="/Pizza/toppings/"+topping.getId() +"?form"><img src="images/update.png" /></a>");
//delete link
toppingView.data.add("<a href="javascript:void(0)" onClick="mygrid.deleteRow("+topping.getId()+")"><img src="images/delete.png" /></a>");
collection.add(toppingView);
}
String json_result= "{rows: "+new JSONSerializer().exclude("*.class").deepSerialize(collection)+"}";
return new ResponseEntity<String>(json_result, headers, HttpStatus.OK);
}

Les liens sont maintenant créés lors de l’appel à la fonction mygrid.load(…) lors du chargement ou du rafraîchissement de la page qui liste tous les toppings.

FIN TUTORIEL

Nous avons ainsi remplacé de façon ISO-fonctionnelle le composant tableau généré par défaut avec Spring ROO par le composant dhtmlxGrid, nous permettant de disposer de toute la puissance de ce composant AJAX.

– Concernant la pagination dans le cas de gros volumes de données, elle est présente nativement dans la version payante de la dhtmlxGrid et nous n’avons pas encore développé de fonction équivalente. Toutefois, une fonctionnalité de cette dhtmlxGrid, le “Smart Rendering” permet de ne charger que ce qui est affiché actuellement dans la table (et les lignes d’avant/après pour ne pas gêner la navigation). Cela devrait permettre en théorie de ne pas diminuer les performances de notre grille pour gérer de gros volumes de données. La pagination n’aurait alors plus qu’une vocation ergonomique.

Quelques possibilités d’évolution:

  • Modifications des données directement dans la grid, via des cellules éditables,
  • Intégration des formulaires CRUD dans des pop-ups sans changer de page en utilisant la bibliothèque javascript Dojo par exemple (cette API AJAX étant disponible par défaut dans les applications Spring ROO)
  • Ajout d’un champ de recherche en tête de colonne (cf exemple du site dhtmlx)
  • Ajout d’un tri des données pour chaque colonne.
Advertisements