Remarque préliminaire: ce fichier contient une erreur javascript volontaire.
JavaScript et les formulaires
Permet de valider les formulaires côté client.
Attention : ne dispense pas de la validation côté serveur, qui est indispensable (sécurité).
On peut accéder aux formulaires et au champs par leurs id si on leur en donne.
On peut accéder aux formulaires par leur nom (name); de même pour les champs.
Principe: on lie des fonctions javascript à certains événements
(on quitte un champ, on valide le formulaire, on presse une touche...)
Vérification à l'expédition
On veut que le formulaire soit vérifié juste avant d'être expédié
On utilise l'événement onsubmit de la balise form
Quand le formulaire va être envoyé, on appelle le code javascript dans onsubmit
Si la valeur de onsubmit a la forme return nomDeFonction():
Si la fonction renvoie true, l'action est effectuée
Sinon, le formulaire n'est pas expédié
Premier exemple
On veut tester que le nom et le prénom fournis par l'utilisateur ne sont pas vides.
Critique de la méthode précédente
alert() : message d'erreur peu précis
disparaît quand on veut corriger
agressif (nouvelle fenêtre)
On utilisera plutôt la manipulation du DOM (voir ci-dessous) pour écrire les messages d'erreur directement sur la page...
Traitement des champs en cours d'édition
Le plus souvent, on utilise l'événement onblur ou onchange
Avec onblur, le code est appelé quand le curseur quitte le champ (il perd le "focus"),
Avec onchange, le code est appelé
quand le curseur quitte le champ et que la
valeur a changé;
onchange s'utilise aussi pour un
champ de type select, auquel cas il
permet tout simplement de savoir que la sélection a
été modifiée.
S'utilise en complément de onsubmit
On n'a pas besoin de retourner une valeur
Vérification lors de la frappe
On peut utiliser onkeydown pour un traitement avant modification du champ
ou onkeyup pour un traitement a posteriori.
Noter l'utilisation de return (ne fonctionne qu'avec onkeydown)
Tapez du texte (mais pas de chiffre)
Traitement d'un formulaire uniquement en Javascript
Normalement un formulaire <form> charge une nouvelle page ;
Si on veut rester sur la même page, plusieurs solutions :
ne pas utiliser de formulaire
que onSubmit retourne false
utiliser des url javascript:
<form action="javascript:pageSuivante()" >
<input type="submit" value="passer a la page suivante" >
<form>
Propriétés spécifiques aux éléments de formulaire
Valables pour certains des éléments (pas forcément tous, ex. selected).
value
Pour les champs de formulaire uniquement. Contient la valeur
actuelle du champ. L'attribut value, accessible par
getAttribute(), quant à lui, contient la valeur par
défaut.
name
pour les éléments qui ont un attribut name, et en particulier les champs de formulaire, la valeur de l'attribut en question.
disabled
un booléen. Permet de désactiver/activer un champ
readOnly
un booléen. Permet de placer un champ en lecture seule
checked
pour les cases à cocher (CheckBox). Permet de les cocher/décocher
selectedIndex
pour des listes de type Select, permet de fixer ou consulter l'élément sélectionné
selected
S'utilise sur un élément option dans une
liste. Permet de le sélectionner/déselectionner.
Propriétés des éléments de formulaire textuels: input (texte), textarea
name
nom de l'élément (et variable qui sera envoyée au serveur)
value
valeur de l'élément. en lecture et en écriture.
Événement spécifique : onchange
Propriétés de <input type="checkbox"> et <input type="radio">
name
nom de l'élément (et variable qui sera envoyée au serveur)
checked
booléen (true ou false) permettant de savoir si l'élément est coché.
en lecture et en écriture.
value
valeur de l'élément.
Checkbox
Attention, pas de "onchange" !
Solution : onclick
Checkbox
Propriétés des éléments de formulaire: select
Un élément select contient des éléments option.
Si le select ne permet qu'une sélection, on utilisera la
propriété value du select :
var monSelect= document.getElementById("idSelect");
var monOpt= monSelect.value;
Sinon, on récupèrera le tableau des options (options[]) ou on attaquera directement l'option désirée.
Le code suivant donne la première option sélectionnée:
var monOpt= monSelect.options[monSelect.selectedIndex].value;
Dans le cas où il y a plusieurs options sélectionnables, le code suivant les range dans un tableau:
var o= monSelect.options;
var resultat= new Array();
var i;
for (i= 0; i < o.length; i++) {
if (o[i].selected) {
resultat.push(o[i].value);
}
}
Le select a aussi une
propriété selectedIndex qui donne la position de
l'élément selectionné.
Notez que value, selectedIndex (pour les select) et selected pour les options peuvent être modifiés.
Méthodes des éléments de page : les tables
On peut éventuellement manipuler directement le DOM des tables, mais
des méthodes spécifiques sont prévues :
Si tabElt est un élément de type table, il dispose des propriétés et méthodes suivantes:
tabElt.rows tableau des lignes de tabElt.
var rowElt= tabElt.insertRow(pos) : insère
une nouvelle ligne dans le tableau, à la
position pos (pos= 0: première ligne; pos= -1 : fin du tableau), et retourne l'élément correspondant au <tr>
tabElt.deleteRow(pos) : pour détruire la ligne d'index pos ; -1 pour détruire la dernière ligne.
Méthodes pour les lignes de tableau
On devra aussi pouvoir manipuler les tr:
rowElt.cells tableau des cases (cellules) de la ligne.
var cellElt= tabElt.insertCell(pos) : insère
une nouvelle cellule dans la ligne, à la
position pos (pos= 0: première ligne; pos= -1 : fin du tableau), et retourne l'élément correspondant au nouveau <td>
tabElt.deleteCell(pos) : pour détruire la case d'index pos ; -1 pour détruire la dernière case de la ligne.
Pour ajouter une ligne de trois cases à la fin d'un tableau (désigné par la variable tabElt) on fera donc:
var tabElt= document.getElementById("monTableau");
var rowElt= tabElt.insertRow(-1);
var cellule= rowElt.insertCell(-1);
cellule.textContent= "case 0";
cellule= rowElt.insertCell(-1);
cellule.textContent= "case 1";
cellule= rowElt.insertCell(-1);
cellule.textContent= "case 2";
Les événements
gestionnaires liés à des balises : onclick, onchange,
etc...
le code javascript exécuté par le gestionnaire peut
être quelconque, ou une fonction qui prendra l'événement
comme argument. (exemple:cliquez dans la zone ci-dessous).
Notez que l'événement doit s'appeler event dans l'appel.
Quelques propriétés des événements
clientX, clientY : position de la souris dans le navigateur
web
altKey, shiftKey, ctrlKey, metaKey: booléens indiquant
si une touche alt, shift... est pressée
Position d'un événement relativement à un élément
Pour donner la position d'un événement dans l'élément
auquel il est lié, on ne dispose pas de méthode standard.
IE propose offsetX/offsetY, et les autres,
rien.
D'où le code
// offsetX est-il défini ??
if (event.offsetX) {
x= event.offsetX;
y= event.offsetY;
} else {
// On calcule la position
pos_x = event.pageX-document.getElementById("eltID").offsetLeft;
pos_y = event.pageY-document.getElementById("eltID").offsetTop;
}
Le DOM (Document Object Model)
Représentation manipulable par javascript de la page web courante.
Structure d'arbre
Accessible à travers l'objet pré-défini document
Compatible avec le DOM XML : spécification pour la
manipulation de documents XML dans n'importe quel
langage de programmation.
en théorie, contrôle total sur le document
en pratique, certains navigateurs ne supportent pas certaines manipulations.
Représentation d'un document
Un document HTML, aux yeux du DOM, est un arbre composé de
noeuds, qui représentent les balises (appelées
éléments), le texte, et les
attributs. En pratique, on traitera les attributs à part.
Celui-ci contient un élément racine, qui représente la balise html
Par la suite, on mélange des éléments (des balises) et du texte.
Chaque élément a des enfants (childNodes) qui représentent son contenu.
Ces enfants sont, soit du texte, soit des éléments.
Attention: selon les navigateurs, le contenu du DOM peut varier. Par exemple, certains navigateurs insèrent du texte pour représenter les espaces et les retours à la ligne entre body et le premier p.
Les noeuds (introduction)
Chaque partie du document (texte ou élément) est représentée par un noeud (node)
Chaque noeud est un objet.
Je peux lire et (parfois) écrire ses propriétés pour consulter ou changer ses caractéristiques
Je peux appeler des méthodes sur le noeud pour modifier son contenu, par exemple
On distingue plusieurs types de noeuds, avec des caractéristiques différentes, dont les noeuds texte et les noeuds éléments
Pour consulter ou modifier le contenu d'une page en javascript, les étapes sont:
récupérer le ou les éléments concernés
lire et/ou modifier leurs caractéristiques
Accès aux éléments
la méthode normale pour manipuler un élément est
de le doter d'un identificateur, et d'utiliser la méthode
document.getElementById(ID).
Exemple: si j'écris
<p id='monIdentificateur0'> un paragraphe </p>
Je peux récupérer l'élément en javascript en utilisant getElementById:
... dans du code javascript: ...
var monParagraphe= document.getElementById('monIdentificateur0');
// Maintenant, la variable monParagraphe contient l'élément qui représente la balise.
getElementById() renvoie null si l'élément n'est pas trouvé ;
la méthode document.getElementsByTagName() renvoie le
tableau de tous les éléments correspondant à une balise donnée :
// Exemple de code: compte le nombre de balises div avec comme classe "exemple" dans le document courant:
// (du type <div class="exemple">...</div;>)
funtion compterExemples() {
var nb=0;
var i= 0;
var tab= document.getElementsByTagName("div");
for (i= 0; i < tab.length; i++) {
// Le champ qui contient la classe est "className" et non "class"
// (car class est un mot réservé)
if (tab[i].className == "exemple")
nb= nb + 1;
}
return nb;
}
Accès aux éléments (suite)
La méthode document.getElementsByName() récupère des éléments à partir de leur attribut "name".
Son comportement est très (trop) variable selon les navigateurs.
document.documentElement désigne la racine du document (l'élément HTML)
document.body désigne l'élément "body" du document
Accès aux éléments (HTML5)
document.querySelector(q) prend comme argument un sélecteur
CSS, et renvoie le premier élement qui satisfait le sélecteur.
document.querySelectorAll(q) prend comme argument
un sélecteur CSS, et renvoie la liste des
éléments qui satisfont le sélecteur.
Exemple
un exemple pour tester
op
Propriétés et méthodes des éléments
Tout élément elt a les propriétés suivantes.
innerHTML : non standard (mais implémenté partout), code HTML interne de l'élément ;
textContent : contenu textuel de l'élément (tout le texte, en ignorant les balises). Pour IE: à partir d'IE 9.
parentNode : nœud parent ;
childNodes : tableaux des noeuds fils. Chaque noeud fils est, soit un noeud élément (de nodeType 1), soit un noeud texte (nodeType 3) ;
firstChild : équivalent de childNodes[0] ;
lastChild : dernier fils ;
nodeName : nom de la balise ;
nodeType : 1 pour éléments (balises) ;
id : identifiant du noeud ;
className : classe (au sens CSS) de l'élément ;
style : accès aux propriétés CSS de l'élément ;
getAttribute(NOM) : valeur d'un de ses
attributs. Ne fonctionne pas pour l'attribut "class"
sous IE.
setAttribute(NOM,VALEUR) : pour un noeud/élément, permet
de fixer la valeur d'un attribut. Ne
fonctionne pas sous IE pour les styles css ni
pour l'attribut "class".
Propriétés des noeuds textes
nodeType
toujours à 3 pour un noeud texte.
nodeValue
texte contenu dans le noeud. On peut modifier cette valeur.
Exemple:
ce texte sera modifié, pas celui-ci
Parcours d'un document
Pour parcourir un document, on va typiquement:
Récupérer l'élément racine à partir duquel on fera le parcours.
Utiliser childNodes pour parcourir les fils des éléments en question.
Pour les dit fils, on regardera quel est leur type, et on agira en conséquence.
=> parcours d'arbre
Exemple: on veut afficher le texte de la liste précédente dans l'élément ci-dessous.
texte quelconque
Remarques sur les propriétés
En théorie, on peut aussi manipuler des noeuds qui représentent les
attributs. Mais en pratique, un bon nombre de navigateurs internets ont
des interprétations trop personnelles de ceux-ci. On utilisera donc les propriétés des éléments :
style
pour accéder aux informations CSS (en lecture et en écriture)
className
pour lire ou écrire la classe CSS d'un élément
id
pour accéder à l'identifiant d'un élément
Modification des éléments: 1) innerHTML
Principe
innerHtml est une propriété des éléments DOM, et représente le code HTML compris à l'intérieur
d'une balise. Par exemple, si j'ai la balise :
Solution au dernier problème: écrire une fonction qui
remplace les caractères <, > et & par <,
> et &, et l'utiliser lors du remplacement... ou passer par le DOM.
Création en passant par le DOM
Théoriquement, c'est la manière normale. Elle
permet, entre autres, d'ajouter et d'insérer des éléments.
Deux étapes : créer un élément, et d'insérer dans l'arbre.
Création de noeud
Deux méthodes de l'objet document :
document.createElement('nomDuTag') : crée un élément (balise) pour un type donné de balise. exemple
titre= document.createElement('h1');
document.createTextNode('contenu de l'élément')
Les éléments sont simplement créés, et pas insérés dans l'arbre.
Insertion d'élément
On insère les éléments dans un élément parent, en utilisant les méthodes suivantes (n étant un noeud) :
pere.appendChild(nouveauNoeud) : ajoute un noeud comme dernier fils
pere.insertBefore(a,b) : insère a juste avant le noeud b ; si b est null, insère à la fin
Exemple: pour insérer en première position, on fera
parent.insertBefore(nouveau, parent.firstChild);
Si la liste des enfants est vide, firstChild est null et ça fonctionne quand même.
Remplacement et suppression d'élément
pere.removeChild(fils) : enlève un noeud
pere.replaceChild(ancien,nouveau) : remplace un noeud par un autre.
Premier exemple
On reprend l'exemple utilisé pour innerHTML, mais en l'écrivant de manière sûre
Ce texte sera remplacé...
Exemple de modification au travers du DOM...
On crée une liste dont la taille augmente à chaque click sur un bouton. Utilisation pratique:
formulaire avec nombre variable d'entrées...
Remarque: ce code n'est pas du HTML valide, car une liste n'a pas le
droit d'être vide (en voilà une idée qu'elle est étrange, car quand
le code est créé automatiquement, on peut très bien se retrouver
avec des "listes" vides. Supposez une requête qui ne renvoie rien,
par exemple). Pour bien faire, il faudrait, soit ajouter un élément
<li> caché (display="hidden"), soit ne créer la liste qu'avec
le premier élément.
Version ancienne du DOM (Pré-XML)
Les premières versions de javascript ne permettaient pas de manipuler le document de manière souple.
Seuls étaient accessibles
les formulaires (forms), les images, les layers, et les liens.
Chacun de ces éléments est accessible à travers un tableau :
document.forms[]
,
document.images[]
,
document.layers[]
et
document.links[]
. Ces tableaux sont utilisables même en XHTML.
pour les éléments en question, s'ils avaient un name, ils étaient accessibles par document.NOM.
Cependant, en XHTML, les form, par exemple, ne peuvent plus avoir d'attribut name.
les éléments de formulaire étaient alors accessibles par : document.nomFormulaire.nomChamp
Exemple:
<form name="monFormulaire2" action="uneAction" onsubmit="return prixPositif()">
<input type="text" name="prix">
........
</form>
<script type="text/javascript">
function prixPositif() {
var p= document.monFormulaire2.prix.value;
p= parseFloat(p);
// si p non numérique, retourne la valeur NaN (not a number)
// On peut tester avec isNaN
return ! isNaN(p) && p > 0;
}
</script>
système simple, mais qui rend difficile l'écriture de code réutilisable.
Ne fonctionne pas en XHTML strict: name n'est plus défini pour les <form>.
Chargement des pages
L'intéraction entre javascript et la page web dépend de
l'existence de certains objets DOM. Il importe donc de savoir
comment se passe le chargement des pages:
Le code est lu en même temps que la page
Le code HTML crée des objets qui représentent les balises
Les instructions javascript sont exécutées à la lecture
pour qu'une instruction soit correctement exécutée, elle doit faire référence à des objets qui existent.
Exemple où l'ordre est respecté
Ce paragraphe sera en rouge sur fond jaune
<p id='par1'>Ce paragraphe sera en rouge sur fond jaune </p>
<script type="text/javascript">
document.getElementById('par1').style.backgroundColor='yellow';
document.getElementById('par1').style.color='red';
</script>
Exemple où l'ordre n'est pas respecté
Ce paragraphe ne va pas changer de couleur
<script type="text/javascript">
document.getElementById('par2').style.backgroundColor='yellow';
document.getElementById('par2').style.color='red';
</script>
<p id='par2'>Ce paragraphe ne va pas changer de couleur </p>
En revanche, une fonction peut référencer un élément qui
n'existe pas encore. Ce qui importe, c'est qu'il existe quand la
fonction est appelée.
Ce paragraphe sera aussi en rouge sur fond jaune
<script type="text/javascript">
function changerCouleurPar3() {
document.getElementById('par3').style.backgroundColor='yellow';
document.getElementById('par3').style.color='red';
}
</script>
<p id='par3'>Ce paragraphe sera aussi en rouge sur fond jaune </p>
<script type="text/javascript">
changerCouleurPar3();
</script>
L'événement onload
événement associé au body:
<body onload="fonctionDeMiseEnplace()">
cette fonction est appelée quand le corps de la page a été
chargé, et que les objets DOM existent tous.
endroit normal pour placer tous les traitements qui doivent se faire quand la page a été chargée.