Les sélecteurs
Sélection par id
Comme pour tout élément du DOM, il est possible d'accéder à un form
ou un de ses
input
en lui donnant un id
, et donc en utilisant une méthode de sélection
"classique" du type getElementById
ou encore querySelector
.
Une fois l'élément récupéré, on peut accéder à sa valeur en lecture et/ou écriture.
<form id="user-infos-01" style="width: 300px "
action="http://web.gregory-bourguin.fr/teaching/php/requests/ajax/02_generateUserID.php"
method="post">
<div class="form-group">
<label for="firstname-01">Prénom</label>
<input type="text" class="form-control" name="firstname-01" id="firstname-01" value="Gregory">
</div>
<div class="form-group">
<label for="lastname-01">Nom</label>
<input type="text" class="form-control" name="firstname-01" id="lastname-01" value="Bourguin">
</div>
</form>
<hr>
<p class="console_output">
Valeur du champ au chargement : <span id="output-01"></span>
</p>
<script>
document.addEventListener('DOMContentLoaded', function (){
let fnameInput = document.getElementById("firstname-01")
let output = document.getElementById("output-01")
output.innerText = fnameInput.value
})
</script>
Resultat
Valeur du champ au chargement :
Sélection par name
Une particularité des champs est qu'ils sont généralement désignés par un nom (name
).
Ce nom est utilisé au niveau du serveur (par exemple en php) pour littéralement "nommer" des données reçues.
La valeur de l'attribut name
peut (aussi) être utilisée en Javascript pour désigner un champ d'un formulaire.
<form id="user-infos-02" style="width: 300px"
action="http://web.gregory-bourguin.fr/teaching/php/requests/ajax/02_generateUserID.php"
method="post">
<div class="form-group">
<label for="firstname">Prénom</label>
<input type="text" class="form-control" name="firstname" id="firstname" value="Gregory">
</div>
<div class="form-group">
<label for="lastname">Nom</label>
<input type="text" class="form-control" name="lastname" id="lastname" value="Bourguin">
</div>
</form>
<hr>
<p class="console_output">
Valeur du champ au chargement : <span id="output-02"></span>
</p>
<script>
document.addEventListener('DOMContentLoaded', function (){
// récupération du formulaire
let form = document.getElementById("user-infos-02")
// accès grâce au nom du champ
let fnameInput = form.firstname
let output = document.getElementById("output-02")
output.innerText = fnameInput.value
})
</script>
Resultat
Valeur du champ au chargement :
NB: en Javascript les éléments DOM de type form
possèdent aussi tous un attribut nommé
elements
qui est un tableau contenant tous les champs du formulaire.
Dans l'exemple précédent, on aurait pu accéder au champ grâce à :
form.elements[0]
Évènements
Les formulaires et les champs sont capables de générer un (ou des) évènement(s).
La gestion d'écouteurs est similaire à celle que nous avons vue précédemment :
il suffit de récupérer l'élément que l'on veut écouter (le formulaire ou un de ses champs),
et d'indiquer ce qu'on veut faire au gestionnaire d'évènements ciblé.
Évènements de champ
Les champs de formulaires proposent des gestionnaires d'évènements qui permettent de réagir lors
de leur modification par l'utilisateur.
Les moyens d'interactions avec ces champs diffèrent selon leur type (ex. taper du texte, cocher une case, ...).
En conséquence, les gestionnaires d'évènements disponibles peuvent aussi différer :
Pour text
, textarea
, checkbox
, radio
, select
:
-
change
: déclenché lors d'une modification "validée" (quand le champ perd
le focus).
-
input
: déclenché dès qu'une modification est apportée.
Spécifiques à text
et textarea
:
-
keydown
: déclenché quand une touche est enfoncée.
-
keyup
: déclenché quand une touche est relâchée.
-
keypress
: déclenché quand touche produisant un caractère est pressée.
Ci-dessous quelques exemples...
Exemple text
& keyup
<form id="user-infos-04" style="width: 300px">
<div class="form-group">
<label for="pseudo">Pseudo</label>
<input type="text" class="form-control" name="pseudo" id="pseudo">
</div>
</form>
<hr>
<div></div>
<script>
document.addEventListener('DOMContentLoaded', function (){
let form = document.getElementById("user-infos-04")
let log = form.nextElementSibling.nextElementSibling // form -> hr -> div
form.pseudo.addEventListener('keyup', function (event){
log.innerText = form.pseudo.value // ou this.value
})
})
</script>
Exemple select
& change
<form id="user-infos-06" style="width: 300px">
<label>Moyen de paiement</label>
<select name="pay" class="form-control">
<option selected disabled>Choisissez...</option>
<option value="carte">Carte</option>
<option value="paypal">Paypal</option>
</select>
</form>
<hr>
<div></div>
<script>
document.addEventListener('DOMContentLoaded', function (){
let form = document.getElementById("user-infos-06")
let log = form.nextElementSibling.nextElementSibling // form -> hr -> div
form.pay.addEventListener('change', function (event){
log.innerText = form.pay.value
})
})
</script>
Exemple radio
& change
<form id="user-infos-05" style="width: 300px">
<div class="form-check">
<input type="radio" class="form-check-input" name="sex" id="male" value="male">
<label class="form-check-label" for="male">Homme</label>
<input type="radio" class="form-check-input" name="sex" id="female" value="female">
<label class="form-check-label" for="female">Femme</label>
</div>
</form>
<hr>
<div></div>
<script>
document.addEventListener('DOMContentLoaded', function (){
let form = document.getElementById("user-infos-05")
let log = form.nextElementSibling.nextElementSibling // form -> hr -> div
form.sex.forEach(radio => radio.addEventListener('change', function (event){
log.innerText = form.sex.value
}))
})
</script>
Exemple checkbox
& change
<form id="user-infos-07" style="width: 300px">
<div class="form-check">
<input type="checkbox" class="form-check-input" name="share" id="share" value="share">
<label class="form-check-label" for="share">Partager les données</label>
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="mailing" id="mailing" value="mailing">
<label class="form-check-label" for="mailing">Recevoir les emails</label>
</div>
</form>
<hr>
<div></div>
<script>
let log = undefined
let checkboxes = undefined
document.addEventListener('DOMContentLoaded', function (){
let form = document.getElementById("user-infos-07")
log = form.nextElementSibling.nextElementSibling // form -> hr -> div
// récupération de toutes les checkbox du formulaire
checkboxes = form.querySelectorAll("input[type='checkbox']")
// ajout des écouteurs
checkboxes.forEach(check => check.addEventListener('change', function (event){
displayCheckboxes()
}))
})
/**
* Affiche l'état de toutes les checkboxes
*/
function displayCheckboxes(){
log.innerHTML = ""
checkboxes.forEach(cb => {
let div = log.appendChild(document.createElement("div"))
div.innerHTML = cb.value + " : " + cb.checked
})
}
</script>
Évènements de formulaire
Les formulaires proposent 2 principaux gestionnaires d'évènements :
-
sumbit
: déclenché lorsque le formulaire est soumis.
-
reset
: déclenché lorsque le formulaire est réinitialisé.
Le gestionnaire submit
est particulièrement intéressant car il permet de conditionner l'envoi
effectif des données (la soumission) du formulaire au serveur.
Une approche classique est en effet de vérifier en Javascript (donc avant envoi) que les valeurs des champs
entrées par l'utilisateur correspondent à la forme attendue par le serveur. Une telle vérification
permet d'alléger le fonctionnement du site (éviter les échanges/rechargements superflus entre
le navigateur et le serveur du fait d'erreurs de saisie),
et accessoirement d'alléger la charge du serveur (qui n'a plus qu'à procéder aux NECESSAIRES
vérifications finales).
NB: Valider en Javascript n'empêche pas la vérification des données par le serveur !
Par exemple, dans un formulaire demandant un mot de passe, Javascript pourra vérifier
si celui-ci possède au moins 3 caractères (etc.), mais ce n'est en aucun
cas Javascript qui va vérifier le mot de passe de l'utilisateur : pour mémoire, tout ce qui est
écrit en Javascript est lisible dans le navigateur -> on ne lui enverra donc en aucun cas la liste
des mots de passe possibles !!!
Exemple de vérification simple
L'exemple suivant propose un formulaire de login/password.
L'action
indiquée est un script php très simple qui :
-
Renvoie un message (html) de bienvenue lorsque le login n'est pas vide et le mot de passe est correct.
-
Renvoie un message (html) d'erreur lorsque le login est vide et/ou le mot de passe est erroné.
NB: ce script php est un "fake" -> le mot de passe attendu est toujours 'mdp'.
Le code ci-dessous présente une version
sans vérification en Javascript :
Le formulaire SANS vérification Javascript
<form style="width: 300px"
action="http://www.web.gregory-bourguin.fr/teaching/php/requests/ajax/03_fakeLogin.php"
method="post"
target="_blank">
<div class="form-group">
<label for="login-sans-verif">Login</label>
<input type="text" class="form-control" name="login" id="login-sans-verif">
</div>
<div class="form-group">
<label for="password-sans-verif">Mot de passe</label>
<input type="password" class="form-control" name="password" id="password-sans-verif">
</div>
<button type="submit" class="btn btn-primary">Envoyer</button>
<button type="reset" class="btn btn-secondary">Reset</button>
</form>
Formulaire SANS vérification Javascript
On ajoute maintenant un (Java)script de vérification qui :
-
empêche l'envoi tant que le nom est vide et/ou le mot de passe n'a pas au moins 3 caractères
-
affiche un message en cas d'erreur
Le formulaire AVEC vérification Javascript
<form id="user-infos-verif" style="width: 300px"
action="http://www.web.gregory-bourguin.fr/teaching/php/requests/ajax/03_fakeLogin.php"
method="post"
target="_blank">
<div class="form-group">
<label for="login">Login</label>
<input type="text" class="form-control" name="login" id="login">
</div>
<div class="form-group">
<label for="password">Mot de passe</label>
<input type="password" class="form-control" name="password" id="password">
</div>
<button type="submit" class="btn btn-primary">Envoyer</button>
<button type="reset" class="btn btn-secondary">Reset</button>
</form>
<br>
<div id="message" style="color: red"></div>
<script>
const PWD_MIN_LEN = 3
document.addEventListener('DOMContentLoaded', function (){
// récupération de la zone de messages
let message = document.getElementById("message")
// récupération du formulaire
let form = document.getElementById("user-infos-verif")
// enregistrement dans le gestionnaire d'évènements 'submit'
form.addEventListener('submit', function (event){
// on bloque le comportement par défaut (l'envoi automatique)
event.preventDefault()
// on procède aux vérifications
if(form.login.value == ""){
message.innerHTML = "Le <b>login</b> ne doit pas être vide !"
}else if(form.password.value.length < PWD_MIN_LEN){
message.innerHTML = "Le <b>mot de passe</b> doit avoir au moins " + PWD_MIN_LEN + " caractères !"
}else{
// les champs sont ok : on peut soumettre le formulaire
form.submit()
message.innerHTML = ""
}
})
// ... pour le fun, on déclenche une alerte lors d'un reset
form.addEventListener('reset', function (event){
window.alert("Réinitialisation du formulaire")
})
})
</script>
Formulaire AVEC vérification Javascript
Dans cet exemple, lorsque le formulaire a bien été vérifié, il est soumis par Javascript grâce
à l'appel form.submit()
. Ce type d'envoi des données au serveur correspond à une soumission
"classique" de formulaire, i.e comme si on n'avait pas fait appel à Javascript.
Il faut cependant noter qu'après la vérification (en Javascript),
on aurait tout à fait aussi pu remplacer cet appel à .submit()
par une requête avec
XMLHttpRequest
ou
fetch,
et ainsi récupérer la réponse du serveur pour l'intégrer dynamiquement à la page en cours de visualisation.
TP 05
Recréez la page ci-dessous en faisant attention aux détails aussi bien visuels que fonctionnels.
Informations à prendre en compte :
-
Le select affiche les noms des pays, mais la
value
associée est en réalité le code d'appel correspondant
(32 pour la Belgique, 33 pour la france).
-
Vous remarquerez que lors d'une saisie, la partie "pré-visualisation" sous forme de carte de visite
reformate les données.
En particulier, la 1ere lettre du prénom est toujours en majuscule,
le reste en minuscules, et le nom est quant à lui complètement en majuscules.
Vous pourrez utiliser les méthodes Javascript
toUpperCase()
et
toLowerCase()
.
-
Pour récupérer les prénom et nom(s) à partir du nom complet entré par l'utilisateur,
sachez que la méthode Javascript
split(...)
permet découper une string en un tableau de
mots.
La méthode
join(...)
permet à l'inverse de
reconstituer une string à partir d'un tableau de string.
-
La méthode Javascript
trim()
permet de "nettoyer" une string en enlevant les espaces
qui éventuellement l'entourent.
-
L'image (le smiley) est un
Bootstrap Icon.
-
L'
action
liée à ce formulaire est un script php dont l'adresse est :
http://www.web.gregory-bourguin.fr/teaching/php/requests/ajax/00_test_REQ.php
.
NB: Ce script ne fait que renvoyer la liste des données qu'il a lui même reçues.
-
La soumission du formulaire lance une vérification qui, en cas d'erreur, colorie le(s) champ(s)
incriminé(s), et affiche un message sous le formulaire.
-
La vérification du Téléphone (ne doit contenir que des chiffres) peut être réalisée grâce à
RegExp
.
-
Quand il n'y a pas d'erreur de remplissage, le formulaire n'est pas soumis "classiquement" :
une requête
fetch
est lancée, et le résultat de l'action
est injecté dans
la page en cours.
-
Tout est bien "nettoyé" en cas de correction d'erreur/reset/validation...
Upload Preview
Les formulaires peuvent aussi servir à uploader des fichiers vers le serveur.
Nous verrons dans un autre cours comment gérer cet
upload en PHP
.
Javascript et le DOM peuvent servir à offrir à l'utilisateur d'un formulaire une prévisualisation
du fichier qui va être uploadé (donc avant envoi/soumission du formulaire).
Le code ci-dessous donne un exemple de prévisualisation d'un fichier sélectionné par
l'utilisateur dans un formulaire d'upload : l'évènement change
est déclenché
lorsqu'un fichier a été sélectionné dans l'input
; un
FileReader
est utilisé pour lire le fichier et, quand le résultat est prêt (evènement onload
du FileReader
),
le résultat est utilisé en tant que src
d'une balise img
.
NB : puisqu'on utilise le résultat dans une balise img
, il faut que le fichier
sélectionné soit bien une image, sinon on ne voit rien...
Prévilusalisation de fichier à uploader
<style>
.form-label{
height: 200px;
display: flex ;
justify-content: center
}
#preview-image{
object-fit: contain;
}
</style>
<form id="file-upload-form" action="" method="post" enctype="multipart/form-data">
<div class="mb-3">
<div class="card" id="preview">
<label for="fileInput" class="form-label" style="display: flex ; justify-content: center">
<img id="preview-image" src=""/>
</label>
</div>
<input class="form-control"
type="file" id="fileInput" name="fileInput"
accept="image/png, image/gif, image/jpeg">
</div>
<div class="mb-3">
<button id="submit-button" type="submit" class="btn btn-primary" style="width: 100%" disabled>Envoyer</button>
</div>
</form>
<script>
document.addEventListener('DOMContentLoaded', ()=>{
const submitButton = document.getElementById("submit-button") ;
const preview = document.getElementById("preview-image") ;
const reader = new FileReader() ;
reader.onload = (e)=>{
preview.src = reader.result ;
}
const fileInput = document.getElementById("fileInput") ;
fileInput.addEventListener('change', ()=>{
let file = fileInput.files[0] ;
if(file && file.type.split('/')[0] === "image"){
reader.readAsDataURL(fileInput.files[0])
submitButton.disabled = false ;
}else{
submitButton.disabled = true ;
preview.src = "" ;
}
})
})
</script>
Previsuaisation de fichier à uploader
(NB: la prévisualisation ne fonctionne ici qu'avec un fichier image...)