Premi�re �tape : construire la page

Tout d'abord, il faut faire la page web. Pour cela, on utilise du XHTML tout � fait classique, et on construit un tableau. Je vous invite � lire l'article Habillage de tableaux avec des CSS sur Openweb pour en savoir plus sur la mani�re de faire un tableau conforme aux standards.

Le tableau que j'ai choisi de dessiner est on-ne-peut-plus simple : il contient 4 colonnes contenants chacunes un champ de type "text", et une derni�re colonnes contenant les actions possibles. Pour l'instant, la seule action possible est la suppression d'une ligne.

Le code donne (vous pouvez consulter l'exemple 1) :

<table class="dTable">
        <thead>
                <tr>
                        <th>Colonne 1</th>
                        <th>Colonne 2</th>
                        <th>Colonne 3</th>
                        <th>Colonne 4</th>
                        <th>Actions</th>
                </tr>
        </thead>
        
        <tfoot>
                <tr>
                        <th colspan="5"><a href="#">Ajouter une ligne</a></th>
                </tr>
        </tfoot>
        
        <tbody>
                
                <tr>
                        <td><input type="text" name="champ1[]" /></td>
                        <td><input type="text" name="champ2[]" /></td>
                        <td><input type="text" name="champ3[]" /></td>
                        <td><input type="text" name="champ4[]" /></td>
                        <td><a href="#">Supp</a></td>
                </tr>
                
        </tbody>
</table>

Les liens ont tous pour trajet (href) la valeur #. Cela revient � dire qu'ils n'ont pas d'effet... pour l'instant. J'ai appliqu� la classe dTable au tableau (comme « Dynamic Table ») afin de pouvoir l'identifier parmis d'autres eventuels tableaux, qui, eux, ne seront pas dynamiques. Enfin, dernier d�tails, les champs input ont tous un nom finissant par []. Nous verrons dans la troisi�me partie � quoi �a va servir.

Deuxi�me �tape : rendre le tableau dynamique

Maintenant on rentre dans le vif du sujet. Pour rendre ce tableau dynamique, on va utiliser du Javascript et du DOM, en s'arrageant pour qu'il soit compatible Internet Explorer et Firefox.

Premi�re chose : inclure un script. Pour cela, on rajoute dans le header de la page html la ligne suivante (avec dtable.js le nom du fichier script) :

<script type="text/javascript" src="dtable.js"></script>

Bien ensuite, un peu de conception... Comment allons nous proc�der ?

Ajout

Pour ajouter une ligne, le plus simple est d'utiliser la m�thode DOM cloneNode() qui permet de dupliquer un noeud (par exemple un tr, donc une ligne du tableau) et appendChild() qui permet d'ajouter un noeud � un autre (par exemple le tr clon� au tbody, donc au corps du tableau). Cette m�thode est tr�s simple � condition d'avoir une ligne « de r�f�rence », c'est � dire une ligne vide que l'on pourra cloner pour simuler l'ajout de ligne. La premi�re ligne du tableau (la seule que j'ai saisis dans le code html ci-dessus) fera office de r�f�rence.

Nous allons faire une fonction addLigne qui prend en param�tre l'�l�ment appellant (en l'occurence il s'agira d'un lien, donc d'un element A). A partir du lien, il faudra retrouver le tableau en « remontant » dans l'arbre html � la recherche du parent s'appelant TABLE. A partir du tableau, on pourra retrouver le TBODY et la premi�re ligne, et effectuer l'ajout.

Pour retrouver le parent d'un �l�ment, j'utilise une fonction r�cursive, getParent(element, parentTagName), dont voici l'impl�mentation :

/* trouve le tag "parentTagName" parent de "element" */
function getParent(element, parentTagName) {
        if ( ! element )
                return null;
        else if ( element.nodeType == 1 && element.tagName.toLowerCase() == parentTagName.toLowerCase() )
                return element;
        else
                return getParent(element.parentNode, parentTagName);
}

Le code pour ajouter une ligne devient :

/* ajoute une ligne */
function addLigne(link) {
        // 1. r�cuperer le node "TABLE" � manipuler
        var td = link.parentNode;
        var table = getParent(td,'TABLE');
        
        // 2. on va manipuler le TBODY
        var tbody = table.tBodies[0];
        
        // 3. on clone la ligne de reference
        var newTr = tbody.rows[0].cloneNode(true);
        tbody.appendChild(newTr);
}

Pour appeller cette fonction, on peut transformer le lien « Ajouter une ligne » comme ceci :

<a href="#" onclick="addLigne(this); return false;">

Le return false; permet de stopper le traitement normal du lien et donc de ne pas executer le href.

Suppression

L� encore, une fonction DOM nous mache tout le travail : removeChild(). Il suffit de trouver le TR � supprimer en remontant l'arbre html depuis le lien appellant, et de le retirer du TBODY

/* supprimer une ligne */
function delLigne(link) {
        // 1. r�cuperer le node "TABLE" � manipuler
        var td = link.parentNode;
        var table = getParent(td, 'TABLE');
        
        // 2. r�cuperer le TBODY
        var tbody = table.tBodies[0];
        
        // 3. Supprimer le TR
        tbody.removeChild(getParent(td, 'TR'));
}

Pareil que pour l'ajout, on peut transformer les liens « Supp » comme ceci :

<a href="#" onclick="delLigne(this); return false;">

L'ajout et la suppression donnent l'exemple 2.

Prot�ger la premi�re ligne

Le probl�me de l'exemple 2, que vous avez peut-�tre remarqu� en testant, est que la premi�re ligne, la ligne de r�f�rence donc, est supprimable comme les autres. Et lorsqu'on supprime tous les lignes, il n'y en a plus aucune � cloner ! On va donc masquer la premi�re ligne avec la propri�t� CSS display="none" et en ajoute une vide suppl�mentaire.

On ajoute au code :

window.onload = dtableInit;

/* initialise le script */
function dtableInit() {
        var table = document.getElementsByTagName('TABLE');
        for ( var i = 0; i < table.length; i++ ) {
                // on r�cup�re tous les tableaux dynamiques
                if ( table[i].className == 'dTable' ) {
                        
                        var tbody = table[i].tBodies[0];
                        var newTr = tbody.rows[0].cloneNode(true);
                        
                        // on masque la premi�re ligne du tbody (la ligne de reference)
                        tbody.rows[0].style.display = 'none';
                        
                        // on en ajoute une
                        tbody.appendChild(newTr);
                        
                }
        }
}

Un dernier probl�me subsiste : lorsqu'on clone cette ligne, son style est clon� �galement. Toutes les lignes sont donc invisibles ! Il faut ajouter � la fin de addLigne de quoi les remettres visibles :

        if ( document.all )
                newTr.style.display = "block"; // pour IE
        else
                newTr.style.display = "table-row"; // pour Gecko

L'utilisation de document.all permet de d�tecter s'il s'agit d'IE ou pas. En effet, seul ce navigateur impl�mente cette propri�t� (non-standard).

Vous pouvez tester ce code dans l'exemple 3.

Troisi�me �tape : traiter les donn�es

Grace � leur nom finissant par [], les valeurs des champs input seront assembl�es dans un tableau lors du post du formulaire. R�sultat : on se retrouve avec 4 tableaux : champ1, champ2, champ3 et champ4 correspondants aux 4 colonnes du tableaux html. Les lignes de ces tableaux correspondent aux lignes du tableau html (en commen�ant par 0).

Imaginons qu'il faille mettre � jour une base, le plus rapide est de tout supprimer puis de r�ins�rer les donn�es directement ! Pas besoin de s'emb�ter � trouver ce qui a chang� puisque tout est renvoy�.

Derni�re chose : au moment de traiter ces donn�es, il ne faut pas oublier d'oublier l'index 0, qui correspond � la ligne de r�f�rence.

Vous pouvez tester le r�sultat renvoy� par le serveur grace � l'exemple 4.

Conclusion

Rajouter des fonctions � ce script est extrement simple : il suffit de veiller � ne pas toucher � la premi�re ligne. On peut par exemple imaginer des fonctions permettant de monter une ligne, de la descendre, de la dupliquer, etc. Bref, les possibilit�s de cr�er des interfaces web se rapprochant de celles des clients lourds sont de plus en plus nombreuses et de plus en plus simples � mettre en oeuvre grace notamment aux standards du W3C !