Les formulaires HTML et JavaScript

Utiliser un formulaire à la place des fonctions prompt() & alert()

Dans les exemples du chapitre précédent (les bases du JavasScript) l'utilisateur communique avec le programme grâce à des fonctions de JavaScript : prompt(), confirm(), alert(). C'est pas très ergonomique ...

Si JavaScript est un excellent langage de programmation pour le Web il faut cependant constater que la gestion des entrées et sorties sont minimalistes ...

Heureusement en HTML nous avons un outil formidable : le formulaire.
Il faut donc préférable de confier les entrées-sorties d'un script à un formulaire HTML.

Premier exemple

Thème: l'utilisateur saisit un nom et un prénom et le script retourne la concaténation des deux.

Le code CSS et HTML

... <style> label, input, button {display : inline-block ; width : 45% ; height : 40px ; margin : 10px ; vertical-align : top ; } label {text-align : right ; } ... <form name ="f"> <label>votre nom : </label> <input type = 'text' name ="nom"> <label>votre prénom : </label> <input type = 'text' name ="prenom"> <label></label><button type = 'button' name ="bouton">Concaténez ! </button> <label>Nom et prénom : </label> <input type ='text' readonly name ="nom_prenom"> </form> ...

Commentaire du CSS :
dans un formulaire on utilise surtout les balises input, label, button. Ces balises sont par défaut de type inline alors que la balise form est de type block. Or nous voulons avoir la légende (balise label) du champ puis le champ de saisie (balise input) alignés. Il faut donc que ces balises deviennent de type inline-block c'est à dire des boites qui comme toutes les boites peuvent être dimensionnées mais qui se positionnent côté à côté tant qu'il y a de la place.

Ici chaque légende ou champ a une largeur interne de 45% de la largeur de la boite parente (FORM). Donc il y aura deux contrôles par ligne (la balise LABEL et la balise INPUT).

Commentaire du HTML :
les attributs action et method de la balise form sont ici inutiles puisque ce formulaire n'a pas pour objet d'envoyer les données saisies dans une autre page en vue d'un traitement PHP (avec éventuellement un stockage dans une base de données).
Astuce : notez une balise LABEL vide afin que le bouton de commande se positionne au dessous des champs de saisie.

Depuis HTML5 les boutons de commande peuvent être créés avec la balise double BUTTON.
Attention : le bouton doit être impérativement de type "button" car il est associé à une fonction JS. Si vous ne précisez pas le type d'un bouton il est par défaut de type "submit". Et alors dès que vous cliquez sur le bouton le contenu du formulaire est effacé ... donc vous ne voyez pas le résultat.
Notez pour le troisième input l'attribut readonly. Il est donc impossible de saisir dans ce champ !

Dans le formulaire chaque INPUT et le bouton de commande sont nommés grâce à l'attribut name.
Ces noms seront utilisés dans le script.

Le script

Il est d'une simplicité déroutante !

f.bouton.onclick = function () {f.nom_prenom.value = f.nom.value +" "+ f.prenom.value}

Pour référencer dans le script un élément de formulaire j'ai utilisé une vieille technique mais toujours valide et reposant sur la syntaxe : nomFormulaire.nomChamp.

Je rajoute "value" quand je manipule le contenu d'un champ ou "onclick" pour appeler une fonction sur clic.
Notez que la fonction n'a pas de nom. On dit qu'il s'agit d'une fonction anonyme.
Testez ce code !

Deuxième exemple

Nous saisissons un nombre (entier ou décimal) dans un champ et le carré ce nombre s'affiche dans un deuxième champ du formulaire.

Le code CSS & HTML

La feuille de style interne est strictement identique à celle de l'exemple précédant. Donc je vous communique uniquement le code de la partie BODY

<form name ="f"> <label>Saisir un nombre :</label><input type = 'number' name ="nombre" > <label></label><button type = 'button' name ="bouton">Calculez le carré de ce nombre !</button> <label>Carré du nombre :</label><input type = 'text' readonly name ="carre"> </form>

Le premier INPUT est de type "number" donc on ne peut saisir dans ce champ que des valeurs numériques (impossible de saisir des lettres). Autre avantage ce champ accepte comme séparateur décimal la virgule ...
Inconvénient : ce type de INPUT est introduit par HTML5 donc n'est pas reconnu pas les anciens navigateurs qui vont le traiter comme un champ de type "text".

Le script

