headermask image

header image

Composant grid et dataset

L’objet de cet article est de démystifier l’objet grid, et montrer comment travailler sur un ensemble de données présentées dans un tableau.

L’exemple sur lequel je m’appuierais, sera un tableau utilisant l’objet grid, contenant une liste d’utilisateurs, une colonne du tableau sera dédiée à une case pour marquer l’utilisateur « à supprimer ».
Un bouton permettra de traiter tous les utilisateurs du tableau et de supprimer tous ceux pour lesquels la case sera cochée.

1- Méthodologie

Nous allons récupérer la liste des utilisateurs grâce à une fonction AJAX, puis intégrer cette liste dans un dataset, je ne détaillerais pas cette procédure, un article lui est consacré dans ce blog.

Puis nous allons afficher ce dataset dans un objet grid.

Ensuite nous créerons un bouton « supprimer » pour traiter toutes les lignes du tableau et créer une requête qui sera envoyée au serveur en POST pour lui indiquer la liste des utilisateurs à supprimer dans la base. Les utilisateurs seront supprimés du dataset pour disparaître du tableau.

Cet article va nous permettre de voir une autre possibilité du langage, la possibilité d’envoyer une requête POST et récupérer un message de retour du serveur par l’intermédiaire d’un dataset.

2- Récupération et intégration des données

La liste des utilisateurs sera stockée dans une base SQL et récupérée par un scripte PHP. Le script et les informations sur les utilisateurs ne diffèrent que peu par rapport au tutoriel sur l’intégration de dataset avec AJAX donc je ne détaillerais que les points essentiels.

Requête SQL – Création de la table utilisateur -

  1.  CREATE TABLE `users` (
  2.    `id` int(10) unsigned NOT NULL auto_increment,
  3.    `nick` varchar(30) NOT NULL default '',
  4.    `name` varchar(30) default NULL,
  5.    `surname` varchar(30) default NULL,
  6.    `password` varchar(100) NOT NULL default '',
  7.    PRIMARY KEY  (`id`)
  8.  )

Le document XML voulut est le suivant, il est identique à celui du tutoriel sur AJAX et les dataset mais comporte un attribut en plus par utilisateurs, l’attribut supp= »false », cette attribut est rajouté par le script PHP pour permettre à l’application client de contrôler quel utilisateur doit être supprimé.

Document XML – Format des données -

  1.  <utilisateurs>
  2.      <user id="1" nick="xxxx" prenom="xxxx" nom="xxxx" supp="false"/>
  3.      <user id="2" nick="yyyy" prenom="yyyy" nom="yyyy" supp="false"/>
  4.      .......
  5.      <user id="3" nick="zzzz" prenom="zzzz" nom="zzzz" supp="false"/>
  6.  </utilisateurs>

voilà le script PHP qui permet la génération de la liste des utilisateurs au format XML

Script PHP – Création du document XML –

  1.  <?php
  2.      header("Content-type: text/xml; charset=UTF-8");
  3.     
  4.      include"includes/config.inc";
  5.      include"includes/connect.inc";
  6.     
  7.      echo"<utilisateurs>\n";
  8.     
  9.      //  liste des utilisateurs
  10.      $query = 'SELECT `id`, `nick`, `name`, `surname` FROM `users`';
  11.      $result = mysql_query($query) or die("impossible de récupérer la liste des utilisateurs");
  12.      while ($line = mysql_fetch_assoc($result)) {
  13.          $id = $line["id"];
  14.          $nick = $line["nick"];
  15.          $prenom = $line['name'];
  16.          $nom = $line['surname'];
  17.         
  18.          echo"<user id=\"$id\" nick=\"$nick\" prenom=\"$prenom\" nom=\"$nom\" supp=\"false\"/>\n";
  19.      }
  20.      mysql_free_result($result);
  21.      include"includes/disconnect.inc";
  22.      echo"</utilisateurs>\n";
  23.  ?>

La structure est identique à celle du script vu dans le tutoriel « AJAX et les dataset », le seul ajout est l’attribut supp=\ »false\ ».
La vérification du résultat est toujours possible en entrant l’URL du script dans un navigateur pour vérifier le bon formatage du document.

xml dans navigateur

L’intégration du fichier XML dans le dataset est décrit dans le tutoriel « AJAX et les dataset », je ne décrirais donc pas les fonctions AJAX.

Script LZX partie 1 – initialisation et récupération de la liste d’utilisateurs –

  1.  <?xml version="1.0" encoding="UTF-8" ?>
  2.  <canvas width="900" height="550" oninit="loadXMLListUsers()">
  3.  
  4.  <!-- AJAX -->
  5.  <include href="rpc/ajax.lzx" />
  6.  <dataset name="listuser"/>
  7.  
  8.  <script>
  1.  <![CDATA[
  2.    var req = null;
  3.    function processReqChange() {
  4.          // only if req shows "loaded"
  5.          if (req.readyState == 4) {
  6.              // only if "OK"
  7.              if (req.status == 200) {
  8.                 Debug.write("OK");
  9.              // enregistrement des données du XML dans le dataset
  10.                  canvas.listuser.setChildNodes(req.responseXML.childNodes )
  11.               } else {
  12.                  Debug.write("Problème lors de la récupération des données:\n" + req.statusText);
  13.              }
  14.          }
  15.      }
  16.   
  17.      function loadXMLListUsers() {
  18.          // requete XMLHttpRequest
  19.          req = new XMLHttpRequest();
  20.          req.onreadystatechange = processReqChange;
  21.          req.open("GET", "http://localhost/listusers/listusers.php", true);
  22.        req.send(null);
  23.      }
  24.  ]]>
  1.  </script>

