<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
  <head>
    <title>Openweb.eu.org - Bien valider ses formulaires avec Javascript</title>
    <meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
    <link rel="schema.DC" href="http://purl.org/dc/elements/1.1/" />
    <meta name="DC.Language" scheme="RFC3066" content="fr" />
    <meta name="DC.Identifier" content="validation_formulaire" />
    <meta name="DC.Creator" content="Laurent Jouanneau" />
    <meta name="DC.Rights" content="Cet article est sous licence Creative Commons Attribution-ShareAlike." />
    <meta name="DC.Date.created" scheme="W3CDTF" content="2003-12-17" />
    <meta name="DC.Date.modified" scheme="W3CDTF" content="2003-12-17" />
    <meta name="DC.Subject" content="debutant, expert, pages_dynamiques, accessibilite, dom" />
  </head>
  <body>
    <h1>Bien valider ses formulaires avec Javascript</h1>
    <ul>
      <li>
        <strong>Profil :</strong> <a href="/debutant/">Débutant</a>, <a href="/expert/">Expert</a>
      </li>
      <li>
        <strong>Thème :</strong> <a href="/pages_dynamiques/">Pages dynamiques</a>, <a href="/accessibilite/">Accessibilité</a>
      </li>
      <li>
        <strong>Technologie :</strong> <a href="/dom/">DOM</a>
      </li>
      <li>
        <strong>Auteur :</strong> <a href="mailto:laurent.jouanneau%40openweb.eu.org">Laurent Jouanneau</a>
      </li>
      <li>
        <strong>Mise à jour :</strong> 17/12/2003</li>
    </ul>
    <h2>En bref</h2>
    <p>En fouinant sur le web, on peut découvrir plusieurs pratiques pour appeler
      des scripts en Javascript qui vérifient le contenu d'un formulaire. Mais elles
      sont, hélas, rarement correctes dans le sens où beaucoup d'entre elles
      réduisent l'accessibilité et l'ergonomie des formulaires, voire sont
      inefficaces. Cet article vous propose de passer en revue ce qu'il faut faire
      et ne pas faire en la matière.</p>
    <hr />
    <h3>Petit rappel sur les formulaires</h3>
    <p>Rappelons-nous d'abord de quoi est composé un formulaire :</p>
    <ul>
      <li>de champs de saisie, matérialisés par des balises <code>input</code>,
        <code>select</code> et <code>textarea</code> ;</li>
      <li>de boutons pour valider ou annuler / effacer le formulaire,
        respectivement <code>&lt;input type="submit" /&gt;</code> et
        <code>&lt;input type="reset" /&gt;</code> ;</li>
      <li>une balise <code>form</code> qui encadre le tout ;</li>
      <li>et éventuellement ce fameux script en Javascript qui va vérifier
        le contenu avant son envoi vers le serveur Web.</li>
    </ul>
    <p>Cet ensemble peut être complété par des balises <code>label</code>,
    <code>fieldset</code>, <code>legend</code>, etc. pour améliorer
    l'accessibilité et la structure d'un formulaire. Je vous renvoie à l'article
    <a href="/articles/formulaire_accessible/">Utilisation des formulaires</a> pour
    en savoir plus à ce sujet. Nous ne nous occuperons ici que de l'aspect Javascript.</p>
    <p>Voila ce que cela pourrait donner :</p>
    <pre>
&lt;form action="url_page_suivante" method="get" name="formSaisie"&gt;
  &lt;p&gt;
    &lt;label for="prenom"&gt;Saisissez votre prénom&amp;nbsp;:&lt;/label&gt;
    &lt;input type="text" name="prenom" id="prenom" /&gt;
    &lt;input type="submit" value="Ok" /&gt;
  &lt;/p&gt;
