Bon nombre de clients utilisant les sites Internet de mon employeur passent des commandes en saisissant directement les codes articles de leur choix. Ce n’est pas anodin : pour du réassort de magasin, ils savent exactement ce qu’ils veulent. Et un beau jour on vient me voir en me disant qu’ils ne peuvent saisir qu’un code et une seule quantité à la fois, qu’il faudrait changer ça.

Voici donc mon constat de départ :
- un client doit pouvoir saisir un seul article s’il le veut
- un client doit pouvoir saisir 10 articles s’il le veut
- un client doit pouvoir saisir 100 articles s’il le veut
- mais celui qui n’en saisit que 10 ne doit pas être gêné par 100 lignes de formulaire à remplir
- un débutant doit pouvoir saisir 100 lignes sans avoir de mode d’emploi sous la main
Donc ma solution a été très simple : je ne mettrai qu’une ligne.
L’idée
Comment faire pour satisfaire tout le monde, les gros donneurs d’ordre comme les petits ?
En faisant en sorte que le formulaire s’adapte à leur besoin. Je voulais donc qu’à chaque ligne complétée s’en ajoute une autre avant de passer à la validation finale. Place au combo JavaScript + DOM = Ajax.
La version dégradée
Une bonne pratique de l’Ajax est de partir du cas particulier : celui où les conditions ne sont pas requises. En clair, une personne qui n’a pas JavaScript d’activé ou pas de JavaScript tout court.
Conclusion, j’ai décidé de générer un tableau en HTML de 10 lignes. 10 est un choix arbitraire, modifiable à tout moment et qui ne doit donc pas gêner la version dynamique en cas de changement (ajout de colonne, ajout de lignes).