Encore une fois il est très succinct puisque le contrôle de saisie est effectué via le formulaire.

	f.bouton.onclick =function()
		{	
			var vnombre = f.nombre.value;
			f.carre.value = vnombre * vnombre;
		}

Le script ne présente aucune difficulté.
Essayez ce code !

Contrôle de saisie

Je vais maintenant évoquer l'emploi de JS dans le cadre d'un formulaire de soumission c'est à dire un formulaire qui permet d'adresser des données en vue d'un traitement PHP, traitement qui modifie le plus souvent la base de données.
On reconnait un formulaire de soumission facilement ; les attributs action & method de la balise FORM sont alors obligatoires.

Dans ce type de formulaire avant toute tentative de soumission des données il faut procéder à un contrôle de saisie par le navigateur ou côté client.

Vous êtes en droit de vous dire que grâce à toutes ces nouveautés apportées par HTML5 & CSS3 on peut parfaitement effectuer un contrôle de saisie côté client sans avoir à recourir à JavaScript.
En effet pour vérifier si un champ n'est pas vide ou si la saisie correspond à un certain gabarit vous n'avez plus besoin de JS ; il suffit d'utiliser les nouveaux attributs required et pattern.
Mais si vous devez comparer la saisie dans deux champs différents alors HTML, même version 5, ne vous est d'aucun secours puisque la notion de test n'existe pas dans ce langage. Mais heureusement il y a JavaScript !

Première thématique : inscription à un site

Pour vous inscrire sur un site de rencontres coquin (lol) vous devez saisir en guise d'identifiant votre adresse mail et la confirmer puis choisir un mot de passe et le confirmer.
Le mot de passe doit contenir entre 6 et 8 caractères alphanumériques c'est à dire des lettres non accentuées et des chiffres. Les autres caractères sont bannis.

Première solution : sans JavaScript

... <style> label, input, button {display : inline-block ; width : 44% ; height : 30px ; margin :10px 1% 10px 1% } input:invalid {color : red; } input:valid {color : lime ; } button:hover {color : red ; box-shadow : 5px 5px 5px grey ; } ... <form action = "inscription_trait.htm" method ='post'> <p>Vous devez saisir votre adresse mail en guise d'identifiant et choisir un mot de passe. <br>Le mot de passe est composé de lettres non accentuées et de chiffres ; entre 6 et 8 caractères</p> <label>Tapez votre adresse mail : </label> <input type = "email" required placeholder = "n'oubliez pas @" name ='mail1'> <label>Confirmez votre adresse mail : </label> <input type = "email" required name ='mail2'> <label>Saisissez mot de passe :</label> <input type = "password" required pattern ='[A-z0-9]{6,8}' maxlength ='8' placeholder = 'entre 6 et 8 lettres ou chiffres' name ='passe1'> <label>Confirmer le mot de passe : </label> <input type = "password" required pattern = '[A-z0-9]{6,8}' maxlength ='8' name ='passe2'> <label></label><button type = 'submit'> inscription</button> </form> ...

les données envoyées avec la méthode POST. En cas de succès de la soumission accès à la page "inscription_trait.htm" ;
Page qui réserve quelques surprises ...

Quatre "input" dont deux de type "email" et deux de type "password"
Les attributs name dans chaque input sont utiles que dans le cadre du traitement PHP (traitement qui ne sera pas évoqué).

Notez les pattern associés aux champs pour la saisie et confirmation du mot de passe.

D'après ce "pattern" seuls sont autorisés les lettres (majuscules et minuscules) non accentuées ainsi que les chiffres. Donc les lettres accentuées, les caractères de ponctuation, etc sont interdits.

On ne ne peut saisir plus de 8 caractères (maxlength ="8").

Test 1

Faites le test !

Bravo! vous accéder à la page "inscription_trait". Donc vous avez pu soumissionner avec succès.

Test 2

Faites le test !

Vous accéder quand même à la page "inscription_trait" alors que les deux adresses mail saisies sont différentes et les deux mots de passe sont également différents ...
Vous découvrez à cette occasion les limites du HTML !

Solution avec un script (solution provisoire)

Grâce à JS il sera possible de comparer la saisie 1 à la saisie2 et de comparer la saisie 3 à la saisie 4

Le code HTML

En effet il n'y a qu'un petit changement dans le code HTML.

<button type = 'button' onclick = 'fenvoi()'> inscription</button>

Le bouton de type "submit" est remplacé par un bouton de type "button" pour pouvoir appeler une fonction JS. En effet un bouton de type "submit" ne permet pas d'appeler une fonction JS.