&lt;/form&gt;
</pre>
    <p>Nous sommes dans l'hypothèse où notre page est conforme au
    <acronym title="eXtensible HyperText Markup Language" lang="en">XHTML</acronym> 1.0 Transitionnal, et non Strict, pour
    faciliter la compréhension des exemples qui suivront. En effet,
    en <acronym>XHTML</acronym> Strict ou <acronym title="HyperText Markup Language" lang="en">HTML</acronym> 4.01 Strict, l'attribut
    <code>"name"</code> de la balise <code>form</code>
    est obsolète. De ce fait, il est impossible avec ces <acronym title="Document Type Definition" lang="en">DTD</acronym>
    d'utiliser le code <code>document.nom_du_formulaire</code>, très souvent utilisé,
    pour accéder aux champs de saisie (comme par exemple
    <code>document.nom_du_formulaire.mon_champs.value</code>). Nous verrons
    à la fin de cet article comment contourner cette restriction et écrire du code
    respectant un peu mieux les spécifications du <acronym title="Document Object Model" lang="en">DOM</acronym>,
    utilisable avec toutes les versions de <acronym>HTML</acronym>
    et sur tous les navigateurs.</p>
    <h3>Les erreurs les plus courantes</h3>
    <p>En général, les formulaires ressemblent à notre exemple, il n'y a pas trop
    de soucis. Là où ça se gâte, c'est
    au moment d'inclure le petit bout de code Javascript qui va vérifier que
    l'internaute a bien saisi un prénom (en se référant à notre exemple),
    avant d'envoyer le formulaire.</p>
    <p>Beaucoup de développeurs, instinctivement, implémentent (à tort)
    cette vérification au niveau du clic sur le bouton « Ok ».
    C'est ainsi que l'on trouve ce genre de fonction (à ne pas faire).</p>
    <pre>
&lt;script type="text/javascript"&gt;
&lt;![CDATA[

function valider() {
  // si la valeur du champ prenom est non vide
  if(document.formSaisie.prenom.value != "") {
    // alors on envoie le formulaire
    document.formSaisie.submit();
  }
  else {
    // sinon on affiche un message
    alert("Saisissez le prénom");
  }
}

]]&gt;
&lt;/script&gt;
    </pre>
    <p>Puis sur le bouton « Ok », on trouve en général
    l'appel de la fonction <code>valider()</code> sur l'événement
    <code>"onclick"</code>, déclenché lorsque
    l'on clique sur le bouton, ce qui ressemble à ceci :</p>
    <p>Cas A</p>
    <pre>
&lt;input type="submit" value="Ok" onclick="valider()" /&gt;
    </pre>
    <p>On trouve parfois aussi, non pas un bouton « submit »
    mais un bouton tout court, ou une image, ou un lien, ce qui est
    encore moins bien :</p>
    <p>Cas B</p>
    <pre>
&lt;input type="button" value="Ok" onclick="valider()" /&gt;
&lt;img src="ok.png" onclick="valider()" alt="ok" /&gt;
&lt;a href="#" onclick="valider()"&gt;Ok&lt;/a&gt;
</pre>
    <p>Souvent même, la fonction <code>valider()</code> est
    appelée directement dans l'attribut <code>"href"</code>
    d'un lien :</p>
    <p>Cas C</p>
    <pre>
