Au cours de vos projets, vous serez sûrement amenés à développer, supprimer ou simplement lire le contenu d'un tableau HTML, surtout si vos structures, ou celles que vous devrez traiter, seront en tableaux HTML. Ici, je vous présente une manière sûre d'y arriver.
Totalement sûre ?
Oui ! Totalement sûre, car les outils que nous allons utiliser sont issus du DOM level 1, c'est-à-dire l'ensemble des standards publiés par le W3C en 1998. Ils sont donc disponibles dans tous les navigateurs dès Internet Explorer 5 et Netscape 6.
Ce tutoriel demande des connaissances en JavaScript, et en particulier sur les objets. Je vous invite donc à lire ce tutoriel. De plus, des connaissances préalables sur les DOM pourront vous être utiles. Enfin, et bien entendu, vous devez connaître les tableaux HTML. Néanmoins, on en reverra des éléments.
J'essaierai d'être le plus clair possible en expliquant les nouvelles notions. Pour vous aider à les assimiler, j'ai mis des exemples qui sont des applications directes, ainsi que des exercices pour aller plus loin où je vous mettrai du mieux que je peux sur la piste. Cependant, si vous ne comprenez pas, n'hésitez pas à me l'indiquer. Ces exercices sont primordiaux car ils vous entraînent également à la programmation.
Ainsi ce tutoriel ne s'adresse pas uniquement à ceux qui doivent traiter des tableaux HTML, mais aussi à tous ceux qui veulent progresser en JavaScript.
Voici un exemple de ce que vous pourrez facilement faire : aperçu. Mais en réalité, vous saurez faire bien plus.
Tout d'abord, je vais vous expliquer l'intérêt de maîtriser les tableaux par des objets JavaScript. En effet, peut-être avez-vous déjà eu recours pour cela à un mélange d'innerHTML et de RegEx (expressions régulières).
Cependant, cette méthode a ses limites. Tout simplement, elle est trop compliquée pour vous et trop longue pour votre ordinateur (c'est une règle d'or, n'abusez pas trop des RegEx : trop nombreuses, elles feront ralentir l'ordinateur de l'internaute et le site pourra devenir inutilisable !).
Comment ça ?? Il suffit d'être un peu débrouillard et le problème de complexité n'en est plus un !
Eh bien en fait non... Pour deux raisons :
votre code va sûrement être trifouillé par d'autres personnes que vous, et figurez-vous que lire une RegEx quand on ne l'a pas écrite soi-même est une chose très compliquée !
imaginez que vous réalisez un tableau dynamique, qui peut aussi contenir d'autres tableaux qui sont ajoutés par l'internaute ; de ce fait vous ne maîtrisez plus réellement son contenu. Là encore, vous pourrez vous débrouiller par de nombreuses RegEx, et ainsi passer de nombreuses heures à produire un code long, compliqué et fragile (fragile car une simple erreur va être difficile à retrouver !).
Désormais, vous allez donc utiliser les méthodes suivantes (elles seront davantage détaillées dans la partie suivante) :
objet.insertRow([index]) c'est-à-dire, ô ordinateur, dans ce tableau, insère une ligne s'il te plait, à cet endroit-là (le JavaScript est une langue plus abrégée que le français :lol: ) ;
objet.deleteRow(), ou supprime la ligne ;
objet.insertCell([index]), ou insère une colonne à cet endroit précis ;
objet.deleteCell(), ou supprime une cellule ;
objet.createTHead(), ou crée un haut de tableau ;
objet.deleteTHead(), ou supprime le haut de tableau ;
objet.createTFoot(), ou crée un bas de tableau ;
objet.deleteTFoot(), ou supprime le bas de tableau ;
objet.createCaption(), ou donne un titre au tableau ;
objet.deleteCaption(), ou supprime le titre du tableau.
Lorsque vous voyez un argument entre crochets, cela signifie qu'il est facultatif. Néanmoins tous les navigateurs ne respectent pas cela. Aussi, pour être au maximum compatible avec les différents navigateurs, vous devez toujours indiquer le paramètre de ces méthodes.
sa sous-structure (thead, tbody et tfoot), facultative également ;
ses lignes (tr) ;
ses cellules (td), voire ses cellules d'en-tête (th).
<table>
<caption>Titre du tableau</caption>
<thead><!-- en-tête -->
<tr><!-- première ligne -->
<th> Première cellule</th>
</tr>
</thead>
<tbody>
<tr><!-- seconde ligne du tableau et première de tbody-->
<td> Première cellule de la ligne</td>
</tr>
</tbody>
<tfoot>
<tr><!-- seconde ligne -->
<td> Première cellule</td>
</tr>
</tfoot>
</table>
Parcourir votre tableau
Cette partie est importante, car elle vous fera comprendre que JavaScript modélise les tableaux HTML en array. De ce fait, la première ligne est la clé 0 de cet array, la seconde est la clé 1. Retenez bien cela, car sinon cela vous fournira systématiquement des erreurs.
Le tableau étant un array, il serait pratique d'appliquer les propriétés et méthodes des arrays. Pour cela, on utilise la propriété rows (c'est une propriété, on ne mettra donc pas ()). Rows retourne un array contenant les lignes du tableau. Elle est applicable sur l'élément table, tbody, tfoot et thead.
Exemple
var arrayLignes = document.getElementById("monTableau").rows;
Exercice n°1
0n va changer la couleur de fond du tableau. Une ligne aura un background de couleur claire (#bdcbf5), la suivante aura le sien de couleur plus foncée (#829eeb). Ainsi, on devrait avoir quelque chose comme :
Si vous avez besoin d'aide, voici l'algorithme :
on stocke l'array des lignes dans une variable ;
si la clé de la ligne est paire, alors le background de la ligne sera clair ;
sinon, le background sera foncé ;
on retourne en 2 si on n'a toujours pas fini de parcourir l'array.
Petite astuce : pour savoir si un nombre est pair, vous faites if(nombre % 2 == 0) (% est le modulo, qui représente le reste de la division).
Vous avez trouvé ? Voici la réponse :
var arrayLignes = document.getElementById("monTableau").rows; //l'array est stocké dans une variable
var longueur = arrayLignes.length;//on peut donc appliquer la propriété length
var i=0; //on définit un incrémenteur qui représentera la clé
while(i<longueur)
{
if(i % 2 == 0)//si la clé est paire
{
arrayLignes[i].style.backgroundColor = "#bdcbf5";
}
else //elle est impaire
{
arrayLignes[i].style.backgroundColor = "#829eeb";
}
i++;
}
Pratique non ? :D
var arrayCellules = document.getElementById("maLigne").cells;
Exercice n°2
Vous pouvez ainsi coloriser une colonne sur deux avec une couleur foncée et les autres avec une couleur claire. Pour cela, nous allons faire une boucle qui va appliquer le changement sur toutes les cellules de toutes les lignes du tableau. C'est-à-dire que nous allons faire une boucle dans une boucle.
var arrayLignes = document.getElementById("monTableau").rows; //on récupère les lignes du tableau
var longueur = arrayLignes.length;//on peut donc appliquer la propriété length
for(var i=0; i<longueur; i++)//on peut directement définir la variable i dans la boucle
{
var arrayColonnes = arrayLignes[i].cells;//on récupère les cellules de la ligne
var largeur = arrayColonnes.length;
for(var j=0; j<largeur; j++)
{
if(j % 2 == 0)//si la clé est paire
{
arrayColonnes[j].style.backgroundColor = "#bdcbf5";
}
else //elle est impaire
{
arrayColonnes[j].style.backgroundColor = "#829eeb";
}
}
}
Maintenant, imaginez que vous vouliez afficher le numéro de la ligne sélectionnée. Pour cela vous pourriez faire une boucle à nouveau, jusqu'à tomber sur la ligne sélectionnée, et ensuite afficher son numéro. Ou... vous pouvez utiliser directement rowIndex qui vous indiquera le numéro dans l'array. Il faudra ensuite ajouter 1 au nombre renvoyé, car un array commence par 0.
Exemple
function numeroLigne(ligne)
{
var numero = ligne.rowIndex;
ligne.cells[0].innerHTML = numero+1;
}
De même, il existe cellIndex qui va vous renseigner sur le numéro de la cellule dans la ligne. Enfin, sachez également que sectionRowIndex donnera le numéro de la ligne par rapport à tbody, tfoot, et thead.
Maintenant que nous avons compris comment JavaScript gère les tableaux HTML, nous pouvons aller encore un peu plus loin, et découvrir comment ajouter des lignes et des cellules dans un tableau. Si vous vous sentez un peu perdu, je vous invite à retravailler les exemples et exercices.
insertRow([index])
Cette méthode insère une ligne dans un tableau. Comme vous le constatez, cette méthode utilise un argument facultatif. Il indique l'emplacement dans le tableau. Par défaut il vaut -1, c'est-à-dire à la fin du tableau. Cependant, une fois de plus, vous devez l'indiquer pour être compatible avec tous les navigateurs.
Attends... comment ça -1 ?!
En fait, si vous avez bien suivi la partie précédente, vous devez vous rappeler que la première ligne du tableau est une clé 0, la seconde ligne clé 1, etc. Ainsi, la -1 est celle précédant la 0, c'est donc la dernière (oui, je dois reconnaître qu'une certaine logique m'échappe... :-° ). Pour autant, ne vous avisez pas d'écrire -2, ça n'existe pas ! InsertRow() est applicable sur table, tbody, tfoot, et thead.
var nouvelleLigne = document.getElementById("monBody").insertRow(-1);
insertRow() vous retourne la ligne créée. À ce moment là, vous remplissez la ligne avec des insertCell... (belle transition non ? :lol: ).
insertCell([index])
Son fonctionnement est quasi-identique à celui de insertRow(), sauf que cette fois-ci, on ajoute des cellules dans une ligne (et non pas dans un tableau, attention !). De plus, pour la remplir, vous pouvez utiliser la belle méthode insertData(decalage, string), mais qui n'est malheureusement pas compatible avec la plupart des navigateurs. On se contentera donc d'innerHTML.
Exemple
Imaginez que vous devez coder une plate-forme d'administration. Vous voulez réaliser un programme qui démarrera quand on clique sur un bouton. Ce programme va mettre dans un tableau les données (auteur, titre, jour, mois, année) de l'article. Dans ce tableau se trouvent aussi les données des articles précédents. En gros, voici ce que nous allons demander à l'ordinateur via le JavaScript :
récupère le titre et l'auteur des champs du formulaire, ainsi que la date d'aujourd'hui ;
crée une nouvelle ligne dans le tableau ;
crée des nouvelles colonnes dans le tableau et places-y les données correspondantes.
Voici la solution commentée. Je l'ai fortement commentée pour vous aider à comprendre.
function ajouterLigne()
{
var tableau = document.getElementById("tableau");
var ligne = tableau.insertRow(-1);//on a ajouté une ligne
var colonne1 = ligne.insertCell(0);//on a une ajouté une cellule
colonne1.innerHTML += document.getElementById("titre").value;//on y met le contenu de titre
var colonne2 = ligne.insertCell(1);//on ajoute la seconde cellule
colonne2.innerHTML += document.getElementById("auteur").value;
var date = new Date();
var colonne3 = ligne.insertCell(2);
colonne3.innerHTML += date.getDate();//on ajoute le jour du mois
var colonne4 = ligne.insertCell(3);
colonne4.innerHTML += date.getMonth()+1;//les mois commencent par 0
var colonne5 = ligne.insertCell(4);
colonne5.innerHTML += date.getFullYear();
}
Exercice n°3
Eh bien maintenant, on peut encore aller un peu plus loin, et oui ! :diable: Nous allons partir de la même situation. Sauf que maintenant, il faut insérer la ligne de sorte que les dates soient classées par ordre croissant. En effet, vous pouvez voir que la dernière ligne du tableau HTML a pour date 20/12/2012. Il faudrait donc que la ligne insérée arrive juste avant celle-ci. Cependant... nous n'allons pas nous contenter de placer la ligne dans ce cas particulier (où on écrirait directement tableau.insertRow(2)), mais bien de manière générale ! :pirate:
Je trouve cet exercice plus difficile que les précédents, car il va utiliser toutes les connaissances acquises. De ce fait, je vous donne l'algorithme. À vous de voir si vous en avez besoin.
On pose une variable qui contient l'ensemble des lignes.
Une autre variable pour le jour, une autre encore pour le mois et une dernière pour l'année.
On pose i=1, car la première ligne du tableau est occupée par le thead.
Si la ligne du tableau qui a pour clé i a une année plus vieille que celle actuelle, on passe à la ligne suivante et on repart en 4.
Sinon, si le mois est déjà passé, on passe à la ligne suivante et on repart en 4.
Sinon si le jour est déjà passé ou qu'il est le même que celui d'aujourd'hui, on passe à la ligne suivante et on repart en 4.
Sinon (la date est dans le futur), on arrête la boucle.
Allez cherchez bien ! Vous n'y arriverez peut-être pas du premier coup (comme moi :-° ), mais cherchez l'erreur et résolvez-la, c'est ainsi que vous progresserez.
function ajouterLigne()
{
//on pose toutes les variables dont on aura besoin
var arrayLignes = document.getElementById("tableau").rows;
var date = new Date();
var jour = date.getDate();
var mois = date.getMonth()+1;
var annee = date.getFullYear();
var i=1;//car la première ligne correspond à thead
while(1==1)//on fait une boucle infinie car la boucle s'arrêtera forcément avec le break
{
if(arrayLignes[i].cells[4].innerHTML < annee)//cells[4] désigne la cellule qui contient l'année
{
i++;
continue;//on recommence un tour de boucle
}
else if(arrayLignes[i].cells[3].innerHTML < mois)//cells[3] le mois
{
i++;
continue;//on recommence un tour de boucle
}
else if(arrayLignes[i].cells[2].innerHTML <= jour)//cells[2] le jour
{
i++;
continue;//on recommence un tour de boucle
}
else
{
break;
}
}
//i représente donc maintenant l'indice la ligne à insérer
var ligne = document.getElementById("tableau").insertRow(i);
var colonne1 = ligne.insertCell(0);//on a ajouté une cellule
colonne1.innerHTML += document.getElementById("titre").value;//on y met le contenu de titre
var colonne2 = ligne.insertCell(1);//on ajoute la seconde cellule
colonne2.innerHTML += document.getElementById("auteur").value;
var colonne3 = ligne.insertCell(2);
colonne3.innerHTML += date.getDate();//on ajoute le jour du mois
var colonne4 = ligne.insertCell(3);
colonne4.innerHTML += date.getMonth()+1;//les mois commencent par 0
var colonne5 = ligne.insertCell(4);
colonne5.innerHTML += date.getFullYear();
}
Cette solution respecte bien l'algorithme. Néanmoins, vous pouvez faire un peu plus court.
function ajouterLigne()
{
var arrayLignes = document.getElementById("tableau").rows;
var date = new Date();
var jour = date.getDate();
var mois = date.getMonth()+1;
var annee = date.getFullYear();
var i=1;//car la première ligne correspond à thead
while(1==1)//on fait une boucle infinie car on arrête la boucle avec le break
{
if(arrayLignes[i].cells[4].innerHTML >= annee && arrayLignes[i].cells[3].innerHTML >= mois && arrayLignes[i].cells[2].innerHTML > jour)
{//si la date est dans le futur
//l'inverse de < est >= et celui de <= est > ; faites bien attention à cela
break;
}
i++;
}
//i représente donc maintenant l'indice de la ligne à insérer
var ligne = document.getElementById("tableau").insertRow(i);
ligne.insertCell(0).innerHTML += document.getElementById("titre").value;//on y met le contenu de titre
ligne.insertCell(1).innerHTML += document.getElementById("auteur").value;
ligne.insertCell(2).innerHTML += jour;//on ajoute le jour du mois
ligne.insertCell(3).innerHTML += mois;//les mois commencent par 0
ligne.insertCell(4).innerHTML += annee;
}
On peut certainement faire encore plus rapide, mais c'est déjà pas mal non ?
Voilà, nous savons faire pleins de choses désormais ! Mais... ce n'est rien par rapport à ce qu'il nous reste à découvrir. :D
Reprenons l'exemple de la partie précédente. Vous êtes donc toujours en train de travailler sur la plate-forme d'administration. Votre chef de projet explique alors que la plate-forme devra également donner la possibilité de supprimer les articles. Pour cela, une colonne du tableau est ajoutée et propose de supprimer l'article. Sauf que le chef est un peu pointilleux et demande que cela soit fait en Ajax (si vous ne connaissez pas ce n'est pas grave, nous ne l'utiliserons pas, mais sachez que l'on utilise le plus souvent le DOM du JavaScript quand on utilise l'Ajax), afin d'éviter le rechargement de la page. Il nomme un premier développeur chargé de l'Ajax, et quant à vous, vous devez supprimer la ligne avec du JavaScript.
Pour cela, vous allez utiliser...
deleteRow([numIndex])
Vous mettez en argument à la méthode deleteRow() l'indice du tableau.
Si vous appliquez deleteRow() non pas sur le tableau tout entier, mais sur tbody, thead, ou tfoot, l'index ne tiendra compte que des clés de cette sous-structure, et non pas des clés de l'ensemble du tableau. Cela peut donc provoquer un décalage ! Faites attention à cela aussi !
tableau.deleteRow(-1);//supprime la dernière ligne du tableau.
Exercice n°4
Vous allez devoir écrire le code que le chef de projet demande.
Ainsi, vous devez coder la fonction supprimerLigne(). Regardez bien : j'ai mis this.parentNode.rowIndex en paramètre. J'aurais très bien pu mettre le numéro de la ligne directement, mais cela m'aurait au final fournit une erreur. En effet dans ce cas-là, j'aurais mis dans la dernière ligne supprimerLigne("3"); mais lorsqu'une ligne précédente est supprimée, l'index est remis à jour comme je vous l'ai dit. De ce fait, la ligne 3 n'existe plus ! Peut-être que vous ne comprenez pas this.parentNode.rowIndex. Je vous le détaille. On part de this, qui représente la cellule où on a cliqué. parentNode nous amène dans l'élément HTML qui contient la cellule, c'est-à-dire la ligne. Cela peut vous paraître flou, et si vous voulez plus d'indications allez donc lire ce tutoriel. Enfin rowIndex que nous avons déjà vu nous renseigne sur le numéro de la ligne. Il est mis à jour lorsque l'index change.
Bon courage !
function supprimerLigne(num)
{
document.getElementById("tableau").deleteRow(num);
}
En fait écrire la fonction n'apporte pas grand-chose. On aurait pu écrire le code de suppression directement dans la cellule. Mais ainsi vous pourrez ajouter d'autres fonctionnalités à la fonction. Et puis ça me permet de ne pas vous donner la solution en même temps que l'énoncé... :-°
D'autres propriétés de suppression moins utiles...
Ici je ne détaillerai que très rapidement les propriétés, car elles sont peu utilisées. En revanche si vous les croisez, vous pourrez les comprendre.
deleteCell([numIndex])
Similaire à deleteRow(), mais supprime une cellule. Même si le standard met l'argument en facultatif, vous devez indiquer l'indice. deleteCell s'applique à une ligne.
var tableau = document.getElementById("monTableau");//on prend le tableau
var ligne = tableau.rows[0];// on prend la première ligne
ligne.deleteCell(0);//on supprime la première cellule de la première ligne
deleteCaption()
Cette méthode supprime le caption (la légende du tableau). Dans le cas où il y a plusieurs captions, deleteCaption() ne supprime que le premier.
deleteTFoot()
Vous utilisez deleteTFoot() pour supprimer le tfoot (le bas de tableau). Il faut donc l'utiliser avec attention, car l'action est bien évidemment sans retour. Cela peut être pratique par exemple quand vous indiquez le nom des colonnes également en thead (en-tête de tableau), mais que le nombre de lignes du tableau est trop petit pour que cela ait un intérêt ; ainsi vous supprimez le tfoot pour alléger le tableau. Chose assez étrange, on peut appliquer deleteTFoot() non seulement sur un tableau, mais aussi sur un tbody.
deleteTHead()
Cette méthode fonctionne exactement comme deleteTFoot(), sauf que cette fois-ci c'est le thead (le haut de tableau) qui est supprimé.
Nous avons vu comment ajouter ou supprimer du contenu, mais comment fait-on pour en déplacer ? Vous avez peut-être déjà vu sur Internet des boutons servant à faire monter ou descendre une ligne d'un tableau. Comment fait-on cela ? Si on modifie une cellule, comment la classer dans le bon ordre par la suite ?
Déplacer une ligne
Il existe une méthode déjà toute faite : c'est moveRow(source, cible). Mais là je sens que je vais vous énerver prodigieusement, car cette méthode n'est pas standardisée et n'est valable que pour Internet Explorer. :colere2:
Nous allons donc écrire la fonction nous-mêmes. :magicien: C'est votre cinquième exercice.
Comment va-t-on s'y prendre ? À l'image de moveRow(), nous allons créer la fonction deplacerLigne(). Celle-ci va prendre deux arguments :
la source qui indiquera l'indice de la ligne à déplacer ;
la cible, qui indiquera son emplacement de destination.
Pour déplacer, il va falloir mettre en mémoire la ligne, l'insérer autre part, puis la supprimer. C'est parfait, ça reprend les trois parties précédentes !
Allez hop, au boulot !
Besoin d'aide ? Voici l'algorithme :
on stocke la ligne de la source dans la variable « ligne » ;
on insère la nouvelle ligne à l'endroit de la cible qu'on appelle « nouvelle » ;
tant qu'il y a des cellules dans « ligne », on crée des cellules dans « nouvelle » qui ont le même contenu que les cellules de « ligne » ;
on supprime l'ancienne ligne.
Faites bien attention lorsque vous supprimez l'ancienne ligne. En effet, son indice peut avoir été modifié si la ligne insérée se situe avant (n'oubliez pas la mise à jour de l'index du tableau !).
Vous avez trouvé ? Voici ma solution. Ce n'est pas forcément la meilleure mais elle devrait être simple à comprendre.
function deplacerLigne(source, cible)
{
//on initialise nos variables
var ligne = document.getElementById("tableau").rows[source];//on copie la ligne
var nouvelle = document.getElementById("tableau").insertRow(cible);//on insère la nouvelle ligne
var cellules = ligne.cells;
//on boucle pour pouvoir agir sur chaque cellule
for(var i=0; i<cellules.length; i++)
{
nouvelle.insertCell(-1).innerHTML += cellules[i].innerHTML;//on copie chaque cellule de l'ancienne à la nouvelle ligne
}
//on supprimer l'ancienne ligne
document.getElementById("tableau").deleteRow(ligne.rowIndex);//on met ligne.rowIndex et non pas source car le numéro d'index a pu changer
}
Grâce à cette fonction, vous pouvez très facilement proposer de monter ou de descendre une ligne du tableau ! Il suffira d'écrire deplacerLigne(this.parentNode.rowIndex, this.parentNode.rowIndex+1); pour monter.
Déplacer une cellule
De même que deplacerLigne(), nous allons écrire une fonction qui permet de déplacer une cellule. Elle prendra 4 paramètres :
ligne1 et cellule1 : l'indice de la ligne et de la première cellule ;
ligne2 et cellule2 : idem pour l'autre cellule.
En fait le code va récupérer les valeurs des cellules, puis les placer dans les autres cellules.
function intervertirCellule(ligne1, cellule1, ligne2, cellule2)
{
//on récupère les données
var contenu1 = document.getElementById("tableau").rows[ligne1].cells[cellule1].innerHTML;//on copie le contenu de la cellule 1
var contenu2 = document.getElementById("tableau").rows[ligne2].cells[cellule2].innerHTML;//on copie celui de la cellule 2
//on remplace
document.getElementById("tableau").rows[ligne1].cells[cellule1].innerHTML = contenu2;
document.getElementById("tableau").rows[ligne2].cells[cellule2].innerHTML = contenu1;//on intervertit les contenus
}
Vous avez appris un certain nombre de nouvelles notions. Cependant si vous avez toujours un peu de mal, je peux vous proposer des exercices plus ou moins durs où vous utiliserez ces notions :
faites un tableau qui permet de déplacer, ajouter, ou supprimer une ligne ou une cellule ;
ajoutez un bouton qui classe les lignes en fonction de la date, du titre, etc. ;
ajoutez un bouton qui sélectionne les lignes dont la colonne date est située dans un intervalle de temps donné, les autres lignes seront supprimées ;
si vos structures sont faites de tableaux HTML, dynamisez votre page.
Si vous avez besoin d'aide, non pas pour vos codes mais pour la théorie, n'hésitez pas à m'envoyer un MP.