Le script

function fenvoi() { // création des variables objets var mail1 = document.querySelector('input') ; var mail2 = document.querySelectorAll('input')[1] ; var passe1 = document.querySelectorAll('input')[2] ; var passe2 = document.querySelectorAll('input')[3] ; var formulaire = document.querySelector('form'); // test if(mail1.value == mail2.value && passe1.value == passe2.value) { alert ('ok') ; formulaire.submit() ; } else alert('erreur de saisie') ; } // fin fonction

J'utilise les nouvelles méthodes de l'objet document pour référencer les champs de saisie.
Il suffit de savoir compter jusqu'à 4 puisqu'il y a quatre INPUT sachant que querySelector("input") référence le premier INPUT. Remarque : pour référencer le premier INPUT j'aurais pu écrire : document.querySelectorAll('input')[0] ;

Si les deux adresses mail sont identiques et les deux mots de passe saisie sont identique alors soumission du formulaire (emploi de la méthode submit de JavaScript appliquée au formulaire).

Tests

Testez le code !

En effet les contrôles de saisie HTML5 ne fonctionnent plus ici car le bouton de commande est de type button. !
Retenez bien. Pour que les contrôles de saisie HTML (créés grâce aux attributs pattern, required) fonctionnent il faut impérativement que le bouton d'envoi soit de type submit.

Solution définitive

Comment bénéficier simultanément des contrôles de saisie HTML et de ceux programmés dans le script ???
Il y a une astuce de codage que je vais évoquer maintenant.

Le code du formulaire (extraits)

<form name ="formulaire" action = "inscription_trait.htm" method ='post' onsubmit="return fenvoi()" > ... <label></label><button type ="submit"> inscription</button> </form>

J'ai donné un nom au formulaire : name ="formulaire".

Le bouton de commande est redevenu de type submit.

Donc on bénéficie à la fois des contrôles de saisie HTML et JS. C'est pas beau la vie !!!

Le script

function fenvoi() { // variables var compteur =0 ; var mail1 = formulaire.mail1.value; var mail2 = formulaire.mail2.value; var passe1 = formulaire.passe1.value; var passe2 = formulaire.passe2.value; // test if(mail1 == mail2) compteur++; if(passe1 == passe2) compteur++; if (compteur < 2) {alert("champs mal renseignés");return false; } if (compteur==2) {alert("saisies correctes"); return true;} } // fin fonction

J'ai utilisé une autre méthode pour référencer dans le script les champs du formulaire et qui repose sur la syntaxe : nomFormulaire.nomChamp. Il s'agit d'une technique aussi ancienne que le JavaScript mais qui est toujours valide.

La variable compteur est incrémentée à chaque fois qu'un test est vérifié.

Si compteur < 2 la fonction retourne FALSE et donc pas de soumission.
Si compteur ==2 (tous les tests vérifiés) la fonction retourne TRUE et donc soumission des donnés.

Tests

Testez !

Premier essai :
Saisir : toto - toto- aaaa - aaaa
Les mails et mots de passe sont égaux entre eux mais ne correspondent pas aux "pattern" donc soumission bloquée.

Deuxième essai :
Saisir : toto@free.fr - toto@free.fr - abcedef -abcdef
Les mails et mots de passe sont identiques et le mail est correct (existence du caractère "@" dans la chaine).

Une adresse mail correcte c'est non seulement le caractère "@" mais aussi un point après ce caractère.
Donc dans le cadre d'un script "professionnel" il faudrait utiliser un pattern basé sur une expression régulière ...

Remarque importante

Un contrôle des saisies côté client (navigateur) ne dispense d'une vérification côté serveur (en PHP au niveau de la page cible).
En effet le JavaScript peut être désactivé par le navigateur.
Un utilisateur chevronné du Web peut accéder au code du formulaire et supprimer pour sa session les contrôles de saisie HTML.
En d'autres termes tous les contrôles côté client peuvent être rendus inopérants !

Deuxième thématique : fiche de renseignements

L'objectif du formulaire n'est pas d'adresser les données saisies dans une autre page (en vue d'un traitement PHP) mais tout simplement de créer une chaine concaténant les "values" des cases cochées ou des items sélectionnés dans les listes.
C'est pour cette raison que la balise FORM n'a pas ni l'attribut action ni l'attribut method puisqu'il n'y a pas soumission.

Le code CSS et HTML

... input[type = checkbox], input[type = radio], span {width : 5% ; height : 20px ; margin : 1% ; vertical-align : top; } label,button,select {display : block ; margin-left : 2% ; width :40%;} ... <form> <h2>Fiche de renseignements en ligne</h2> <label>Civilité : </label> <span>Monsieur</span><input type ='radio' value = 'Msieur' name = 'civilite'> <span>Madame</span><input type ='radio' value = 'Mme' name = 'civilite'> <span>Mademoiselle</span><input type ='radio' value = 'Mlle' name = 'civilite'> <label>sports pratiqués :</label> <span>aucun</span><input type ='checkbox' value = 'Rien' name = 'sports' > <span>vélo</span><input type ='checkbox' value = 'Vélo' name = 'sports'> <span>football</span><input type ='checkbox' value = 'Foot' name = 'sports'> <span>natation</span><input type ='checkbox' value = 'Nata' name = 'sports'> <span>autres</span><input type ='checkbox' value = 'autres' name = 'sports'> <label>Votre tranche d'âge :</label> <select id = 'age'> <option value = 't1'>Moins de 20 ans </option> <option value = 't2'>Entre 20 et 40 ans </option> <option value = 't3'>Entre 40 et 60 ans </option> <option value = 't4'>Plus de 60 ans </option> </select> <label>Jeux de carte pratiqués :</label> <select id = 'jeux' multiple= "multiple" size ="6" > <option value = 'Rien'>aucun </option> <option value = 'Be'>Belote </option> <option value = 'Ta'>Tarot </option> <option value = 'Br'>Bridge </option> <option value = 'Po'>Poker </option> <option value = 'Autres'>Autres</option> </select> <button type ="button" onclick ="ftrait()">Traitement</button> </form> ...

Le script

Le traitement JS sera justement le suivant :

function ftrait() { var chaine1=""; var chaine2=""; var chaine3=""; var chaine4=""; var civilite = document.getElementsByName("civilite") ; for (i = 0 ; i < civilite.length; i++) { if (civilite[i].checked) chaine1 = civilite[i].value; } var sports = document.getElementsByName("sports") ; for (i = 0 ; i < sports.length; i++) { if (sports[i].checked) chaine2 = chaine2 + " " + sports[i].value; } var age = document.getElementById("age") ; for (i = 0 ; i < age.length; i++) { if (age.options[i].selected) chaine3 = age.options[i].value; } var jeux = document.getElementById("jeux") ; for (i = 0 ; i < jeux.length; i++) { if (jeux.options[i].selected) chaine4 = chaine4 + " " + jeux.options[i].value; } document.write("civilité : " +chaine1 + " sports pratiqués : " + chaine2 +" code tranche d'âge : " + chaine3 + " jeux de cartes : " + chaine4); }

Le script consiste tout simplement à concaténer dans toutes les "values" saisies dans différentes variables (civilite, sports, age, jeux) et à afficher ces différentes variables.

Tests

Testez le formulaire

Traitement des groupes de boutons radio ou de cases à cocher en JS

Il faut créer une variable indicée (tableau) qui identifie tout le groupe d'où l'emploi de la méthode getElementsByName.
Une boucle permet ensuite d'examiner les éléments du groupe.
Pour chaque passage dans la boucle il suffit de tester si l'élément est coché (checked).
Dans un groupe de boutons radio une seule case peut être cochée ce qui n'est pas le cas pour un groupe de cases à cocher.
Il faut donc dans ce dernier cas concaténer dans une variable les "values" des cases cochées.
Exemple: if (sports[i].checked) chaine2 = chaine2 + " " + sports[i].value;

Traitement des listes déroulantes en JS

Une liste est un conteneur (balise select) incluant plusieurs items (balise option).
On crée une variable qui référence la liste via son identifiant (getElementById).
Une boucle permet ensuite d'examiner toutes les balises option de la liste.
Ainsi, par exemple, si la liste est référencée age les différents items sont référencés age.options[i]
Pour chaque passage dans la boucle il suffit de tester si l'item a été sélectionné (exemple : if (jeux.options[i].selected)).
Dans une liste simple il ne peut y avoir qu'un seul item sélectionné alors que dans une liste à sélection multiple on peut sélectionner plusieurs items ; il faut alors concaténer dans une variable les "values" des items sélectionnés.
Exemple: if (jeux.options[i].selected) chaine4 = chaine4 + " " + jeux.options[i].value;
Retour menu