HTML et cases à cocher (checkboxes)

L’un des problèmes du HTML, c’est ses éléments de formulaires qui n’ont pas évolué depuis des années. J’ai même l’impression qu’il n’ont jamais évolué après leur invention. Pourtant il manque des tas d’éléments (où sont les combobox?), tandis que d’autres sont limités, pour ne pas dire buggués. C’est notamment le cas des checkbox, ou cases à cocher en français.

La spécification HTML définie que la checkbox ne doit être envoyée avec le formulaire que si elle est cochée, sinon elle est tout bonnement ignorée. Au niveau du serveur nous pouvons donc savoir si une case a été cochée ou non en vérifiant si elle est présente ou non dans les données qu’on reçoit. En PHP cela peut se traduire de la manière suivante :

$checked = isset($_POST['my_cb']);

Ce comportement ne pose pas de problèmes tant qu’on sait qu’on reçoit systématiquement cette valeur. Mais dans le cas d’une fonction d’enregistrement générique qui doit suffire pour réaliser l’enregistrement de X formulaires ? Prenons par exemple un environnement RESTful. On a une et une seule fonction pour enregistrer les données lors d’une requête PUT. Cette unique fonction est largement suffisante et il serait idiot de se répéter à en créer plein, d’autant plus que cela limiterait le nombre de formulaires possibles — à moins de créer autant de fonctions que de cas possibles !

Toujours est-il que dans un tel cas, on ne peut pas savoir si une checkbox est présente dans le formulaire, et encore moins agir en conséquence. Si je reprend le bout de code sus-nommé je vais systématiquement écraser la valeur précédente. Argh.

Je pensais le problème insolvable — et créait autant de fonctions d’enregistrement qu’il n’y a de formulaires — mais il y a quelques jours, en fouillant la documentation de Ruby on Rails, je suis tombé sur un « hack » qui résoud tous les problèmes liés aux checkbox : il permet de savoir quand la checkbox est présente, mais aussi directement la valeur associée aux deux cas coché et décoché (et pas seulement la veleur cochée).

Voici la solution de Rails : ajouter un champ hidden juste après la checkbox. Tout bêtement. Exemple :

<input type="checkbox" name="my_cb" value="1"/>
<input type="hidden" name="my_cb" value="0"/>

Cette solution marche pour deux raisons :

  • la spécification HTML indique que tous les champs, sans exception, doivent être passés au serveur, et ce dans leur ordre de déclaration ;
  • Rails considère qu'un champ déjà déclaré ne doit pas être écrasé.

En postant les données, si la checkbox est cochée, le serveur va voir arriver my_cb=1&my_cb=0. Rails n'en retiendra que my_cb=1. Au contraire si la checkbox est décochée, le serveur va recevoir my_cb=0.

Cela fonctionne bien entendu avec PHP, mais il faut prendre en compte une différence de comportement entre PHP et Rails :

  • PHP se moque de savoir qu'un paramètre a déjà été déclaré et l'écrase sans vergogne.

Ce comportement, certes bourrin, ne pose de problèmes outre-mesure : il prend juste le contre-pied de Rails. Il suffit d'inverser les champs, en plaçant le champ hidden avant la checkbox. Exemple :

<input type="hidden" name="my_cb" value="0"/>
<input type="checkbox" name="my_cb" value="1"/>

En postant les données, si la checkbox est cochée, le serveur va voir arriver my_cb=0&my_cb=1. PHP n'en retiendra que la dernière déclaration, soit my_cb=1. Au contraire si la checkbox est décochée, le serveur recevra seulement my_cb=0.

Et voilà. Avec ce simple « hack » il est possible de travailler avec les checkbox comme avec n'importe quel autre champ de formulaire, sans avoir à se soucier de sa présence ni de sa valeur !

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s


%d blogueurs aiment cette page :