&lt;a href="javascript:valider()"&gt;Ok&lt;/a&gt;
&lt;a href="javascript:valider()"&gt;&lt;img src="ok.png" alt="ok" /&gt;&lt;/a&gt;
    </pre>
    <h3>Pourquoi ce sont des erreurs ?</h3>
    <p>Il faut se mettre en tête que :</p>
    <ol>
      <li>l'utilisateur peut vouloir préférer appuyer sur la
        touche <kbd>Entrée</kbd> de son clavier plutôt que
        de cliquer sur le bouton « Ok ». Il peut s'agir des
        inconditionnels du clavier, mais il peut s'agir aussi de personnes
        qui sont obligées de passer par le clavier. Il y a ainsi ceux qui
        utilisent un navigateur texte. Il y a aussi les handicapés moteurs
        pour qui la manipulation de la souris peut être difficile. Il y a
        aussi les gens qui doivent manipuler à longueur de temps des
        formulaires, comme c'est le cas dans les applications intranet.
        Car éviter de passer du clavier à la souris et de la souris au
        clavier permet d'être plus productif et est moins fatiguant. Tous
        les ergonomes vous le diront ;</li>
      <li>le Javascript n'est pas forcément disponible dans le
        navigateur de l'internaute (ou tout simplement désactivé). La
        plupart des statistiques rapportent que c'est le cas pour 7 à
        10% des internautes.</li>
    </ol>
    <p>Ces constats nous amènent donc à nous rendre compte que les
    exemples vus précédemment sont inadaptés.</p>
    <p>Dans le cas A, si l'utilisateur appuie sur la touche
    <kbd>Entrée</kbd> en étant dans l'un des champs de
    saisie, ou s'il met le focus sur le bouton avec la touche <kbd>Tab</kbd>
    puis en appuyant sur <kbd>Entrée</kbd>, le formulaire
    sera envoyé, sans même que la fonction <code>valider()</code> soit
    exécutée. En effet, elle n'est ici appelée que sur l'événement
    <code>"onclick"</code>.</p>
    <p>Dans le cas B, étant donné qu'il ne s'agit ni de bouton « submit »,
    ni de bouton « image », la touche <kbd>Entrée</kbd> est
    inactive, et ne provoque pas l'envoi du formulaire. On est <em>obligé</em>
    de cliquer sur le bouton, l'image ou le lien. Cela peut être donc embêtant
    pour certaines personnes comme on l'a vu.</p>
    <p>Pire, dans les cas B et C, si le support du Javascript est désactivé
    ou n'est pas présent dans le navigateur, le formulaire ne pourra jamais
    être envoyé ! Idem si on n'a pas de souris (navigateur texte) dans
    le cas B !</p>
    <h3>
      <strong>La</strong> bonne façon de vérifier un formulaire</h3>
    <p>En fait, il n'existe qu'une seule méthode valable pour vérifier le
    contenu d'un formulaire en Javascript avant son envoi.</p>
    <h4>Utilisation des bons boutons</h4>
    <p>Le/les bouton(s) pour envoyer le formulaire doivent être :</p>
    <ul>
      <li>soit de type « submit » : <code>&lt;input type="submit" value="Ok" /&gt;</code> ;</li>
      <li>soit de type image, si on veut un bouton « submit »
          sous forme d'image : <code>&lt;input type="image" src="ok.png" alt="ok" /&gt;</code>.</li>
    </ul>
    <p>Rappelez-vous qu'il est possible d'utiliser des feuilles de styles
      pour changer l'apparence des boutons : couleurs, bordures, image de
      fond, etc.
      Il faut noter cependant que tous les navigateurs non conformes ne supportent
      pas tous les styles sur les boutons.</p>
    <h4>L'événement <code>"onsubmit"</code>
    </h4>
    <p>Cet événement, spécifique à la balise <code>form</code>, est
      déclenché lorsque le formulaire est sur le point d'être envoyé, suite à
      l'appui sur la touche <kbd>Entrée</kbd>, ou d'un clic sur un
      bouton « submit », ou toute autre action indiquant au navigateur
      d'envoyer le formulaire.</p>
    <p>Donc l'éxecution d'un script devant vérifier le contenu du formulaire
      (ou faisant éventuellement d'autres traitements liés à l'envoi)
      <strong>doit toujours se faire sur l'événement
      <code>"onsubmit"</code>
      </strong> !</p>
    <p>Comme sur tous les événements (<code>"onclick"</code>…),
      le script appelé doit renvoyer un booléen, <code>true</code> ou
      <code>false</code>. S'il ne renvoie rien, l'événement reçoit <code>true</code>
      par défaut. Ce booléen indique si l'événement doit se propager, c'est-à-dire si
      l'événement par défaut doit s'exécuter.</p>
    <p>Ainsi, si vous renvoyez <code>true</code> sur l'événement
      <code>"onsubmit"</code>, le formulaire sera envoyé.
      Si vous renvoyez <code>false</code>, il ne le sera pas. Par exemple,
      en mettant <code>onsubmit="return false"</code>, le formulaire ne pourra
      jamais être envoyé !</p>
    <p>Nous devons donc appeler notre fonction <code>valider()</code> sur
      le <code>"onsubmit"</code>, et celle-ci devra renvoyer
      un booléen pour indiquer si le formulaire doit être envoyé ou non :</p>
    <pre>
&lt;script type="text/javascript"&gt;
&lt;![CDATA[

function valider(){
  // si la valeur du champ prenom est non vide
  if(document.formSaisie.prenom.value != "") {
    // les données sont ok, on peut envoyer le formulaire    
    return true;
  }
  else {
    // sinon on affiche un message
    alert("Saisissez le prénom");
    // et on indique de ne pas envoyer le formulaire
    return false;
  }
}

]]&gt;
&lt;/script&gt;
      </pre>
    <p>Et la balise <code>form</code> devient :</p>
    <pre>
&lt;form action="url_page_suivante" <strong>onsubmit="return valider()"</strong>
  method="get" name="formSaisie"&gt;
  &lt;p&gt;
    &lt;label for="prenom"&gt;Saisissez votre prénom&amp;nbsp;:&lt;/label&gt;
    &lt;input type="text" name="prenom" id="prenom" /&gt;
    &lt;input type="submit" value="Ok" /&gt;
  &lt;/p&gt;