Ici, rien de particulier, lors de l’initialisation de l’application cliente, on exécute la fonction loadXMLListUsers() qui récupère la liste des utilisateurs avec XMLhttprequest().

3- La suppression des utilisateurs dans la base

La suppression d’un ou plusieurs utilisateurs dans la base est effectuée par le script delusers.php,
ce script prend en paramètre un tableau nommé « supp », passé par la méthode POST, contenant la liste des id des utilisateurs à supprimer de la base.
Le script effectue la suppression pour chaque « id » et revoit un message en cas de réussite ou échec de la suppression. Ce message peut être des formes suivantes :

En cas de réussite:

  1.  <reponse>
  2.     <validation name='envoie'>OK</validation>
  3.  </reponse>

En cas d’échec:

  1.  <reponse>
  2.     <validation name='envoie'>ERR</validation>
  3.  </reponse>

Script PHP – suppression de l’utilisateur dans la base de donnée -

  1.  <?php
  2.      header("Content-type: text/xml; charset=UTF-8");
  3.     
  4.      include"includes/config.inc";
  5.      include"includes/connect.inc";
  6.     
  7.      //récupération des infos
  8.      $id_Array = $_POST["supp"];
  9.     
  10.      foreach($id_Array as $id){
  11.          $query = "DELETE FROM `users` WHERE `id` = $id;";
  12.          $result = mysql_query($query);
  13.          if ($result != 1) {
  14.              echo"<reponse>";
  15.              echo"<validation>ERR</validation>";
  16.              echo"</reponse>";
  17.              die();
  18.          }
  19.      }
  20.     
  21.      echo"<reponse>";
  22.      echo"<validation>OK</validation>";
  23.      echo"</reponse>";
  24.     
  25.      include"includes/disconnect.inc";
  26.  ?>

Voilà le code LZX pour gérer l’envoi et la gestion des réponses du côté du client.

Script LZX partie 2 – gestion des envois et réceptions de données –

  1.  <!-- DATASET pour la suppression des utilisateurs -->
  2.  <dataset name="query" type="http" src="http://localhost/listusers/delusers.php" request="false"  ondata="canvas.checksupp()" querytype="POST"/>
  3.  
  4.  <!-- Contrôle du retour du serveur -->
  5.  <method name="checksupp">
  1.  // création d'un pointeur sur le message de retour du serveur
  2.      var retours = canvas.query.getPointer();
  3.     
  4.      // positionnement du pointeur
  5.      retours.setXPath("query:/reponse/validation");
  6.     
  7.      // on récupère le texte de la balise validation
  8.      var result = retours.getNodeText();
  9.  
  10.      // si c'est OK on affiche la boîte de dialogue "suppression réussit"
  11.      if (result == "OK"){canvas.good.open();}
  12.     
  13.      // si c'est ERR, on affiche une boîte d'erreur
  14.      if (result == "ERR") {canvas.erreurdialog.open();}
  1.  </method>
  2.  
  3.  <!-- Fenêtre en cas de suppression correctement effectuée -->
  4.  <modaldialog name="good" title="OK" width="250" height="110">
  5.      <text align="center">tous les éléments ont été supprimés</text>
  6.      <view align="center" layout="axis:x; spacing:20">
  7.        <button onclick="parent.parent.close()" isdefault="true">OK</button>
  8.      </view>
  9.      <simplelayout spacing="5"/>
  10.  </modaldialog>
  11.     
  12.  <!-- Fenêtre en cas d'erreur -->
  13.  <modaldialog name="erreurdialog" title="erreure" width="250" height="110">
  14.      <text align="center">Erreure lors de l'émission du message</text>
  15.      <view align="center" layout="axis:x; spacing:20">
  16.        <button onclick="parent.parent.close()" isdefault="true">OK</button>
  17.      </view>
  18.      <simplelayout spacing="5"/>
  19.  </modaldialog>

Pour commencer on crée un dataset pour gérer l’envoi et la réception de données vers le script delusers.php en mode POST. Lorsque le dataset reçoit une réponse du serveur, il appel la méthode « canvas.checksupp() ».

La méthode « checksupp » commence par initialiser un pointeur sur le message de retour du serveur, puis récupère le text de ce message, OK ou ERR, en fonction de ce message, on ouvre la fenêtre good ou la fenêtre erreurdialog, pour informer l’utilisateur sur le déroulement des opérations.

Pour créer les fenêtres de message, j’utilise les composants « » de la bibliothèque OpenLaszlo.

4- Affichage des données avec le composant grid