La version Ajax
On peut manipuler le document à loisir grâce à JavaScript. Avec un code propre et ordonné c’est d’autant plus simple. Alors voici la logique à mettre en oeuvre :
- éliminer toutes les lignes dont on ne veut pas et n’en garder qu’une
- assigner à chaque champ de formulaire de la ligne (
input,select,textarea) une fonction de vérification : si tous les éléments de la ligne sont remplis / cochés et qu’il n’y a pas de ligne après, on clonera la ligne - cloner la ligne en la vidant de ses valeurs, en modifiant les noms de champ pour les rendre exploitable après coup
Ce qu’on l’on veut étant relativement simple, le code doit l’être également ! Le résultat aussi, la preuve en mouvement.
Au final, 50 lignes de JavaScript ont suffit à transformer un tableau complètement statique en tableau dynamique, s’adaptant à la demande de n’importe quel client. Client qui pourra également utiliser le clavier pour davantage d’efficacité de saisie.
C’est à dire exactement ce que l’on souhaitait au départ.
Le code
Le tableau HTML
<table cellspacing="0" id="ajout_multi_articles">
<thead>
<tr>
<th>Code article</th>
<th>Quantité</th>
</tr>
</thead>
<tbody>
<tr class="article">
<th><input type="text" name="article[1][ref]” maxlength=”10″ /></th>
<td><input type=”text” name=”article[1][qte]” maxlength=”5″ size=”5″ /></td>
</tr>
<tr class=”article”>
<th><input type=”text” name=”article[2][ref]” maxlength=”10″ /></th>
<td><input type=”text” name=”article[2][qte]” maxlength=”5″ size=”5″ /></td>
</tr>
<tr class=”article”>
<th><input type=”text” name=”article[3][ref]” maxlength=”10″ /></th>
<td><input type=”text” name=”article[3][qte]” maxlength=”5″ size=”5″ /></td>
</tr>
<tr class=”article”>
<th><input type=”text” name=”article[4][ref]” maxlength=”10″ /></th>
<td><input type=”text” name=”article[4][qte]” maxlength=”5″ size=”5″ /></td>
</tr>
<tr class=”article”>
<th><input type=”text” name=”article[5][ref]” maxlength=”10″ /></th>
<td><input type=”text” name=”article[5][qte]” maxlength=”5″ size=”5″ /></td>
</tr>
<tr class=”article”>
<th><input type=”text” name=”article[6][ref]” maxlength=”10″ /></th>
<td><input type=”text” name=”article[6][qte]” maxlength=”5″ size=”5″ /></td>
</tr>
<tr class=”article”>
<th><input type=”text” name=”article[7][ref]” maxlength=”10″ /></th>
<td><input type=”text” name=”article[7][qte]” maxlength=”5″ size=”5″ /></td>
</tr>
<tr class=”article”>
<th><input type=”text” name=”article[8][ref]” maxlength=”10″ /></th>
<td><input type=”text” name=”article[8][qte]” maxlength=”5″ size=”5″ /></td>
</tr>
<tr class=”article”>
<th><input type=”text” name=”article[9][ref]” maxlength=”10″ /></th>
<td><input type=”text” name=”article[9][qte]” maxlength=”5″ size=”5″ /></td>
</tr>
<tr class=”article”>
<th><input type=”text” name=”article[10][ref]” maxlength=”10″ /></th>
<td><input type=”text” name=”article[10][qte]” maxlength=”5″ size=”5″ /></td>
</tr>
</tbody>
</table>
La fonction JavaScript
/**
* Transforme un tableau multi-lignes en un tableau mono-ligne mais auto-extensible
* Renomme également les noms de champ en suivant un masque paramétrable ; par défaut article[]
*
* @usage articlesMultiRows([{'css_id': ?, 'css_row_class': ?, 'check_inputs': ?}])
* @param {Object} params Objet contenant (ou pas) les paramètres de contrôle de la classe
*/
function articlesMultiRows(params)
{
this.row_number = 0;
/*
* Extension des paramètres par défaut
*/
var params = params || {};
params.css_id = params.css_id || ‘ajout_multi_articles’;
params.css_row_class = params.css_row_class || ‘article’;
params.check_inputs = params.check_inputs || ‘input,select,textarea’;
/**
* Initialise le tableau de données et accroche les méthodes dynamiques
*/
this.init = function(){
//aucun ID détecté, pas la peine de continuer plus loin
if (!$(params.css_id))
{
return false;
}
//on récupère les lignes, on enlève la première du tableau et on supprime les autres
var rows = $(params.css_id).getElements(’tr.’+params.css_row_class);
var row_first = rows.shift();
rows.removeElements();
rows = null;
/*
* On assigne l’évènement aux champs paramétrés de la ligne
* On place le focus sur le premier champ
*/
$ES(params.check_inputs, row_first).addEvent(’blur’, rowCheck);
$(row_first).getElement(’input’).focus();
row_number = 1;
/*
* On écrit un petit message sympathique indiquant le fonctionnement du bazar
* On le fait via JavaScript car un utilisateur sans JS ne pourrait justement pas suivre les infos
* Il est placé juste avant le tableau
*/
new Element(’p',{
‘class’ : ‘message’
}).setHTML(”Dès qu’un code article et une quantité sont saisis ci-dessous, <strong>une nouvelle ligne s’ajoute automatiquement</strong>.<br />Afin d’accélérer votre saisie, <em>utilisez la touche de tabulation de votre clavier</em> pour passer d’un champ à l’autre. Vous verrez, c’est facile et surtout efficace !”).injectBefore(params.css_id);
};
/**
* Vérifie si la ligne a entièrement été complétée et le cas échéant, déclenche l’ajout de ligne
*/
this.rowCheck = function(){
var row = { ‘inputs’ : 0, ‘completed’ : 0, ‘dom’ : $(this).getParent().getParent() };
$ES(params.check_inputs, row.dom).each(function(input){
//Un élément de plus …
++row.inputs;
//… dont on vérifie s’il est bien complété
switch (input.getTag())
{
case ‘input’:
case ‘textarea’:
if (input.value.clean())
{
++row.completed;
}
break;
case ’select’:
if (input.selectedIndex >= 0 && input.selectedIndex < input.length)
{
++row.completed;
}
break;
}
});
/*
* Pour insérer une nouvelle ligne, on doit avoir :
* - autant de champs complétés que de champs existants
* - aucun élément suivant
*/
if (row.inputs === row.completed && !row.dom.getNext())
{
rowInsert(row.dom);
}
};
/**
* Insère une nouvelle ligne en clonant la dernière du tableau et la purgeant de ses valeurs
*
* @param {Object} row Noeud DOM correspondant à la ligne à cloner
*/
this.rowInsert = function( row ){
//On incrémente le nombre de lignes dispo
//Ce numéro sert à changer les masques de nom de champ
++row_number;
var row_clone = row.clone();
//Clonage de la ligne
$ES(’input[type=text],input[type=password],input[type=hidden],textarea’, row_clone).setProperty(’value’, ”);
$ES(params.check_inputs, row_clone).removeEvents(’blur’); /* obligé car IE5+ clone aussi les évènements … alors qu’il ne le devrait pas */
$ES(params.check_inputs, row_clone).addEvent(’blur’, rowCheck); /* oui oui, IE5+ ne rassignait pas cet évènement comme il fallait malgré ça */
//On remplace les noms des champs pour que permettre une utilisation des résultats $_POST
$ES(params.check_inputs, row_clone).each(function(input){
input.name = input.name.replace(new RegExp(’^'+params.css_row_class+’[[0-9]+]’), params.css_row_class+’['+row_number+']‘);
});
//Injection de la ligne, une fois tout le travail terminé
row_clone.injectAfter(row);
//Nettoyage, le clonage, ça salit
row_clone = null;
row = null;
};
/*
* Initialisation de la classe
*/
this.init();
}
/*
* Initialisation du tableau multi-lignes avec les options par défaut
*/
window.addEvent(’domready’, articlesMultiRows);











Chouchou a dit le Mardi 26 juin 2007 :
C’est beau!
Et nous, pauvres clients, ne pensons même pas aux idées et difficultés qu’il y a derrière un tableau de ce genre
Oncle Tom a dit le Mardi 26 juin 2007 :
Oui mais qu’est-ce que ça rapporte ^^
Spooky a dit le Mercredi 27 juin 2007 :
Pour ceux qui n’ont pas Javascript d’activé, pourquoi ne pas tout simplement mettre un bouton “ajouter un article” plutôt que de mettre 10 lignes par défaut ?
M’enfin je dis ça, j’ai toujours détesté javascript c’est pour ça que pour moi rien ne vaut un bon vieux bouton html et du traitement PHP avec plein de rafraichissements de page ^^
Oncle Tom a dit le Mercredi 27 juin 2007 :
J’ai procédé ainsi parce qu’avant ils n’avaient qu’une ligne. Pour un client dont l’utilité du site est la saisie de commandes, moins il perd de temps, mieux c’est. En moyenne ils commandent 30 références par commande donc un par un … D’ailleurs après réflexion, 10 peut être trop peu pour les “défavorisés” du navigateur Web.
JavaScript ne t’affranchit pas des traitements PHP mais s’il peut simplifier la collecte des données alors tant mieux. C’est dans cette optique que je rajoute ma surcouche JavaScript (sauf pour des applis internes où il est vraiment impératif). Si le client peut gagner en confort et diviser par 3 ou 4 la durée de sa commande, pourquoi s’en priver surtout si c’est propre ?
imad a dit le Mercredi 5 septembre 2007 :
c’est bien fais
tl a dit le Jeudi 8 novembre 2007 :
bonjour,
c’est sympa de nous montrer ce beau tableau dynamique mais je n’ai pas vu le code. Je suis débutant et ce genre de réalisation me serait utile. Peut-être n’ai je pas regardé au bon endroit…
Merci de m’indiquer où je peux trouver le code de ce tableau.
Oncle Tom a dit le Jeudi 8 novembre 2007 :
Bonne remarque
je prends note et je tâcherai de rajouter le code sous peu.
belgacem a dit le Jeudi 29 novembre 2007 :
Merci Oncle j attend codeee
Stéphane a dit le Jeudi 20 décembre 2007 :
Super l’article, mais je vois pas le code qui va avec…
Donc aucun interêt…
Oncle Tom a dit le Samedi 22 décembre 2007 :
C’est Noël
le code est à disposition.