&lt;/form&gt;
      </pre>
    <p>Notez l'emploi du mot-clé <code>return</code> sur l'appel de <code>valider()</code>.</p>
    <p>Ainsi, que l'on appuie sur la touche <kbd>Entrée</kbd> ou
      que l'on clique sur le bouton « submit », la fonction
      <code>valider()</code> sera toujours appelée. Et si le Javascript n'est
      pas activé, cela n'empêche pas le contenu du formulaire d'être envoyé.</p>
    <h4>Quelques précisions</h4>
    <ol>
      <li>Le test du contenu d'un formulaire en Javascript doit être
          seulement considéré comme un <em>plus</em> pour le confort
          de l'utilisation de la page, afin d'éviter un envoi et un rechargement
          du formulaire si son contenu est invalide. Il ne remplace en aucun cas
          une vérification faite côté serveur, qui doit être systématique (que ce
          soit en <acronym title="PHP: Hypertext Preprocessor" lang="en">PHP</acronym>, <acronym title="Active Server Pages" lang="en">ASP</acronym>, Java, etc.),
          afin de palier le cas où le Javascript n'est pas activé, donc au cas où
          le formulaire n'est pas vérifié côté navigateur.</li>
      <li>S'il y a du code Javascript qui envoie le formulaire en appelant
          la methode <code>submit()</code> de l'objet formulaire comme
          ceci : <code>document.formSaisie.submit();</code>, l'événement
          <code>"onsubmit"</code> n'est pas déclenché, mais
          le formulaire est tout de même envoyé. Donc la fonction <code>valider()</code>
          ne sera pas appelée dans ce cas.</li>
      <li>On évitera d'utiliser les méthodes propriétaires à Internet Explorer comme
         <code>document.all</code> pour récupérer l'objet formulaire ou les objets
         correspondants aux champs de saisie, afin de garder une interopérabilité
         maximum. On préferera utiliser les fonctions du <acronym>DOM</acronym> comme nous
         allons le voir dans la section suivante.
         </li>
    </ol>
    <h3>La vérification de formulaire en Strict</h3>
    <p>Le problème des <acronym>DTD</acronym> Strict (<acronym>HTML</acronym> 4.01 Strict,
    <acronym>XHTML</acronym> 1.0 Strict ou <acronym>XHTML</acronym> 1.1),
    c'est que l'attribut <code>"name"</code>
    de la balise <code>form</code> est obsolète. Du coup, il est impossible de
    récupérer l'objet formulaire par l'instruction suivante comme on a très souvent l'habitude
    de faire : <code>document.formSaisie</code>. Cette instruction est en fait
    un raccourci de ce qu'il faudrait faire.</p>
    <h4>Utilisation du <acronym>DOM</acronym> avec la collection <code>forms</code>
    </h4>
    <p>L'objet <code>document</code> possède une propriété <code>forms</code>,
      qui est une collection contenant les objets formulaires présents dans la page.
      On peut alors l'utiliser de deux manières pour récupérer l'objet formulaire désiré </p>
    <ul>
      <li>
        <code>document.forms[n]</code> où <code>n</code> est le
			numéro de formulaire, 0 étant le premier formulaire.</li>
      <li>ou <code>document.forms['mon_formulaire']</code> où
				<code>mon_formulaire</code> est la valeur de l'attribut
            <code>"id"</code> de la balise <code>form</code>,
            ou bien de l'attribut <code>"name"</code>
            en (X)HTML transitionnal. Il faut savoir que si la balise <code>form</code>
            a les 2 attributs, c'est la valeur de l'attribut <code>"id"</code>
            qu'il faudra utiliser pour récupérer votre objet formulaire.
         </li>
    </ul>
    <p>Ensuite, un objet formulaire contient une propriété <code>elements</code>
      qui est une collection contenant les éléments de saisie du formulaire. On récupère
      donc un élément du formulaire d'une de ces façons </p>
    <ul>
      <li>
        <code>document.forms['mon_formulaire']<strong>.elements[n]</strong>
        </code>
         où <code>n</code> est le numéro de l'élément dans la collection, 0 étant le premier
         élément.</li>
      <li>ou <code>document.forms['mon_formulaire']<strong>.elements['mon_element']</strong>
        </code> où
				<code>mon_element</code> est la valeur de l'attribut
            <code>"id"</code> ou <code>"name"</code>
            de l'élément. Même remarque que pour les formulaires  si il y a les 2 attributs,
            il faudra utiliser la valeur de l'attribut <code>"id"</code>
            pour récupérer l'élément.
         </li>
    </ul>
    <p>Notre fonction <code>valider()</code> devient donc </p>
    <pre>