Script LZX partie 3 – affichage des données –

  1.  <view>
  2.      <grid name="gridlivre" datapath="listuser:/utilisateurs/">
  3.                 <gridtext datapath="@id" editable="false" width="50" resizable="false"> Id </gridtext>
  4.              <gridtext datapath="@nick"> Nickname </gridtext>
  5.              <gridtext datapath="@prenom"> Prénom </gridtext>
  6.              <gridtext datapath="@nom"> Nom </gridtext>
  7.              <gridcolumn resizable="false" sortable="false" width="40"> Supp
  8.                  <checkbox datapath="@supp" xoffset="${10-parent.width/2}">
  9.                     
  10.                      <!-- En cas de changement de valeur, on appel la méthode updateData pour modifier le datapath -->
  11.                      <method event="onvalue">
  12.                          parent.parent.datapath.updateData();
  13.                      </method>
  14.                     
  15.                      <!-- On retourne la valeur du checkbox -->
  16.                      <method name="updateData">
  17.                          return this.value;
  18.                      </method>
  19.                  </checkbox>
  20.              </gridcolumn>
  21.      </grid>

Pour afficher la liste des utilisateurs, on utilisera le composant , qui permet d’afficher le contenu d’un dataset sous forme de tableau, le grand intérêt du composant grid est la possibilité d’ordonner le contenu en fonction d’une colonne de manière croissante ou décroissante ou alphabétique, pour du texte, et ceci dynamiquement sans avoir à le définir préalablement, il est aussi possible d’éditer le contenu d’une ligne, pour plus de détail, voir la référence du composant .

Ici, on attache au composant le dataset contenant la liste des utilisateurs, puis chaque colonne est défini par un composant qui affichera, pour chaque ligne, la valeur du paramètre fixé dans son paramètre datapath. Seule la dernière colonne est spécifique, elle ne contiendra pas de texte, mais une case à cocher pour définir si l’utilisateur doit être supprimé ou pas, nous utiliserons le composant dans lequel nous plaçons une qui prendra la valeur du paramètre @supp de l’utilisateur (fixé à false lors de l’envoi par le script php).

En cas de modification de l’état de la checkbox, la méthode updateData() modifiera directement, dans le dataset, la valeur de l’ attribut @supp, pour l’utilisateur concerné.

5- Création du bouton pour la suppression des utilisateurs sélectionnés

Script LZX partie 4 – Suppression des utilisateurs sélectionnés –

  1.  <button x="20" y="300" text="Delete selected">
  2.          <method event="onclick">
  1.  <![CDATA[
  2.              // initialisation de la requête de suppression
  3.              var Query;
  4.                     
  5.              // initialisation des pointeurs sur les utilisateurs
  6.              var liste = canvas.listuser.getPointer();
  7.                     
  8.              // positionnement du pointeur
  9.              liste.setXPath("listuser:/utilisateurs");
  10.             
  11.              //récupération du nombre d'utilisateurs
  12.              var count = liste.getNodeCount();                                                                               
  13.                 // positionnement sur le premier noeud (premier utilisateur)
  14.                 liste.selectChild();
  15.                                               
  16.                 // initialisation du compteur pour le tableau de suppression
  17.                 var cpt = 0;
  18.                         
  19.                 // pour chaque ligne...
  20.                 for (var c = 0; c < count; ++c){
  21.                     // si l'attribut supp est vrais...
  22.                        if ( liste.getNodeAttribute("supp") == true){
  23.                                   
  24.                            // on rajoute la ligne dans la liste de suppression
  25.                            // sous la forme supp[0]=1&supp[1]
  26.                            if (cpt == 0){var Query = "supp["+cpt+"]="+liste.getNodeAttribute("id");}
  27.                            else{Query = Query+"&supp["+cpt+"]="+liste.getNodeAttribute("id");}
  28.                                   
  29.                            // on supprime le noeud
  30.                            liste.deleteNode();
  31.                                   
  32.                            // on incrémente le compteur du tableau de suppression
  33.                            cpt = cpt + 1;
  34.                     }
  35.                 
  36.                     // si pas de suppression on passe à la ligne suivante
  37.                     else {liste.selectNext();}
  38.              }
  39.                 
  40.                 // initialisation du Dataset query avec le contenu de la requête puis émission
  41.       
  42.                     var DsQuery = canvas.query;
  43.              DsQuery.setQueryString(Query);
  44.              DsQuery.doRequest();
  45.          ]]>
  1.  </method>
  2.      </button> 
  3.  <simplelayout axis="y" spacing="5"/>
  4.  </view>
  5.  </canvas>

application avec grid

Lors de la pression sur le bouton, on reprend le dataset, et pour chaque utilisateur dont l’attribut @supp est différent de faux (donc coché comme « à supprimé »), on ajout un paramètre à la requête POST. Ensuite, nous supprimons la ligne directement dans le dataset, ce qui à un effet immédiat sur l’affichage dans le . Une fois toutes les lignes traitées, on passe le tableau d’utilisateurs aux dataset query qui effectuera la requête au script deluser.php.

Cet exemple illustre bien les communications entre le client et le serveur et présente une partie des possibilités du composant .