function valider(){
  <strong>frm=document.forms['frmSaisie'];</strong>
  if(frm.elements['prenom'].value != "") {
    return true;
  }
  else {
    alert("Saisissez le prénom");
    return false;
  }
}
</pre>
    <p>Ou encore </p>
    <pre>
function valider(){
  <strong>elt=document.forms['frmSaisie'].elements['prenom'];</strong>
  if(elt.value != "") {
    return true;
  }
  else {
    alert("Saisissez le prénom");
    return false;
  }
}
</pre>
    <p>C'est une méthode qui fonctionne sur tous les navigateurs. Tout comme
      la solution suivante.
      </p>
    <h4>Utilisation de <code>this</code>
    </h4>
    <p>Le mot clé <code>this</code> désigne toujours l'objet
      courant. Si on l'utilise lors de l'appel de la fonction
      <code>valider()</code> dans le <code>"onsubmit"</code>,
      on peut transmettre l'objet formulaire à la fonction <code>valider()</code> :</p>
    <pre>
&lt;script type="text/javascript"&gt;
&lt;![CDATA[

function valider(<strong>frm</strong>){
  if(frm.elements['prenom'].value != "") {
    return true;
  }
  else {
    alert("Saisissez le prénom");
    return false;
  }
}

]]&gt;
&lt;/script&gt;

&lt;form onsubmit="return valider(<strong>this</strong>)" id="frmSaisie" …&gt;
…
&lt;/form&gt;
      </pre>
    <p>À noter une petite astuce au passage : si vous avez
      besoin de faire des manipulations du formulaire Javascript sur
      des événements des champs de saisie ou de boutons, sachez que
      les objets Javascript correspondants à ces éléments
      <acronym>HTML</acronym> ont une propriété <code>form</code>
      représentant l'objet formulaire. Voici un exemple d'utilisation :</p>
    <pre>
&lt;script type="text/javascript"&gt;
&lt;![CDATA[

function afficher(<strong>frm</strong>){
  alert("Vous avez tapé : " + frm.elements['prenom'].value)
}
]]&gt;
&lt;/script&gt;

&lt;form&gt;
  &lt;p&gt;
    &lt;label for="prenom"&gt;Saisissez votre prénom&amp;nbsp;:&lt;/label&gt;
    &lt;input type="text" name="prenom" id="prenom" /&gt;
    &lt;input type="button" value="Afficher" onclick="afficher(<strong>this.form</strong>)" /&gt;
    &lt;input type="submit" value="Ok" /&gt;
  &lt;/p&gt;
&lt;/form&gt;
      </pre>
    <h3>Les commentaires dans la balise script</h3>
    <p>Vous avez pu remarquer que tout le code situé entre les balises
   <code>script</code>, était encadré par <code>&lt;![CDATA[</code> et <code>]]&gt;</code>.
   C'est la manière en <acronym>XHTML</acronym> d'indiquer que le contenu représente des données.
   En <acronym>HTML</acronym>,
   il faut utiliser les délimiteurs de commentaires HTML, à savoir <code>&lt;!--</code>
   et <code>--&gt;</code>, pour éviter que le code javascript ne s'affiche dans
   les anciens navigateurs.</p>
    <p>Pour que le contenu de la balise script en <acronym>XHTML</acronym> soit interpreté correctement,
   quel que soit le navigateur, y compris les plus anciens, il faut alors utiliser
   l'astuce suivante :</p>
    <pre>
&lt;script type="text/javascript"&gt;
&lt;!--/*--&gt;&lt;![CDATA[//&gt;&lt;!--
...
//--&gt;&lt;!]]&gt;
&lt;/script&gt;
   </pre>
    <p>Le plus simple est encore de mettre le script dans un fichier séparé :</p>
    <pre>
&lt;script type="text/javascript" src="nom_de_mon_fichier.js"&gt;&lt;/script&gt;
   </pre>
    <h3>Conclusion</h3>
    <p>Si la validation en JavaScript est pratique pour l'utilisateur, il convient de la
    développer correctement de façon à rester compatible avec tous les types de navigateurs
    et d'usages. Pour cela, le recours au bouton <code>submit</code> s'impose !</p>
  </body>
</html>
