« Tutoriel JavaScript côté client » : différence entre les versions

De EduTech Wiki
Aller à la navigation Aller à la recherche
 
(75 versions intermédiaires par 4 utilisateurs non affichées)
Ligne 1 : Ligne 1 :
{{tutoriel
{{tutoriel
|fait_partie_du_cours=JavaScript
|fait_partie_du_cours=Initiation à la pensée computationnelle avec JavaScript
|fait_partie_du_module=Références JavaScript
|module_précédant=JavaScript dans d'autres environnements
|pas_afficher_sous-page=Non
|pas_afficher_sous-page=Non
|page_precedente=Tutoriel JavaScript de base
|page_precedente=Tutoriel JavaScript de base
|page_suivante=JQuery
|page_suivante=JSON
|statut=à améliorer
|statut=à finaliser
|difficulté=intermédiaire
|voir_aussi=Interactivité avec JavaScript
|pages_prérequises=JavaScript, Tutoriel JavaScript de base
|cat tutoriels=JavaScript
|voir_aussi=JQuery
}}
}}
==Introduction==
==Introduction==
Ligne 14 : Ligne 15 :


* [[Tutoriel JavaScript de base]]
* [[Tutoriel JavaScript de base]]
=== Conseil de lecture ===
Cette page présente une grande quantité d'information en relativement peu d'espace. Elle explique principalement les fonctionnalités, mais sans un objectif bien spécifique, ce qui peut décourager surtout les novices. Nous conseillons de lire d'abord la section '''JavaScript et le navigateur web''' et par la suite d'utiliser cette page comme '''référence croisée''' avec la page
* {{Goblock|[[Interactivité avec JavaScript]] }}
qui propose l'explication étape par étape de quelques exemples.


===Rappel de la structure d'une page web===
===Rappel de la structure d'une page web===
Ligne 33 : Ligne 42 :
* [https://developer.chrome.com/devtools Google Chrome Developer Tools] : outils de développement et débug du navigateur Google Chrome
* [https://developer.chrome.com/devtools Google Chrome Developer Tools] : outils de développement et débug du navigateur Google Chrome
* [https://developer.mozilla.org/en-US/docs/Tools Firefox Developer Tools] : outils de développement et débug du navigateur Firefox
* [https://developer.mozilla.org/en-US/docs/Tools Firefox Developer Tools] : outils de développement et débug du navigateur Firefox
===Console JavaScript===
La Console JavaScript (déjà introduite dans le [[Tutoriel JavaScript de base]]) devient encore plus utile pour JavaScript côté client, car elle peut non seulement interpréter le langage de base, mais également avoir accès aux éléments de l'environnement, c'est-à-dire le navigateur web. Nous rappelons que vous pouvez accéder à la Console des manières suivantes :
* Internet Explorer : Menu Outils > Outils de développement (ou F12)
* Firefox : F12 ou plus de fonctionnalités avec le [https://developer.mozilla.org/en-US/docs/Tools/Scratchpad Scratchpad] (SHIFT-F4).
* Chrome : Menu Outils > Console JavaScript (ou F12)
* Safari : D'abord dans les Options > Avancées cocher la case "Afficher le menu Développement dans la barre des menus", puis CTRL+Alt+I ou CTRL+Alt+C
* Opera: Menu Page > Outils de Développement > Opera Dragonfly (ou CTRL+Shift+I)
[[Fichier:JavaScript tutoriel base console error.jpg|thumb|800px|none|Console des erreurs en Google Chrome]]
Par exemple si vous tapez <code>window.navigator</code> vous pouvez voir quelques informations sur votre navigateur.


==JavaScript et le navigateur web==
==JavaScript et le navigateur web==
Ligne 39 : Ligne 61 :


# '''L'inclusion de code JavaScript dans des pages HTML''' ;
# '''L'inclusion de code JavaScript dans des pages HTML''' ;
# '''L'existance d'un objet global <code>window</code> qui permet à JavaScript d'interagir avec le navigateur web.'''
# '''L'existence d'un objet global <code>window</code> qui permet à JavaScript d'interagir avec le navigateur web.'''


===Utilisation du code JavaScript dans une page HTML===
===Utilisation du code JavaScript dans une page HTML===
Ligne 46 : Ligne 68 :
# '''Fichier externe''' : le code est écrit dans un fichier avec extension .js
# '''Fichier externe''' : le code est écrit dans un fichier avec extension .js
# '''Code "inline"''' : le code est écrit directement dans la page web elle-même
# '''Code "inline"''' : le code est écrit directement dans la page web elle-même
# '''Attribut des balises (déconseillé)''' : le code est écrit dans des attributs des balises des éléments HTML de la page. Cette option, utilisée souvent dans le passé, est aujourd'hui fortement déconseillée et ne sera par conséquent pas illustrée dans ce tutoriel.
# '''Attribut des balises''' : le code est écrit dans des attributs des balises des éléments HTML de la page. Cette option, utilisée souvent dans le passé, est aujourd'hui plutôt déconseillée.


Les trois différents manières peuvent être utilisées en même temps, il n'est pas nécessaire de choisir une seule manière pour toute la page.  
Les trois différentes manières peuvent être utilisées en même temps, il n'est pas nécessaire de choisir une seule manière pour toute la page.  


====Fichier externe====
====Fichier externe====
Ligne 57 : Ligne 79 :
  <script src="path/to/file.js"></script>
  <script src="path/to/file.js"></script>


Veuillez noter que la balise <code>script</code> doit être fermée avec la balise de clôture même si à l'intérieur d'une balise avec attribut src il ne faut pas insérer de code.  
'''Veuillez noter que la balise <code>script</code> doit être fermée avec la balise de clôture même si à l'intérieur d'une balise avec attribut src il ne faut pas insérer de code.'''


Le lien au fichier .js suit les règles des liens hypertextuels à tout autre type de fichier, y compris les liens à d'autres pages HTML. On peut donc avoir un lien :
Le lien au fichier .js suit les règles des liens hypertextuels à tout autre type de fichier, y compris les liens à d'autres pages HTML. On peut donc avoir un lien :


* Absolu : le lien présente tout le URL du fichier, e.g. <code><script src="http://tecfa.unige.ch/path/to/file.js"></script></code> (ce fichier n'existe pas)
* Absolu : le lien présente tout le URL du fichier,  
* Relatif à la racine du domaine, e.g. <code><script src="/path/to/file.js"></script></code>. Veuillez noter le / initial qui détermine la racine du domaine. Dans ce cas la page HTML et le fichier JS doivent se trouver sur le même domaine (e.g. http://tecfa.unige.ch)
*: E.g. <code><script src="http://tecfa.unige.ch/path/to/file.js"></script></code> (ce fichier n'existe pas)
* Relatif à la position du fichier HTML, e.g. <code><script src="../path/to/js"></source></code>.
* Relatif à la racine du domaine
*: E.g. <code><script src="/path/to/file.js"></script></code>. Veuillez noter le / initial qui détermine la racine du domaine. Dans ce cas la page HTML et le fichier JS doivent se trouver sur le même domaine (e.g. http://tecfa.unige.ch)
* Relatif à la position du fichier HTML
*: E.g. <code><nowiki><script src="../path/to/js"></source></nowiki></code>.


Les positionnement relatifs utilisent une notation qui combine un <code>.</code> ou deux <code>..</code> points et un slash <code>/</code> :
Les positionnements relatifs utilisent une notation qui combine un <code>.</code> ou deux <code>..</code> points et un slash <code>/</code> :


* <code><script src="./file.js"></script></code> : le fichier file.js se trouve dans la même position (i.e. même dossier sur le serveur) de la page HTML
* <code><script src="./file.js"></script></code> : le fichier file.js se trouve dans la même position (i.e. même dossier sur le serveur) de la page HTML
Ligne 80 : Ligne 105 :
On utilise des fichiers externes souvent dans ces conditions :
On utilise des fichiers externes souvent dans ces conditions :


* Le même fichier contient du code qui est utilisé dans plusieurs pages d'un site, ce qui évite la nécessité de l'écrire dans toutes les pages. De cette manière, une modification au code doit se faire à un seul endroit et sera automatiquement activé dans toutes les pages.
* Le même fichier contient du code qui est utilisé dans plusieurs pages d'un site, ce qui évite la nécessité de l'écrire dans toutes les pages. De cette manière, une modification au code doit se faire à un seul endroit et sera automatiquement activée dans toutes les pages.
* Le fichier est une bibliothèque JavaScript  
* Le fichier est une [[Bibliothèques JavaScript | bibliothèque JavaScript]]
* Il y a beaucoup de code écrit
* Il y a beaucoup de code écrit


Ligne 100 : Ligne 125 :
* Le code sert à configurer des options ou initialiser une bibliothèque JavaScript
* Le code sert à configurer des options ou initialiser une bibliothèque JavaScript


====Placement de la balise script====
==== Attributs des balises HTML ====
Un élément auquel il faut faire attention est le placement de la balise <code>script</code> dans la page HTML. Il faut en effet tenir compte de la manière progressive de charger une page des navigateurs web. Avec le code JavaScript on fait souvent référence à des éléments du DOM (i.e. des balises HTML contenu dans la page). Il faut faire attention dans ces cas à ce que cet élément soit déjà disponible au navigateur. Un exemple illustre cette problématique....


Nous allons récupérer le texte d'un paragraphe avec id="mon-texte" avec la fonction <code>document.getElementById("mon-texte").innerHTML</code> ; et ensuite nous utiliserons la fonction <code>document.write()</code> pour écrire ce contenu. En d'autres termes, le comportement attendu de la page est d'obtenir deux fois exactement le même texte. Les deux exemples du code suivant sont exactement les mêmes, mais dans un cas, la balise <code>script</code> est positionnée avant le paragraphe, et dans l'autre cas après.
Pour placer du JavaScript dans les attributs HTML il faut utiliser les attributs qui se réfèrent aux événements JavaScript (voir plus bas), comme par exemple l'attribut <code>onclick="..."</code> :


<syntaxhighlight lang="HTML5">
<source lang="HTML5">
<!doctype html>
<button onclick="alert('J'ai cliqué sur le bouton');">Ouvrir une alerte</button>
<html>
</source>
<head>
    <meta charset="UTF-8">
    <title>Untitled Document</title>
</head>
<body>
<script>
var texte = document.getElementById("mon-texte").innerHTML;
document.write(texte);
</script>
<p id="mon-texte">Bonjour!</p>


</body>
Cette manière d'ajouter du JavaScript est plutôt déconseillée, mais reste fonctionnelle surtout pour des néophytes.
</html>
</syntaxhighlight>


Si le code est avant le paragraphe, le script n'a pas accès à l'élément du DOM qui correspond au paragraphe. Donc aucun texte ne sera écrit par la fonction <code>write()</code>.
====Placement de la balise script====
Un élément auquel il faut faire attention est le placement de la balise <code>script</code> dans la page HTML. Il faut en effet tenir compte de la manière progressive de charger une page des navigateurs web. Avec le code JavaScript on fait souvent référence à des éléments du DOM (i.e. des balises HTML contenues dans la page). Il faut faire attention dans ces cas à ce que cet élément soit déjà disponible au navigateur.
 
Même s'il existe des fonctions pour déclencher le code seulement une fois que toute la structure du DOM a été chargée dans le navigateur (e.g. window.onload), il est une bonne pratique d'inclure les balises <code>script</code> juste avant la balise de clôture <code>/body</code> :


<source lang="HTML5">
<source lang="HTML5">
Ligne 133 : Ligne 148 :
</head>
</head>
<body>
<body>
<p id="mon-texte">Bonjour!</p>
 
<script>
  <script>
var texte = document.getElementById("mon-texte").innerHTML;
  //Mon code est mieux ici!
document.write(texte);
  </script>
</script>
</body>
</body>
</html>
</html>
</source>
</source>


Au contraire, si le code est placé après le paragraphe, son contenu sera réécrit par le script et apparaîtra donc à l'écran.
On peut insérer plusieurs scripts, l'un après l'autre, et même combiner les fichiers externes et les scripts inline :
 
Même s'il existe des fonctions pour déclencher le code seulement une fois que toute la structure du DOM a été chargée dans le navigateur (e.g. window.onload), il est une bonne pratique d'inclure les balises <code>script</code> juste avant la balise de clôture <code>/body</code> :


<source lang="HTML5">
<source lang="HTML5">
Ligne 154 : Ligne 166 :
</head>
</head>
<body>
<body>
  <!-- HTML de la page -->


<script>
  <!-- Les scripts vont ici -->
//Mon code est mieux ici!
  <script src="path/to/external/file.js"></script>
</script>
  <script src="another/external.js"></script>
  <script>
  //Du code inline ici
  </script>
</body>
</body>
</html>
</html>
Ligne 165 : Ligne 181 :
JavaScript dépend de l'environnement dans lequel il est exécuté à la fois pour afficher les résultats des expressions (i.e. le output), mais également pour recevoir des inputs. Dans JavaScript côté client, cet environnement est représenté par le navigateur web et la communication I/O entre JavaScript et le navigateur web se fait à travers l'objet global <code>window</code>. Plus concrètement cela signifie que :
JavaScript dépend de l'environnement dans lequel il est exécuté à la fois pour afficher les résultats des expressions (i.e. le output), mais également pour recevoir des inputs. Dans JavaScript côté client, cet environnement est représenté par le navigateur web et la communication I/O entre JavaScript et le navigateur web se fait à travers l'objet global <code>window</code>. Plus concrètement cela signifie que :


# JavaScript peut "intercepter" tous les événements qui concerne la fenêtre du navigateur comme par exemple les clicks, les changements d'URL, le scolling de la page, etc.
# JavaScript peut "intercepter" tous les événements qui concernent la fenêtre du navigateur comme par exemple les clicks, les changements d'URL, le scolling de la page, etc.
# JavaScript peut modifier certaines propriétés de la fenêtre, y compris son contenu.
# JavaScript peut modifier certaines propriétés de la fenêtre, y compris son contenu.


Les deux opérations sont possible justement grâce à l'objet global <code>window</code> qui, en tant qu'objet, possède des propriétés et des méthodes. Comprendre l'objet global window peut contribuer à bien comprendre le langage, car en réalité tout le code source écrit en JavaScript côté client peut se diviser en deux catégories :
Les deux opérations sont possibles justement grâce à l'objet global <code>window</code> qui, en tant qu'objet, possède des propriétés et des méthodes. Comprendre l'objet global window peut contribuer à bien comprendre le langage, car en réalité tout le code source écrit en JavaScript côté client peut se diviser en deux catégories :


# Le code qui exploite les propriétés et méthodes mises à disposition par l'objet window
# Le code qui exploite les propriétés et méthodes mises à disposition par l'objet window
Ligne 174 : Ligne 190 :


En effet, lorsqu'on déclare une variable, ce que nous sommes en train de faire c'est tout simplement d'ajouter une propriété avec le nom de la variable à l'objet global window. En d'autres termes, les deux lignes de code suivantes sont équivalentes :
En effet, lorsqu'on déclare une variable, ce que nous sommes en train de faire c'est tout simplement d'ajouter une propriété avec le nom de la variable à l'objet global window. En d'autres termes, les deux lignes de code suivantes sont équivalentes :
* <code>var cours = "STIC I"</code>;
* <code>window.cours = "STIC I"</code>;
Vous pouvez tester l'équivalence de cette manière :


  var cours = "STIC I";
  var cours = "STIC I";
  window.cours = "STIC I";
  cours === window.cours; //--> true


Le même principe s'applique aux fonctions :
Le même principe s'applique aux fonctions :
Ligne 184 : Ligne 205 :
  }
  }
  addTwo(4); // -> 6
  addTwo(4); // -> 6
  window.addTwo(7); --> 9
  window.addTwo(7); //--> 9


En raison du fait que tout appartient à l'objet window, on peut éviter de le déclarer à chaque fois. Le même principe s'applique aux propriétés et méthodes déjà disponibles. Par example la fonction <code>alert()</code> - qui affiche une boîte popup avec un message - est en réalité la méthode <code>window.alert()</code>.
En raison du fait que tout appartient à l'objet window, on peut éviter de le déclarer à chaque fois. Le même principe s'applique aux propriétés et méthodes déjà disponibles. Par exemple la fonction <code>alert()</code> - qui affiche une boîte popup avec un message - est en réalité la méthode <code>window.alert()</code>.


À travers JavaScript il est également disponible de changer des propriétés de l'objet global window, ce qui se traduit par des comportements spécifiquent qui modifient le contenu du navigateur. Vous pouvez par exemple essayer d'écrire ce code dans la Console de votre navigateur web pour être rédirigés à la page d'accueil de ce wiki :
À travers JavaScript il est également possible de changer des propriétés de l'objet global window, ce qui se traduit par des comportements spécifiques qui modifient le contenu du navigateur. Vous pouvez par exemple essayer d'écrire ce code dans la Console de votre navigateur web pour être redirigé à la page d'accueil de ce wiki :


  window.location = "http://edutechwiki.unige.ch/fr/Accueil";
  window.location = "http://edutechwiki.unige.ch/fr/Accueil";
Ligne 199 : Ligne 220 :
[[Fichier:JavaScript CC document.png|cadre|néant|L'objet document représente le DOM de la page. ]]
[[Fichier:JavaScript CC document.png|cadre|néant|L'objet document représente le DOM de la page. ]]


Vous pouvez par la suite essayer <code>document.head</code> et <code>document.body</code> pour obtenir respectivement le contenu de la balise <code>head</code> (informations) et de la balise <code>body</code> (contenu) d'une page.  
Vous pouvez par la suite essayer <code>document.head</code> et <code>document.body</code> pour obtenir respectivement le contenu de la balise <code>head</code> (informations) et de la balise <code>body</code> (contenu) d'une page. Pour sélectionner ensuite des éléments plus spécifiques (e.g. un titre, une image, etc.), il faudra utiliser d'autres méthodes.


* Voir "JavaScript et le DOM" plus bas dans la page
* Voir "JavaScript et le DOM" plus bas dans la page
Ligne 212 : Ligne 233 :
# Les fenêtres de saisies.
# Les fenêtres de saisies.


Vous pouvez structurer votre message dans vos boites en insérant '\n' à la fin de vos phrases. Cela permettra de revenir à la ligne.
Veuillez noter que ces éléments sont mis à disposition par le navigateur web et donc le contrôle que le développeur a sur leur fonctionnement et leur apparence est très limité. De plus, ils ne sont pas très pratique au niveau expérience utilisateur. En d'autres termes, il s'agit d'outils pratiques pour explorer quelques événements/intérations de base, mais par la suite il faudrait les remplacer par des éléments HTML "customizés" (e.g. des fenêtres modales, des formulaires, etc.).
 
alert ('Première ligne.\n Deuxième ligne.')
 
[[Fichier:Alert.jpg|thumb|right|300px]]


=== Les boites d'alerte ===
=== Les boites d'alerte ===
   
   
Elles affichent un message. Elles servent généralement à donner un message à un utilisateur ou à indiquer un message d'erreur. La boîte d'alerte contient un bouton 'Ok'.
Elles affichent un message. Elles servent généralement à donner un message à un utilisateur ou à indiquer un message d'erreur. La boîte d'alerte contient un bouton 'Ok'.
[[Fichier:Alert.jpg|néant|right|600px]]


Il faut utiliser la fonction <code>alert()</code>, c'est-à-dire l'équivalent de <code>window.alert()</code>
Il faut utiliser la fonction <code>alert()</code>, c'est-à-dire l'équivalent de <code>window.alert()</code>


<source lang="JavaScript">
alert("Je suis une alerte!");
<html>
 
    <head>
Vous pouvez structurer votre message dans vos boites en insérant '\n' à la fin de vos phrases. Cela permettra de revenir à la ligne.
        <script type="text/javascript">
 
            function gagné()
alert ('Première ligne.\n Deuxième ligne.');
            {
                alert("Bravo vous avez trouvé");
            }
        </script>
    </head>
    <body>
        <input type="button" onclick="gagné()" value="Trouver">
    </body>
</html>
</source>


[[Fichier:Confirm.jpg||thumb|right|300px|centré]]
La fonction alert() ne "return" aucune valeur (i.e. '''undefined''').


===Les boîtes de confirmation===
===Les boîtes de confirmation===
Ligne 246 : Ligne 255 :
La fonction <code>confirm()</code> affiche une boite de confirmation. L'utilisateur a alors le choix entre 'OK' et 'annuler'.
La fonction <code>confirm()</code> affiche une boite de confirmation. L'utilisateur a alors le choix entre 'OK' et 'annuler'.


<source lang="JavaScript">
[[Fichier:Confirm.jpg||thumb|néant|600px|centré]]
<html>
    <head>
        <script type="text/javascript">
            function confirmer()
            {
                var reponse=confirm("Continuer l'operation en cours ?");
                if (reponse==true)
                {
                    alert("Vous avez cliqué sur OK");
                }
                else
                {
                    alert("Vous avez cliqué sur Annuler");
                }
            }
        </script>
    </head>
    <body>
        <input type="button" onclick="confirmer()" value="Choix" />
    </body>
</html>


</source>
La fonction accepte un paramètre qui détermine le message affiché à l'intérieur de la boîte :


===Les fenêtres de saisie===
confirm("Voulez-vous continuer?");


Il est possible de créer une fenêtre pour saisir une valeur grâce à la fonction <code>prompt()</code>. La fonction prend deux paramètres : le premier est l'invitation à saisir du texte et le second propose un texte par défaut.
La fonction confirm() "return":


Après avoir entré une valeur, l'utilisateur peut cliquer sur 'ok' ou sur 'annuler.
* '''true''' si l'utilisateur clique sur OK
* '''false''' si l'utilisateur clique sur annuler  


'''Exemple''' : ici quand l'utilisateur clic sur 'Ok' la valeur saisie est indiqué dans la fenêtre d'alerte ensuite.
Vous pouvez donc l'utiliser pour simuler des structure de contrôle qui dépendent du choix des utilisateurs:


<source lang="JavaScript">
<source lang="JavaScript">
<html>
var continuer = confirm("Voulez-vous continuer?");
    <head>
 
        <script type="text/javascript">
if(continuer) {
            function saisir()
  console.log("L'utilisateur voudrait continuer...");
            {
} else {
                var reponse=prompt("Identification, veuillez saisir votre prenom","mon prenom");
  console.log("L'utilisateur ne veut pas continuer...");
                //si la réponse est non nul ou vide - donc l'utilisateur a appuyé sur ok
}
                if (reponse!=null && reponse!="")
                {
                    alert("Votre prenom est :"+reponse);
                }  
                //autre cas : si l'utilisateur clic sur 'Annuler'
                else {
                    alert("Operation interrompue")
                }
            }
        </script>
    </head>
    <body>
        <input type="button" onclick="saisir()" value="Saisir mon prenom" />
    </body>
</html>
</source>
</source>


[[Fichier:Prompt.jpeg|400px|centré]]
===Les fenêtres de saisie===


Il est possible de créer une fenêtre pour saisir une valeur grâce à la fonction <code>prompt()</code> et peut ensuite confirmer ou annuler son choix. La fonction prend deux paramètres : le premier est l'invitation à saisir du texte et le second propose un texte par défaut :


[[Fichier:Prompt2.jpeg|400px|centré]]
[[Fichier:Prompt.jpeg|600px|néant]]


===Les fonctions liées au temps===
Le code suivant demande à l'utilisateur de saisir son nom, sans donner une valeur préétablie :


Grâce à l'objet global window il est possibile d'exécuter du code en fonction du temps, plus spécifiquement :
prompt("Identification, veuillez saisir votre prénom", "");


* <code>setTimeout()</code> permet d'exécuter du code une seule fois après une période de temps définie ;
La fonction prompt() "return" :
* <code>setInterval()</code> permet d'exécuter du code à des intervalles reguliers de temps.


====setTimeout()====
* La '''valeur saisie''' lorsque l'utilisateur clique sur OK.
* '''false''' si la personne ne saisie aucune valeur ou si elle clique sur annuler


La syntaxe pour utiliser la fonction <code>setTimeout()</code> est la suivante :
Vous pouvez combiner prompt() et alert() pour créer une première interaction dans une page web :


  setTimeout(function,milliseconds, [param1,param2,...]);
  var name = prompt("Veuillez saisir votre nom", "");
alert("Bonjour " + name);


Les paramètres sont optionnels, tandis que la fonction à exécuter et le temps en milliseconds sont obligatoires. Voici un example qui affiche une boite d'alerte après 5 seconds (i.e. 5 * 1000 milliseconds) :
'''Attention''' : la valeur est toujours de type '''string''' même si la valeur saisie est un nombre! Essayez cet exemple :


  var afficherApres5seconds = setTimeout(function () { alert("Message"); }, 5000);
  var num = prompt("Choisissez un nombre à ajouter à 100 pour voir le résultat", "");
console.log(100 + num);


Il est également possibile de définir d'abord une fonction et ensuite passer son nom comme référence dans la fonction setTimeout() :
Vous pouvez noter que le résultat ne sera pas l'addition souhaitée. Si vous avez choisi 20, le message affiché sera 10020 parce que le 20 saisi est traité comme une suite de caractères et par conséquent le + est interprété comme une concaténation. Pour éviter ce problème, il faut spécifier que le résultat du prompt doit être traité comme un nombre, en utilisant par exemple la fonction <code>parseInt()</code> :
 
   
function alertMessage() {
  var num = prompt("Choisissez un nombre à ajouter à 100 pour voir le résultat", "");
  alert("Message");
console.log(100 + parseInt(num)); //On peut utiliser également Number(num)
}
var afficherApres5seconds = setTimeout(alertMessage, 5000);
 
Associer la fonction setTimeout() à une variable est utile si on veut annuler l'exécution de la fonction avant que la période de temps définie avec la notation :
 
clearTimeout(''variable'');
 
En ajoutant cette ligne de code à l'exemple précédent, la fonction alertMessage() ne sera pas déclenchée :
 
function alertMessage() {
  alert("Message");
}
var afficherApres5seconds = setTimeout(alertMessage, 5000);
clearTimeout(afficherApres5seconds);
 
====setInterval()====
La fonction <code>setInterval</code> est similaire à setTimeout() si ce n'est pour le fait que le code sera exécutée chaque X milliseconds. La syntaxe reste par contre la même :
 
setInterval(function,milliseconds, [param1,param2,...]);
 
Voici un exemple qui affiche dans la console un message chaque 3 seconds (sans arrêt si la page ne sera pas fermée ou après changement de URL) :
 
var chaque3seconds = setInterval(function () { console.log("...encore 3 seconds"); }, 3000);
 
Pour limiter les cycles on peut utiliser un conteur et utiliser la fonction <code>clearInterval</code> direcement à l'intérieur de la fonction invoquée par setInterval() :
 
  var count = 0;
  var cinqFois = setInterval(function () {
  count++;  
  console.log(count);
  if(count == 5) {
    clearInterval(cinqFois);
  }
}, 2000);


==JavaScript et le DOM==
==JavaScript et le DOM==
[[Fichier:DOM html exemple avec couleurs.png|400px|vignette|droite|Le [[Document Object Model]] (DOM) d'une page web.]]
Une des fonctionnalités les plus utilisées de JavaScript est sa capacité d'interagir dynamiquement avec le DOM, c'est-à-dire la structure hiérarchique des balises HTML d'une page web. C'est notamment grâce à la manipulation des éléments du DOM qui s'avèrent les interactions sur une page : apparition d'un message, déplacement d'un élément d'un endroit à un autre, changement de la taille d'une police, du couleur, etc.  
Une des fonctionnalités les plus utilisées de JavaScript est sa capacité d'interagir dynamiquement avec le DOM, c'est-à-dire la structure hiérarchique des balises HTML d'une page web. C'est notamment grâce à la manipulation des éléments du DOM qui s'avèrent les interactions sur une page : apparition d'un message, déplacement d'un élément d'un endroit à un autre, changement de la taille d'une police, du couleur, etc.  


Ligne 371 : Ligne 315 :


* Voir les [http://www.w3schools.com/jsref/dom_obj_document.asp références de l'objet Document]
* Voir les [http://www.w3schools.com/jsref/dom_obj_document.asp références de l'objet Document]
* Voir le [http://eloquentjavascript.net/13_dom.html chapitre 13] de Haverbeke (2015)


NB: La manipulation du DOM à travers JavaScript "de base" est un bon point de départ pour comprendre la logique, mais pour des applications plus poussées les développeurs utilisent souvent des bibliothèques qui simplifient la syntaxe ou facilitent certains opérations. La bibliothèque la plus utilisée dans ce sens est [[jQuery]].  
NB: La manipulation du DOM à travers JavaScript "de base" est un bon point de départ pour comprendre la logique, mais pour des applications plus poussées les développeurs utilisent souvent des [[bibliothèques JavaScript]] qui simplifient la syntaxe ou facilitent certains opérations. La bibliothèque la plus utilisée dans ce sens est [[jQuery]].  


===Manipulation des éléments du DOM===
===Manipulation des éléments du DOM===
Ligne 385 : Ligne 330 :


* <code>document.querySelector(''css selector'')</code>  : cette méthode accepte des identifiants plus complexes par rapports aux trois méthodes vues plus haut dans la page, mais elle est également plus flexible, car elle permet d'identifier les éléments grâce aux selecteurs [[CSS]]. Cette méthode identifie le premier élément qui respecte les critères du selecteur.
* <code>document.querySelector(''css selector'')</code>  : cette méthode accepte des identifiants plus complexes par rapports aux trois méthodes vues plus haut dans la page, mais elle est également plus flexible, car elle permet d'identifier les éléments grâce aux selecteurs [[CSS]]. Cette méthode identifie le premier élément qui respecte les critères du selecteur.
* <code>document.querySelectorAll(''css selector'')</code> : même principe, mais le résultat est un array avec tous les éléments qui respectent le critère de sélection.
* <code>document.querySelectorAll(''css selector'')</code> : même principe, mais le résultat est une liste de noeuds avec tous les éléments qui respectent le critère de sélection.


Voici quelques exemples d'utilisation :
Voici quelques exemples d'utilisation :
Ligne 395 : Ligne 340 :


  var monParagraphe = document.getElementById("monTexte");
  var monParagraphe = document.getElementById("monTexte");
  monTexte.querySelector("span").innerHTML = "Nouveau texte du span";
  monParagraphe.querySelector("span").innerHTML = "Nouveau texte du span";


Ce code identifie le premier élément span à l'intérieur du paragraphe avec id="monTexte" et change le contenu textuel.
Ce code identifie le premier élément span à l'intérieur du paragraphe avec id="monTexte" et change le contenu textuel.


====Modifier un élément====
<source lang="HTML5">
On peut modifier différentes caractéristiques d'un élément une fois identifié dans le document par exemple à travers ces propriétés :
<p id="monTexte">Voici un paragraphe avec du <span>texte dans un span</span></p>
</source>
 
====Récupérer/Modifier des caractéristiques d'un élément====
On peut récupérer ou modifier différentes caractéristiques d'un élément une fois identifié dans le document. Par exemple :
 
* <code>''element''.textContent</code> : se réfère au contenu textuel de l'élément sélectionné
* <code>''element''.innerHTML</code> : se réfère au contenu, y compirs les balises HTML d'éléments emboîtes, de la balise de l'élément sélectionné
* <code>''element''.''attribute''</code> : se réfère à un attribut spécifique de la balise de l'élément sélectionné
* <code>''element''.style.''property''</code> : se réfère à une propriété de style spécifique de la balise de l'élément sélectionné
 
Pour récupérer il suffit de spécifier la propriété à laquelle on s'intéresse, par exemple :
 
<source lang="JavaScript">
//Récupérer le contenu textuel d'un element avec id="my-element"
var myElementText = document.getElementById("my-element").textContent;
 
//Récupérer le contenu, y compirs les balises HTML, d'un élément avec id="my-element"
var myElementHTML = document.getElementById("my-element").innerHTML;
 
//Récupérer la valeur d'un attribut d'un element avec id="my-element", par exemple une image avec l'attribut title
var myImageTitle = document.getElementById("my-element").title;
 
//Récupérer la propriété de style font-size d'un element avec id="my-element"
var myElementFontSize = document.getElementById("my-element").style.fontSize;
//veuillez noter qu'on peut pas utiliser font-size mais il faut transformer en fontSize. Ceci s'applique à toute propriété qui utilise le -
</source>
 
Pour modifier il faut affecter la caractéristique à une nouvelle valeur à travers le symbole d'affectation, par exemple :
 
<source lang="JavaScript">
//Modifier le contenu textuel d'un element avec id="my-element"
document.getElementById("my-element").textContent = "Nouveau texte de l'élément!";
 
//Modifier le contenu, y compirs les balises HTML, d'un élément avec id="my-element"
document.getElementById("my-element").innerHTML = "<strong>Nouveau contenu de l'élément!</strong>";


* <code>''element''.innerHTML</code> : modifie le contenu de la balise de l'élément sélectionné
//Modifier la valeur d'un attribut d'un élément, par exemple la valeur src pour remplacer une image avec une autre
* <code>''element''.''attribute''</code> : modifie un attribut de la balise de l'élément sélectionné
document.getElementById("my-image").src = "./my/new/path/to/image.png";
* <code>''element''.style.''property''</code> : modifie les propriétés de style de la balise de l'élément sélectionné
 
//Modifier la valeur d'une propriété de style d'un élément, par exemple sa taille
document.getElementById("my-element").style.fontSize = '40px';
</source>
 
Veuillez faire attention que pour les modification textContent et innerHTML vous ne pouvez pas afficher votre nouveau contenu sur plusieurs lignes, en d'autres termes CE CODE N'EST PAS VALIDE :
 
<source lang="JavaScript">
//CODE NON VALIDE !!!
var hello = "Hello my dear User!";
document.getElementById("my-element").innerHTML = "<div>
                                                      <p>" + hello + "</p>
                                                  </div>";
</source>
 
Vous avez trois alternatives :
 
* Tout mettre sur une seule ligne, ce qui n'est parfois pas très pratique, surtout si vous voulez insérer des valeurs symboliques à l'intérieur :
 
<source lang="JavaScript">
var hello = "Hello my dear User!";
document.getElementById("my-element").innerHTML = "<div><p>" + hello + "</p></div>";
</source>
 
* Utiliser une concatenation += :
 
<source lang="JavaScript">
var hello = "Hello my dear User!";
document.getElementById("my-element").innerHTML = "<div>";
document.getElementById("my-element").innerHTML += "<p>";
document.getElementById("my-element").innerHTML += hello;
document.getElementById("my-element").innerHTML += "</p>"
document.getElementById("my-element").innerHTML += "</div>";
</source>
 
* Utiliser les littéraux de gabarits `` (backticks en anglais) et l'interpolation ${code} (fonctionnalité introduite en 2016), voir [https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Litt%C3%A9raux_gabarits ici] pour plus d'infos
 
<source lang="JavaScript">
var hello = "Hello my dear User!";
document.getElementById("my-element").innerHTML = `<div>
                                                      <p>${hello}</p>
                                                  </div>`;
</source>


====Ajouter ou supprimer un élément====
====Ajouter ou supprimer un élément====
Ligne 416 : Ligne 438 :
====Exemples de manipulation====
====Exemples de manipulation====


Dans la page suivante, 4 types de manipulation ont lieu lorsque la page a été chargée. L'expression <code>window.onload = function () { ....}</code> associe directement une fonction anonyme (sans nom) qui sera exécutée lorsque la page charge:
Dans la page suivante, 4 types de manipulation ont lieu lorsque la page a été chargée. Vous pouvez comparer le contenu attendu s'il n'y avait pas de manipulation JavaScript (i.e., la source HTML) avec le résultat final qui s'affiche à l'écran de l'utilisateur dans cette image :
 
[[Fichier:JavaScriptCC before after manipulation.png|800px|vignette|néant|Comparaison entre le résultat du simple code HTML et sa transformation avec le script JavaScript]]
 
Voici le code de la page entière :


<source lang="JavaScript">
<source lang="JavaScript">
Ligne 463 : Ligne 489 :
</source>
</source>


Les manipulations 1. et 2. ne nécessitent pas d'explication supplémentaire, tandis que la 3. et la 4. sont un peu plus complexes. Il faut considérer en effet que la méthode <code>getElementsByTagName()</code> renvoie un array d'éléments, c'est-à-dire un groupe d'éléments avec un indice (voir plus haut dans la page pour les Array). On identifie un élément d'un Array avec la notation nomDuArray[indice].
L'expression <code>window.onload = function () { ....}</code> associe directement une fonction anonyme (sans nom) qui est exécutée lorsque la page est chargée (voir plus bas la documentation sur les événements du DOM). Les manipulations 1. et 2. ne nécessitent pas d'explication supplémentaire, tandis que la 3. et la 4. sont un peu plus complexes. Il faut considérer en effet que la méthode <code>getElementsByTagName()</code> renvoie un liste de noeuds. Une liste de noeuds partage plusieurs caractéristiques avec un array, mais n'est pas exactement la même chose. Par exemple il n'est pas possible d'itérer une liste de noeuds avec la fonction <code>forEach()</code>, mais on peut le faire avec un cycle <code>for()</code> en utilisant la notation liste[index] comme indiqué dans l'exemple 4. Pour simplicité, nous nous référons par la suite à une liste de noeuds comme un array, mais tenez présente cette distinction (voir [http://www.w3schools.com/js/js_htmldom_nodelist.asp cette page sur w3school] pour plus de détails).


Dans la manipulation 3. nous avons identifié d'abord la balise body car il s'agit de la balise "parent" du paragraphe 3 qu'on veut supprimer. Bien qu'il n'y ait généralement qu'une seule balise body, la méthode <code>getElementsByTagName()</code> renvoie néanmoins un Array, dont le premier et seul élément est notre balise body. Vu que les indices des Array commence à 0, pour identifier notre élément body nous devons ajouter l'indice [0] à la méthode <code>getElementsByTagName("body")</code>.  
Dans la manipulation 3. nous avons identifié d'abord la balise body car il s'agit de la balise "parent" du paragraphe 3 qu'on veut supprimer. Bien qu'il n'y ait généralement qu'une seule balise body, la méthode <code>getElementsByTagName()</code> renvoie néanmoins une liste de noeuds (une sorte de array), dont le premier et seul élément est notre balise body. Vu que les indices des listes commencent à 0, pour identifier notre élément body nous devons ajouter l'indice [0] à la méthode <code>getElementsByTagName("body")</code>.  


Le même principe concerne la manipulation 4., dans laquelle le Array contient par contre plusieurs éléments. Pour changer chaque élément, il faut par conséquent un cycle. Nous avons créé ce cycle à l'aide de la fonction for et nous avons déclaré en tant que fonction de sortie la propriété length de l'Array lui-même. Cette propriété identifie le nombre d'éléments présents dans l'Array.  
Le même principe concerne la manipulation 4., dans laquelle la liste contient par contre plusieurs éléments. Pour changer chaque élément, il faut par conséquent un cycle. Nous avons créé ce cycle à l'aide de la fonction <code>for</code> et nous avons déclaré en tant que fonction de sortie la propriété <code>.length</code> de la liste. Cette propriété identifie le nombre d'éléments présents.  


[http://codepen.io/mafritz/pen/vNRVxw Tester cet exemple]
[http://codepen.io/mafritz/pen/vNRVxw Tester cet exemple]
Ce type de manipulation est plutôt complexe, raison pour laquelle des bibliothèques JavaScript (e.g. [[jQuery]]) offrent des méthodes plus faciles pour accéder aux éléments du DOM.


===Événements du DOM===
===Événements du DOM===
Ligne 477 : Ligne 501 :


* Voir les [http://www.w3schools.com/jsref/dom_obj_event.asp références des Événements du DOM]
* Voir les [http://www.w3schools.com/jsref/dom_obj_event.asp références des Événements du DOM]
* Voir le [http://eloquentjavascript.net/14_event.html chapitre 14] de Haverbeke (2015)


====L'événement onload====
====L'événement onload====
Ligne 485 : Ligne 510 :


  <script>
  <script>
  window.onload = alert("Je ne serais pas affiché");
  window.onload = alert("Je ne serai pas affiché");
  window.onload = alert("Je serais affiché");
  window.onload = alert("Je serai affiché");
  </script>
  </script>


Un autre problématique relative à cette fonction concerne le fait que l'événement onload s'avère lorsque tous les éléments du DOM ont bien été chargés, y compris images, feuilles de style, etc. Ceci peut parfois retarder le déclenchement de l'événement et par conséquent toutes les éléments interactifs associés à cet événements ne seront pas disponibles.
Un autre problématique relative à cette fonction concerne le fait que l'événement onload se déclenche lorsque tous les éléments du DOM ont bien été chargés, y compris images, feuilles de style, etc. Ceci peut parfois retarder le déclenchement de l'événement et par conséquent tous les éléments interactifs associés à cet événement ne seront pas disponibles.
 
L'événement <code>onload()</code> peut être également associé à d'autres objets de la page, comme par exemple les images, les iframes, etc.
 
Dans l'exemple suivant, la fonction <code>start()</code> sera exécutée dès que la page charge, ceci à cause de l'instruction <code>window.onload = start</code> qui associe à l'événement "onload" le nom d'une fonction qu'il faut exécuter. Rien de neuf. Par contre, la gestion du 2ème événement se fait différemment (voir événements liés à la souris plus bas).
 
<source lang="javascript">
<!DOCTYPE html>
<html>
 
<head>
    <title>Event handling</title>
    <script>
        window.onload = start; //Sans () !
 
        function start() {
            // put an event handler on the div box
            var my_para_button = document.getElementById("box");
            my_para_button.addEventListener("click", modifyText);
        }
 
        function modifyText() {
            // get the box
            var my_content = document.getElementById("content");
            my_content.innerHTML = "That was so good";
        }
    </script>
</head>
 
<body>
    <div id="box">
        <p style="background-color:yellow" id="content">CLICK ME !</p>
    </div>
</body>
 
</html>
</source>
 
Source: http://tecfa.unige.ch/guides/js/ex-intro/event-handler.html
 
La fonction start ajoute un gestionnaire d’événement au bouton my_para_button en utilisant la méthode addEventListener ("click", modifyText); . Le premier argument, "click", identifie le type d’événement, et le deuxième donne le nom de la fonction.
 
Veuillez noter que, grâce à l'ajoute du gestionnaire d'événement <code>window.onload</code>, le code JavaScript a pu être mis dans le <code>head</code> du document. En spécifiant cet événement, en effet, on force le navigateur à attendre que toute la page a été téléchargée et, par conséquent, les éléments HTML seront reconnus.
 
====Une alternative : DOMContentLoaded====
 
Il existe une alternative qui permet de déclencher du code JavaScript lorsque le DOM (et non pas tout le contenu de la fenêtre comme dans le cas de window.onload) a été chargé grâce à l'événement '''DOMContentLoaded''' (voir [https://developer.mozilla.org/fr/docs/Web/Events/DOMContentLoaded cette page sur MDN pour plus d'info]) :
 
<source lang="JavaScript">
document.addEventListener("DOMContentLoaded", function(event) {
    console.log("Le DOM est disponible!");
});
 
document.addEventListener("DOMContentLoaded", function(event) {
    console.log("Je peux utiliser cette méthode une deuxième fois dans le même code!");
});
</source>


L'événement <code>onload()</code> peut être également associé à d'autres éléments du DOM internes ou externes, comme par exemple les images, les iframes, etc.
Veuillez noter que pour utiliser cet événement il faut utiliser le gestionnaire d'événements <code>addEventListener()</code>. Cette méthode de l'objet DOM se différencie de window.onload() également par le fait qu'on peut déclarer deux (ou plusieurs fois) cet listener dans des endroits différents du code et les deux événements seront considérés, à moins qu'il ne proposent pas des instructions contrastantes.


====Événements liés à la souris====
====Événements liés à la souris====
Ligne 499 : Ligne 580 :
* <code>mouseover</code> : l'événement est déclenché lorsque la souris passe sur l'élément
* <code>mouseover</code> : l'événement est déclenché lorsque la souris passe sur l'élément
* <code>mouseout</code> : l'événement est déclenché lorsque la souris quitte un élément
* <code>mouseout</code> : l'événement est déclenché lorsque la souris quitte un élément
* ...


Pour attribuer un événement à un élément il faut procéder ainsi :
Pour attribuer un événement à un élément il faut procéder ainsi :
Ligne 508 : Ligne 590 :
Il y a deux manières d'associer un événement à un élément :
Il y a deux manières d'associer un événement à un élément :


*Utiliser la '''propriété de l'événement''' qui se compose de "on" + événement (élément.onclick, élément.onmouseover, élément.onmouseut, ...) à la quelle on associe une fonction :
# Utiliser la '''propriété de l'événement''' qui se compose de '''"on" + événement''' (élément.onclick, élément.onmouseover, élément.onmouseut, ...) à la quelle on associe une fonction :
** <code>élément.'''on'''événement = function () { ... }</code>
#: <source lang="JavaScript">
*Utiliser la '''méthode addEventListener''' qui prévoit deux arguments : l'événement et la fonction à exécuter :  
  var myBtn = document.getElementById("theButtonId");
**<code>élément.addEventListener(événement, fonction)</code>
  myBtn.onclick = function () {
      console.log("The button has been clicked");
  }
  </source>
#Utiliser la '''méthode addEventListener''' qui prévoit deux arguments : l'événement et la fonction à exécuter :  
#: <source lang="JavaScript">
  var myBtn = document.getElementById("theButtonId");
  myBtn.addEvenetListener('click', function () {
    console.log("The button has been clicked");
  });
  </source>
 
Dans les deux cas, la fonction associée au gestionnaire d'événements peut être :
 
# Une '''fonction anonyme''' (comme dans les exemples plus haut)
#: <source lang="JavaScript">
  var myDiv = document.getElementById("importantDiv");
 
  //version on->event
  myDiv.onmouseover = function() {
    console.log("The mouse of the user is over the importantDiv!");
  }
 
  //version addEventListener
  myDiv.addEventListener('mouseover', function () {
    console.log("The mouse of the user is over the importantDiv!");
  });
  </source>
# Une '''fonction nommée'''
#: <source lang="JavaScript">
  var myDiv = document.getElementById("importantDiv");
 
  //Définir la fonction
  function doSomething() {
    console.log("The mouse of the user is over the importantDiv!");
  }
 
  //L'associer à la version on->event
  myDiv.onmouseover = doSomething; //Attention, pas de () ! Lire plus bas pour l'explication
 
  //L'associer à la version addEventListener
  myDiv.addEvenetListener('mouseover', doSomething); //Encore une fois sans () !
  </source>
# Une '''méthode d'un objet'''
#: <source lang="JavaScript">
  var myDiv = document.getElementById("importantDiv");
 
  //Définir un objet avec une méthode
  var o = {};
  o.mouseOverHandler = function () {
    console.log("The mouse of the user is over the importantDiv!");
  }
 
  //L'associer à la version on->event
  myDiv.onmouseover = o.mouseOverHandler(); //Attention, cette fois ci avec les () !
 
  //L'associer à la version addEventListener
  myDiv.addEventListener('mouseover', o.mouseOverHandler()); //Encore une fois avec les () ! Faites attention aux double )) de clotûre.
  </source>


Le gestionnaire d'événement peut être une fonction déjà définie ou anonyme. Il faut cependant faire attention au fait qu'un gestionnaire d'événement est une référence à la fonction et non pas l'exécution de la fonction elle-même. En d'autres termes, il ne faut pas utiliser les parenthèses dans un gestionnaire d'événement :
La raison pour laquelle il ne faut pas utiliser les () pour une fonction nommée s'explique par le fait que avec les parenthèses la fonction serait exécutée dès que le code est lu, pas lorsque l'événement s'avère  :


  function faireQuelqueChose() {
  function faireQuelqueChose() {
     //code
     //code
  }
  }
  mon-element.mon-evenement = faireQuelqueChose; //OK!
  ''element''.on''event'' = faireQuelqueChose; //OK!
  mon-element.mon-evenement = faireQuelqueChose(); //Faux, de cette manière la fonction sera exécutée de toute manière, sans attendre l'événement déclencheur
  ''element''.on''event'' = faireQuelqueChose(); //Faux, de cette manière la fonction sera exécutée tout de suite, sans attendre l'événement déclencheur


Veuillez par contre noter que si l'on associe comme gestionnaire une méthode d'un objet, alors il faudra de toute manière insérer les parenthèses.
Les objets, par contre, fonctionnent de manière différente : techniquement, on dit qu'ils sont passés par référence, mais la chose à retenir est tout simplement qu'avec les objets il faut mettre les parenthèses :


  var o = {}:
  var o = {}: //Simule un objet quelconque
  o.faireQuelqueChose = function () {
  o.faireQuelqueChose = function () {
   //code
   //code qui détermine une méthode pour l'objet
}
mon-element.mon-evenement = o.faireQuelqueChose; //Faux
mon-element.mon-evenement = o.faireQuelqueChose(); //OK!
 
On peut également utiliser une fonction anonyme en tant que gestionnaire d'événement :
 
mon-element.mon-evenement = function() {
    console.log("L'événement a eu lieu");
  }
  }
''element''.on''event'' = o.faireQuelqueChose; //Faux!
''element''.on''event'' = o.faireQuelqueChose(); //OK!


Enfin, il est possible d'utiliser la méthode<code>élément.addEventListener(événement, gestionnaire)</code> au lieu de la notation élément.événement = gestionnaire. Cette méthode à l'avantage de pouvoir s'ajouter à des gestionnaires d'événements déjà déclarés sur le même élément, sans les annuler (mais ne s'applique pas à window.onload). Voici un exemple pour illustrer ce principe qui se réfère au click sur un bouton :
Par rapport à la différence entre la version <code>on->event</code> et <code>addEventListener</code>,  '''addEventListener''' a l'avantage de pouvoir s'ajouter à des gestionnaires d'événements déjà déclarés sur le même élément, sans les annuler (mais ne s'applique pas à window.onload). Voici un exemple pour illustrer ce principe qui se réfère au click sur un bouton :


<source lang="JavaScript">
<source lang="JavaScript">
Ligne 608 : Ligne 742 :
[http://codepen.io/mafritz/pen/NGzpEo Tester cet exemple]
[http://codepen.io/mafritz/pen/NGzpEo Tester cet exemple]


Pour annuler un gestionnaire d'événement, il suffit de le redéclarer null sa propriété d'événement (e.g. <code>mon-élément.mon-événement = null</code>) ou d'utiliser la méthode <code>élément.removeEventListener()</code>.
Pour annuler un gestionnaire d'événement, vous pouvez :
 
# Affecter à <code>null</code> l'événement dans la version on->event
#: <source lang="JavaScript">
  var myBtn = document.getElementById("theButtonId");
  //Création du gestionnaire
  myBtn.onclick = function () {
    console.log("Je ne serais pas affiché");
  }
  //Annulation du gestionnaire
  myBtn.onclick = null;
  </source>
# Utiliser la méthode <code>removeEventListener()</code> qui fonctionne exclusivement avec des fonctions nommées !
#: <source lang="JavaScript">
  var myBtn = document.getElementById("theButtonId");
  //Définir la fonction
  function logEvent() {
    console.log("Je ne serais pas affiché");
  }
  //Création du gestionnaire
  myBtn.addEventListener('click', logEvent);
  //Annulation du gestionnaire
  myBtn.removeEventListener('click', logEvent);
  </source>
 
Comme pour la création des gestionnaires, la même différence s'applique : annuler la version on->event annule tous les événements qui sont associé, tandis que removeEventListener annule exclusivement l'exécution de la fonction particulière qui a été annulée.
 
====L'objet event passé en argument====


Il existe une méthode plus souple pour définir un gestionnaire d'événement et que l'on retrouve aussi dans ActionScript.
Lorsqu'on associe un gestionnaire d'événement, ce gestionnaire reçoit automatiquement l'objet <code>event</code> en tant qu'argument. On peut utiliser cet objet pour récupérer des informations utiles sur l'événement et/ou sur l'élément qui l'a déclenché. Par exemple, on peut attribuer un listener sur l'ensemble des clicks sur body, et récupérer des informations sur l'élément spécifique qui a été cliqué :


Dans l'exemple suivant,la fonction <code>start()</code> sera exécutée dès que la page charge, ceci à cause de l'instruction <code>window.onload = start;</code> qui associe à l'événement "onload" le nom d'une fonction qu'il faut exécuter. Rien de neuf. Par contre, la gestion du 2ème événement se fait différemment.
<source lang="JavaScript">
<source lang="JavaScript">
<!DOCTYPE html>
//Add a listener for clicks anywhere in the body
<html>
document.body.addEventListener("click", clickHandler);
  <head>
 
      <title>Event handling</title>
//The listener receives the event object
      <script type = "text/javascript">
function clickHandler(event) {
        window.onload = start;
  //Retrieve the name of the tag clicked
        // var my_para_button  ="";
  var tag = event.target.tagName;
  //Retrieve the content of the tag clicked
  var content = event.target.innerHTML;
  //Output some info about what has been clicked
  document.querySelector("#output").innerHTML += "You clicked on a " + tag + " with content <strong>" + content + "</strong><br>";
}
</source>
 
Imaginez maintenant d'avoir dans le body le code suivant :
<source lang="HTML5">
...
<body>
<h1>The event argument/object</h1>
<p>Click over me<!</p>
<p>Or click over me!</p>
<button>Or even here</button> <button>Or finally here</button>
<hr>
<div id="output"></div>
</body>
...
</source>
 
Selon l'élément que vous cliquez dans la page, vous pouvez obtenir un output du type :
 
* You clicked on a H1 with content The event argument/object
* You clicked on a P with content Click over me
* You clicked on a P with content Or click over me!
* You clicked on a BUTTON with content Or even here
* You clicked on a BUTTON with content Or finally here
 
[https://codepen.io/mafritz/pen/JRVAGj Testez cet exemple]
 
====Bloquer les événements associées aux balises HTML====
Certains balises HTML ont des comportements spécifiques associés. Par exemple si on clique sur l'élément <code>a</code>, le navigateur sera redirigé sur le lien correspondant à l'attribut <code>href</code>. JavaScript permet d'intercepter les comportements automatiques des balises et de les empêcher de se déclencher, à travers la notation <code>event.preventDefault()</code>.


function start()  {
Voici un exemple avec deux liens qui pointent à l'home page de ce wiki, mais dont seulement le deuxième marchera "normalement". D'abord le code HTML :
  // put an event handler on the div box
  var my_para_button = document.getElementById("box");
  my_para_button = addEventListener("click", modifyText);
        }


function modifyText() {
<source lang="HTML5">
  // get the box
<ul>
  var my_content = document.getElementById("content");
  <li>Prevented: <a id="prevented" href="http://edutechwiki.unige.ch/fr/Accueil">Go to EduTeckWiki (fr)</a>
  my_content.innerHTML = "That was so good";
  </li>
}
  <li>Normal : <a id="not-prevented" href="http://edutechwiki.unige.ch/fr/Accueil">Go to EduTeckWiki (fr)</a>
      </script>
  </li>
  </head>
</ul>
  <body>
      <div id="box">
        <p style="background-color:yellow" id="content">CLICK ME !</p>
      </div>
  </body>
</html>
</source>
</source>
Source: http://tecfa.unige.ch/guides/js/ex-intro/event-handler.html


La fonction ''start'' ajoute un gestionnaire d’événement au bouton ''my_para_button'' en utilisant la méthode <code>addEventListener ("click", modifyText); </code>. Le premier argument, "click", identifie le type d’événement, et le deuxième donne le nom de la fonction.
Et ensuite le code JavaScript qui permet de bloquer le comportement normal du premier lien.
 
<source lang="JavaScript">
//Prevented
document.getElementById("prevented").onclick = function(event) {
  //Prevent the default link behavior
  event.preventDefault();
  //Change the text of the link
  this.innerHTML = "JavaScript intercepted the normal event and prevented it!"
};
</source>
 
* [http://codepen.io/mafritz/pen/XdQZQR Tester cet exemple]
 
On utilise souvent la méthode <code>preventDefault()</code> pour éviter que la page soit rechargée, notamment avec les formulaires. Ceci permet de garder la session de la page active et donc de maintenir toutes les informations et manipulations de l'utilisateur au niveau client.


===L'élément this dans le DOM===
===L'élément this dans le DOM===
Ligne 663 : Ligne 859 :
     monBouton.onclick = function() {
     monBouton.onclick = function() {
       //Changer le label du bouton
       //Changer le label du bouton
       this.innerHTML = "J'ai cliquez sur le bouton";
       this.innerHTML = "J'ai cliqué sur le bouton";
       //Désactiver le bouton
       //Désactiver le bouton
       this.disabled = "disabled";
       this.disabled = "disabled";
Ligne 700 : Ligne 896 :


Les changements de style peuvent être appliqués à tout moment dans le code et être donc associés, par exemple, à des événements (voir plus haut dans la page).
Les changements de style peuvent être appliqués à tout moment dans le code et être donc associés, par exemple, à des événements (voir plus haut dans la page).
En considération du fait que les noms des propriétés des objets en JavaScript ne peuvent pas contenir le caractère <code>-</code>, toutes les propriétés CSS qui prévoient ce diviseur doivent être modifiées en "camel case", e.g :
* background-color --> ''élément''.style.backgroundColor
* border-color --> ''élément''.style.borderColor
* font-size --> ''élément''.style.fontSize
*...
En alternative vous pouveez utiliser la notation type array : ''élément''.style["background-color"]


===Utiliser les classes===
===Utiliser les classes===
Ligne 709 : Ligne 914 :
  ''élément''.className = 'active'
  ''élément''.className = 'active'


Il faut noter que la propriété className se réfère à tout le l'attribut HTML. Voici un élément HTML qui a plusieurs classes :
Il faut noter que la propriété className se réfère à tout l'attribut HTML. Voici un élément HTML qui a plusieurs classes :


<source lang="HTML5">
<source lang="HTML5">
Ligne 815 : Ligne 1 020 :
Il est également possible d'utiliser la notation "par point", au lieu des parenthèses carrées, si le nom du champ respecte la notation correcte pour les variables JavaScript.  
Il est également possible d'utiliser la notation "par point", au lieu des parenthèses carrées, si le nom du champ respecte la notation correcte pour les variables JavaScript.  


Voici un simple exemple de validation pour montrer brièvement le mécanisme. Le code JavaScript contrôle que le champ email ne soit pas vide et que les conditions ont été acceptées à travers le checkbox.  
Voici un simple exemple de validation pour montrer brièvement le mécanisme. Le code JavaScript contrôle que le champ email ne soit pas vide et que les conditions ont été acceptées à travers la checkbox.  


<source lang="JavaScript">
<source lang="JavaScript">
Ligne 826 : Ligne 1 031 :
<body>
<body>
<h1>JavaScript - formulaires</h1>
<h1>JavaScript - formulaires</h1>
<form name="mon-formulaire">
<form name="mon-formulaire" method="post" action="/submit">
   Email : <input name="email" type="text"><br>
   Email : <input name="email" type="text"><br>
   <input type="checkbox" name="conditions"> J'accepte les conditions d'inscription<br>
   <input type="checkbox" name="conditions"> J'accepte les conditions d'inscription<br>
Ligne 841 : Ligne 1 046 :
     } else {
     } else {
       window.alert("Vous devez insérer votre email et accepter les conditions");
       window.alert("Vous devez insérer votre email et accepter les conditions");
       //Le retour false fait ainsi que le formualire ne soit pas soumis et la page pas actualisée
       //Le retour false fait que le formualire n'est pas soumis et la page pas actualisée
       return false;
       return false;
     }
     }
Ligne 849 : Ligne 1 054 :
</html>
</html>
</source>
</source>
* Voir le [http://eloquentjavascript.net/18_forms.html chapitre 18] de Haverbeke (2015)


== La sécurité avec JavaScript ==
== La sécurité avec JavaScript ==
Ligne 905 : Ligne 1 112 :
* https://fr.wikipedia.org/wiki/Cross-site_scripting
* https://fr.wikipedia.org/wiki/Cross-site_scripting
* https://fr.wikipedia.org/wiki/Injection_de_code_dans_les_applications_web#Cross-site_scripting_.28XSS.29
* https://fr.wikipedia.org/wiki/Injection_de_code_dans_les_applications_web#Cross-site_scripting_.28XSS.29
==Bibliographie==
* Haverbeke, M. (2015). [http://eloquentjavascript.net/ Eloquent JavaScript. A modern Introduction to Programming]. Second Edition. San Francisco, CA: no starch press. Chapitres 12 à 18


[[Category: JavaScript]]
[[Category: JavaScript]]
[[Category: Ressources STIC]]

Dernière version du 21 août 2024 à 09:14

Initiation à la pensée computationnelle avec JavaScript
Module: Références JavaScript ◀▬
◀▬▬▶
à finaliser
2024/08/21
Voir aussi
Catégorie: JavaScript

Introduction

Ce tutoriel présente un survol des caractéristiques principales du langage JavaScript relatives à l’utilisation « côté client », c’est-à-dire l’utilisation la plus fréquente dans des pages/applications web à l’intérieur d’un navigateur. JavaScript permet en effet de "dynamiser" le contenu d'une page une fois qu'elle est disponible dans le navigateur. Pour suivre les exemples disponibles dans ce tutoriel il faut une connaissance de base du langage. Voir :

Conseil de lecture

Cette page présente une grande quantité d'information en relativement peu d'espace. Elle explique principalement les fonctionnalités, mais sans un objectif bien spécifique, ce qui peut décourager surtout les novices. Nous conseillons de lire d'abord la section JavaScript et le navigateur web et par la suite d'utiliser cette page comme référence croisée avec la page

qui propose l'explication étape par étape de quelques exemples.

Rappel de la structure d'une page web

Avant d'aborder JavaScript, il est utile de rappeler la structure d'une page web qui se compose généralement de trois éléments :

  • HTML : cet élément détermine le contenu de la page, c'est-à-dire les éléments textuels et graphiques affichés à l'écran.
  • CSS : cet élément détermine la mise en page, la manière de présenter les éléments HTML de la page. On peut déterminer à travers les CSS les couleurs, les polices, l'alignement des éléments, etc.
  • JavaScript : cet élément ajoute des interactions et des comportements (ou effets) au contenu et/ou à la présentation de la page. Ces phénomènes permettent de modifier la page sans la nécessité d'actualiser le navigateur.

Outils pour le développement et le débug

Pour développer en JavaScript seulement deux outils sont strictement nécessaires :

  • Un navigateur web
  • Un éditeur de texte

Des outils supplémentaires peuvent sans doute rendre le développement plus aisé. Voici une liste de ces outils :

Console JavaScript

La Console JavaScript (déjà introduite dans le Tutoriel JavaScript de base) devient encore plus utile pour JavaScript côté client, car elle peut non seulement interpréter le langage de base, mais également avoir accès aux éléments de l'environnement, c'est-à-dire le navigateur web. Nous rappelons que vous pouvez accéder à la Console des manières suivantes :

  • Internet Explorer : Menu Outils > Outils de développement (ou F12)
  • Firefox : F12 ou plus de fonctionnalités avec le Scratchpad (SHIFT-F4).
  • Chrome : Menu Outils > Console JavaScript (ou F12)
  • Safari : D'abord dans les Options > Avancées cocher la case "Afficher le menu Développement dans la barre des menus", puis CTRL+Alt+I ou CTRL+Alt+C
  • Opera: Menu Page > Outils de Développement > Opera Dragonfly (ou CTRL+Shift+I)
Console des erreurs en Google Chrome

Par exemple si vous tapez window.navigator vous pouvez voir quelques informations sur votre navigateur.

JavaScript et le navigateur web

L'avantage de JavaScript côté client consiste dans le fait que les navigateurs web disposent d'un "moteur" qui permet d'évaluer le code JavaScript et l'exécuter à chaque fois qu'une page web, contenant du code JavaScript, est téléchargée par l'utilisateur. Ceci est possible surtout grâce à deux phénomènes :

  1. L'inclusion de code JavaScript dans des pages HTML ;
  2. L'existence d'un objet global window qui permet à JavaScript d'interagir avec le navigateur web.

Utilisation du code JavaScript dans une page HTML

Il existe trois manières différentes d'utiliser du code JavaScript dans une page web :

  1. Fichier externe : le code est écrit dans un fichier avec extension .js
  2. Code "inline" : le code est écrit directement dans la page web elle-même
  3. Attribut des balises : le code est écrit dans des attributs des balises des éléments HTML de la page. Cette option, utilisée souvent dans le passé, est aujourd'hui plutôt déconseillée.

Les trois différentes manières peuvent être utilisées en même temps, il n'est pas nécessaire de choisir une seule manière pour toute la page.

Fichier externe

Dans le cas d'utilisation d'un fichier externe, ce fichier doit être créé avec l'extension .js. Dans ce fichier doit être contenu seulement du code JavaScript. Le code peut commencer dès la première ligne, il ne faut pas déclarer le type de fichier par exemple à travers une balise XML.

Pour rendre disponible le code d'un fichier externe dans une page web, il faut inclure le lien au fichier dans la balise HTML script et plus précisément à travers l'attribut src. Voici un exemple :

<script src="path/to/file.js"></script>

Veuillez noter que la balise script doit être fermée avec la balise de clôture même si à l'intérieur d'une balise avec attribut src il ne faut pas insérer de code.

Le lien au fichier .js suit les règles des liens hypertextuels à tout autre type de fichier, y compris les liens à d'autres pages HTML. On peut donc avoir un lien :

  • Absolu : le lien présente tout le URL du fichier,
    E.g. <script src="http://tecfa.unige.ch/path/to/file.js"></script> (ce fichier n'existe pas)
  • Relatif à la racine du domaine
    E.g. <script src="/path/to/file.js"></script>. Veuillez noter le / initial qui détermine la racine du domaine. Dans ce cas la page HTML et le fichier JS doivent se trouver sur le même domaine (e.g. http://tecfa.unige.ch)
  • Relatif à la position du fichier HTML
    E.g. <script src="../path/to/js"></source>.

Les positionnements relatifs utilisent une notation qui combine un . ou deux .. points et un slash / :

  • <script src="./file.js"></script> : le fichier file.js se trouve dans la même position (i.e. même dossier sur le serveur) de la page HTML
  • <script src="file.js"></script> : le fichier file.js se trouve dans la même position de la page HTML (équivalent à l'exemple précédent et utilisé plus souvent)
  • <script src="assets/js/file.js"></script> : le fichier file.js se trouve dans un dossier "js" qui se trouve à l'intérieur du dossier "assets". Le dossier "assets" se trouve à l'intérieur du dossier qui contient également la page HTML.
  • <script src="../file.js"></script> : le fichier file.js se trouve directement dans le dossier "parent" du dossier qui contient la page HTML
  • <script src="../js/file.js"></script> : le fichier file.js se trouve à l'intérieur du dossier "js" qui se trouve dans le dossier "parent"
  • <script src="../../../../file.js"> : le fichier file.js se trouve 4 niveaux "plus haut" par rapport à la page HTML

Le mauvais pointage d'un fichier externe est une des raisons les plus communes d'erreur dans le code JavaScript et il est par conséquent la première chose à contrôler en cas de problèmes. Une manière simple pour tester les liens à des fichiers JavaScript externes consiste à utiliser le code source de la page HTML. Certains navigateurs permettent en effet de cliquer sur le lien et ouvrir directement le fichier JS. La vidéo suivante montre cette opération en Google Chrome : si le lien est mauvais, le fichier ne sera pas trouvé.

Utiliser le code source de la page HTML pour tester les liens à des fichiers JS externes (en Google Chrome).

On utilise des fichiers externes souvent dans ces conditions :

  • Le même fichier contient du code qui est utilisé dans plusieurs pages d'un site, ce qui évite la nécessité de l'écrire dans toutes les pages. De cette manière, une modification au code doit se faire à un seul endroit et sera automatiquement activée dans toutes les pages.
  • Le fichier est une bibliothèque JavaScript
  • Il y a beaucoup de code écrit

Code inline

Une autre manière très utilisée d'inclure du code JavaScript consiste à écrire le code directement à l'intérieur de la balise script. Dans ce cas, il ne faut pas déclarer l'attribut src. Voici un exemple :

<script>
alert("Bonjour!");
</script>

La balise script peut contenir seulement du code JavaScript. Dans des exemples sur le web vous pouvez parfois trouver des balises script qui présentent aussi l'attribut type="text/javascript". Cet attribut n'est plus nécessaire car tout navigateur considère automatiquement le code inséré dans cette balise comme du code JavaScript.

On utilise du code "inline" souvent dans ces conditions :

  • Le code doit être exécuté précisément à cet endroit dans la page, par exemple parce qu'il ajoute du texte ou des éléments HTML.
  • Le code est spécifique à une seule page du site est le code n'a pas de probabilité d'être utilisé ailleurs
  • Le code est court
  • Le code sert à configurer des options ou initialiser une bibliothèque JavaScript

Attributs des balises HTML

Pour placer du JavaScript dans les attributs HTML il faut utiliser les attributs qui se réfèrent aux événements JavaScript (voir plus bas), comme par exemple l'attribut onclick="..." :

<button onclick="alert('J'ai cliqué sur le bouton');">Ouvrir une alerte</button>

Cette manière d'ajouter du JavaScript est plutôt déconseillée, mais reste fonctionnelle surtout pour des néophytes.

Placement de la balise script

Un élément auquel il faut faire attention est le placement de la balise script dans la page HTML. Il faut en effet tenir compte de la manière progressive de charger une page des navigateurs web. Avec le code JavaScript on fait souvent référence à des éléments du DOM (i.e. des balises HTML contenues dans la page). Il faut faire attention dans ces cas à ce que cet élément soit déjà disponible au navigateur.

Même s'il existe des fonctions pour déclencher le code seulement une fois que toute la structure du DOM a été chargée dans le navigateur (e.g. window.onload), il est une bonne pratique d'inclure les balises script juste avant la balise de clôture /body :

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Untitled Document</title>
</head>
<body>

  <script>
  //Mon code est mieux ici!
  </script>
</body>
</html>

On peut insérer plusieurs scripts, l'un après l'autre, et même combiner les fichiers externes et les scripts inline :

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Untitled Document</title>
</head>
<body>
  <!-- HTML de la page -->

  <!-- Les scripts vont ici -->
  <script src="path/to/external/file.js"></script>
  <script src="another/external.js"></script>
  <script>
  //Du code inline ici
  </script>
</body>
</html>

L'objet global window

JavaScript dépend de l'environnement dans lequel il est exécuté à la fois pour afficher les résultats des expressions (i.e. le output), mais également pour recevoir des inputs. Dans JavaScript côté client, cet environnement est représenté par le navigateur web et la communication I/O entre JavaScript et le navigateur web se fait à travers l'objet global window. Plus concrètement cela signifie que :

  1. JavaScript peut "intercepter" tous les événements qui concernent la fenêtre du navigateur comme par exemple les clicks, les changements d'URL, le scolling de la page, etc.
  2. JavaScript peut modifier certaines propriétés de la fenêtre, y compris son contenu.

Les deux opérations sont possibles justement grâce à l'objet global window qui, en tant qu'objet, possède des propriétés et des méthodes. Comprendre l'objet global window peut contribuer à bien comprendre le langage, car en réalité tout le code source écrit en JavaScript côté client peut se diviser en deux catégories :

  1. Le code qui exploite les propriétés et méthodes mises à disposition par l'objet window
  2. Le code qui ajoute des propriétés (e.g. des variables) ou des méthodes (e.g. des fonctions) à l'objet global window

En effet, lorsqu'on déclare une variable, ce que nous sommes en train de faire c'est tout simplement d'ajouter une propriété avec le nom de la variable à l'objet global window. En d'autres termes, les deux lignes de code suivantes sont équivalentes :

  • var cours = "STIC I";
  • window.cours = "STIC I";

Vous pouvez tester l'équivalence de cette manière :

var cours = "STIC I";
cours === window.cours; //--> true

Le même principe s'applique aux fonctions :

function addTwo(x) {
  return x + 2;
}
addTwo(4); // -> 6
window.addTwo(7); //--> 9

En raison du fait que tout appartient à l'objet window, on peut éviter de le déclarer à chaque fois. Le même principe s'applique aux propriétés et méthodes déjà disponibles. Par exemple la fonction alert() - qui affiche une boîte popup avec un message - est en réalité la méthode window.alert().

À travers JavaScript il est également possible de changer des propriétés de l'objet global window, ce qui se traduit par des comportements spécifiques qui modifient le contenu du navigateur. Vous pouvez par exemple essayer d'écrire ce code dans la Console de votre navigateur web pour être redirigé à la page d'accueil de ce wiki :

window.location = "http://edutechwiki.unige.ch/fr/Accueil";

Pour une liste exhaustive voir la référence de l'objet Window sur W3Schools.

L'objet document

L'objet global window contient plusieurs "sous-objets" dont un des plus importants est le window.document qui peut être directement abrégé en document dans le code. Cet objet représente le contenu de la page HTML, c'est-à-dire l'arborescence des balises qui déterminent le contenu de la page. Si vous insérez la commande document dans la Console de votre navigateur, vous obtenez en effet le code HTML de la page (le code de l'homepage EduTechWiki à l'image). On se réfère à cette structure avec le nom de Document Object Model, ou DOM.

L'objet document représente le DOM de la page.

Vous pouvez par la suite essayer document.head et document.body pour obtenir respectivement le contenu de la balise head (informations) et de la balise body (contenu) d'une page. Pour sélectionner ensuite des éléments plus spécifiques (e.g. un titre, une image, etc.), il faudra utiliser d'autres méthodes.

  • Voir "JavaScript et le DOM" plus bas dans la page

Les boîtes popup de JavaScript

Pour le débutant, créer quelques simples boîtes popup permet se lancer dans la programmation. On peut par exemple poser une question à un utilisateur et ensuite la traiter, puis afficher le résultat.

JavaScript possède 3 sortes de boîtes popup :

  1. Les boîtes d'alerte
  2. Les boîtes de confirmation
  3. Les fenêtres de saisies.

Veuillez noter que ces éléments sont mis à disposition par le navigateur web et donc le contrôle que le développeur a sur leur fonctionnement et leur apparence est très limité. De plus, ils ne sont pas très pratique au niveau expérience utilisateur. En d'autres termes, il s'agit d'outils pratiques pour explorer quelques événements/intérations de base, mais par la suite il faudrait les remplacer par des éléments HTML "customizés" (e.g. des fenêtres modales, des formulaires, etc.).

Les boites d'alerte

Elles affichent un message. Elles servent généralement à donner un message à un utilisateur ou à indiquer un message d'erreur. La boîte d'alerte contient un bouton 'Ok'.

Alert.jpg

Il faut utiliser la fonction alert(), c'est-à-dire l'équivalent de window.alert()

alert("Je suis une alerte!");

Vous pouvez structurer votre message dans vos boites en insérant '\n' à la fin de vos phrases. Cela permettra de revenir à la ligne.

alert ('Première ligne.\n Deuxième ligne.');

La fonction alert() ne "return" aucune valeur (i.e. undefined).

Les boîtes de confirmation

La fonction confirm() affiche une boite de confirmation. L'utilisateur a alors le choix entre 'OK' et 'annuler'.

Confirm.jpg

La fonction accepte un paramètre qui détermine le message affiché à l'intérieur de la boîte :

confirm("Voulez-vous continuer?");

La fonction confirm() "return":

  • true si l'utilisateur clique sur OK
  • false si l'utilisateur clique sur annuler

Vous pouvez donc l'utiliser pour simuler des structure de contrôle qui dépendent du choix des utilisateurs:

var continuer = confirm("Voulez-vous continuer?");

if(continuer) {
  console.log("L'utilisateur voudrait continuer...");
} else {
  console.log("L'utilisateur ne veut pas continuer...");
}

Les fenêtres de saisie

Il est possible de créer une fenêtre pour saisir une valeur grâce à la fonction prompt() et peut ensuite confirmer ou annuler son choix. La fonction prend deux paramètres : le premier est l'invitation à saisir du texte et le second propose un texte par défaut :

Prompt.jpeg

Le code suivant demande à l'utilisateur de saisir son nom, sans donner une valeur préétablie :

prompt("Identification, veuillez saisir votre prénom", "");

La fonction prompt() "return" :

  • La valeur saisie lorsque l'utilisateur clique sur OK.
  • false si la personne ne saisie aucune valeur ou si elle clique sur annuler

Vous pouvez combiner prompt() et alert() pour créer une première interaction dans une page web :

var name = prompt("Veuillez saisir votre nom", "");
alert("Bonjour " + name);

Attention : la valeur est toujours de type string même si la valeur saisie est un nombre! Essayez cet exemple :

var num = prompt("Choisissez un nombre à ajouter à 100 pour voir le résultat", "");
console.log(100 + num);

Vous pouvez noter que le résultat ne sera pas l'addition souhaitée. Si vous avez choisi 20, le message affiché sera 10020 parce que le 20 saisi est traité comme une suite de caractères et par conséquent le + est interprété comme une concaténation. Pour éviter ce problème, il faut spécifier que le résultat du prompt doit être traité comme un nombre, en utilisant par exemple la fonction parseInt() :

var num = prompt("Choisissez un nombre à ajouter à 100 pour voir le résultat", "");
console.log(100 + parseInt(num)); //On peut utiliser également Number(num)

JavaScript et le DOM

Le Document Object Model (DOM) d'une page web.

Une des fonctionnalités les plus utilisées de JavaScript est sa capacité d'interagir dynamiquement avec le DOM, c'est-à-dire la structure hiérarchique des balises HTML d'une page web. C'est notamment grâce à la manipulation des éléments du DOM qui s'avèrent les interactions sur une page : apparition d'un message, déplacement d'un élément d'un endroit à un autre, changement de la taille d'une police, du couleur, etc.

Ces manipulations sont possibles grâce à l'objet document qui fait partie de l'objet global window (voir plus haut dans la page). Les propriétés, méthodes ainsi que les événements associés à cet objet permettent de manipuler le DOM.

NB: La manipulation du DOM à travers JavaScript "de base" est un bon point de départ pour comprendre la logique, mais pour des applications plus poussées les développeurs utilisent souvent des bibliothèques JavaScript qui simplifient la syntaxe ou facilitent certains opérations. La bibliothèque la plus utilisée dans ce sens est jQuery.

Manipulation des éléments du DOM

Trouver un élément

Trois méthodes permettent d'identifier un élément dans la structure du document :

  • document.getElementById(id élément) : identifie un élément avec l'attribut id="..."
  • document.getElementsByTagName(nom de la balise) : identifie un ou plusiuers éléments avec le nom de la balise
  • document.getElementsByClassName(une ou plusieurs classes) : identifie un ou plusieurs éléments avec l'attribut class="..."

Une méthode plus générale est également disponible à travers les méthodes :

  • document.querySelector(css selector)  : cette méthode accepte des identifiants plus complexes par rapports aux trois méthodes vues plus haut dans la page, mais elle est également plus flexible, car elle permet d'identifier les éléments grâce aux selecteurs CSS. Cette méthode identifie le premier élément qui respecte les critères du selecteur.
  • document.querySelectorAll(css selector) : même principe, mais le résultat est une liste de noeuds avec tous les éléments qui respectent le critère de sélection.

Voici quelques exemples d'utilisation :

document.querySelectorAll("a.external") //cette méthode identifie toutes les balises a avec classe "external"
document.querySelectorAll("h1,h2,h3") //cette méthode identifie toutes les titres de h1 à h3

Cette fonction peut également être utilisée à l'intérieur des éléments du DOM :

var monParagraphe = document.getElementById("monTexte");
monParagraphe.querySelector("span").innerHTML = "Nouveau texte du span";

Ce code identifie le premier élément span à l'intérieur du paragraphe avec id="monTexte" et change le contenu textuel.

<p id="monTexte">Voici un paragraphe avec du <span>texte dans un span</span></p>

Récupérer/Modifier des caractéristiques d'un élément

On peut récupérer ou modifier différentes caractéristiques d'un élément une fois identifié dans le document. Par exemple :

  • element.textContent : se réfère au contenu textuel de l'élément sélectionné
  • element.innerHTML : se réfère au contenu, y compirs les balises HTML d'éléments emboîtes, de la balise de l'élément sélectionné
  • element.attribute : se réfère à un attribut spécifique de la balise de l'élément sélectionné
  • element.style.property : se réfère à une propriété de style spécifique de la balise de l'élément sélectionné

Pour récupérer il suffit de spécifier la propriété à laquelle on s'intéresse, par exemple :

//Récupérer le contenu textuel d'un element avec id="my-element"
var myElementText = document.getElementById("my-element").textContent;

//Récupérer le contenu, y compirs les balises HTML, d'un élément avec id="my-element"
var myElementHTML = document.getElementById("my-element").innerHTML;

//Récupérer la valeur d'un attribut d'un element avec id="my-element", par exemple une image avec l'attribut title
var myImageTitle = document.getElementById("my-element").title;

//Récupérer la propriété de style font-size d'un element avec id="my-element"
var myElementFontSize = document.getElementById("my-element").style.fontSize; 
//veuillez noter qu'on peut pas utiliser font-size mais il faut transformer en fontSize. Ceci s'applique à toute propriété qui utilise le -

Pour modifier il faut affecter la caractéristique à une nouvelle valeur à travers le symbole d'affectation, par exemple :

//Modifier le contenu textuel d'un element avec id="my-element"
document.getElementById("my-element").textContent = "Nouveau texte de l'élément!";

//Modifier le contenu, y compirs les balises HTML, d'un élément avec id="my-element"
document.getElementById("my-element").innerHTML = "<strong>Nouveau contenu de l'élément!</strong>";

//Modifier la valeur d'un attribut d'un élément, par exemple la valeur src pour remplacer une image avec une autre
document.getElementById("my-image").src = "./my/new/path/to/image.png";

//Modifier la valeur d'une propriété de style d'un élément, par exemple sa taille
document.getElementById("my-element").style.fontSize = '40px';

Veuillez faire attention que pour les modification textContent et innerHTML vous ne pouvez pas afficher votre nouveau contenu sur plusieurs lignes, en d'autres termes CE CODE N'EST PAS VALIDE :

//CODE NON VALIDE !!!
var hello = "Hello my dear User!";
document.getElementById("my-element").innerHTML = "<div>
                                                       <p>" + hello + "</p>
                                                   </div>";

Vous avez trois alternatives :

  • Tout mettre sur une seule ligne, ce qui n'est parfois pas très pratique, surtout si vous voulez insérer des valeurs symboliques à l'intérieur :
var hello = "Hello my dear User!";
document.getElementById("my-element").innerHTML = "<div><p>" + hello + "</p></div>";
  • Utiliser une concatenation += :
var hello = "Hello my dear User!";
document.getElementById("my-element").innerHTML = "<div>";
document.getElementById("my-element").innerHTML += "<p>";
document.getElementById("my-element").innerHTML += hello; 
document.getElementById("my-element").innerHTML += "</p>"
document.getElementById("my-element").innerHTML += "</div>";
  • Utiliser les littéraux de gabarits `` (backticks en anglais) et l'interpolation ${code} (fonctionnalité introduite en 2016), voir ici pour plus d'infos
var hello = "Hello my dear User!";
document.getElementById("my-element").innerHTML = `<div>
                                                       <p>${hello}</p>
                                                   </div>`;

Ajouter ou supprimer un élément

On peut ajouter des éléments qui n'existent pas dans la structure de base du document ou supprimer des éléments existants. Exemples :

  • document.createElement() : définit un nouvel élément HTML
  • document.appendChild() : ajoute un élément à la structure existante
  • document.replaceChild() : remplace un élément existant par un autre élément
  • document.removeChild() : supprime un élément présent dans la structure

Exemples de manipulation

Dans la page suivante, 4 types de manipulation ont lieu lorsque la page a été chargée. Vous pouvez comparer le contenu attendu s'il n'y avait pas de manipulation JavaScript (i.e., la source HTML) avec le résultat final qui s'affiche à l'écran de l'utilisateur dans cette image :

Comparaison entre le résultat du simple code HTML et sa transformation avec le script JavaScript

Voici le code de la page entière :

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - exemple de manipulation du DOM</title>
</head>
<body>
 
<h1>JavaScript - exemple de manipulation du DOM</h1>

<p id="p1">Premier paragraphe.</p>
<p id="p2">Deuxième paragraphe.</p>
<p id="p3">Troisième paragraphe</p>
<p>Quatrième paragraphe.</p>
<div>Je ne suis pas un paragraphe!</div>

<script>

window.onload = function() {
  //1. On remplace le texte du premier paragraphe
  var p1 = document.getElementById("p1");
  p1.innerHTML = "Le texte du premier paragraphe a été modifié par JavaScript";
 
  //2. On ajoute une image au deuxième paragraphe
  var p2 = document.getElementById("p2");
  var image = document.createElement("img");
  image.src = "http://lorempixel.com/200/200/abstract";
  p2.appendChild(image);
 
  //3. On supprime le troisième paragraphe
  var p3 = document.getElementById("p3");
  document.getElementsByTagName("body")[0].removeChild(p3);
 
  //4. On change la couleur du texte des paragraphes
  var pp = document.getElementsByTagName("p");
  for(var i = 0; i < pp.length; i++) {
    document.getElementsByTagName("p")[i].style.color = "#F00";
  }
}
</script>
</body>
</html>

L'expression window.onload = function () { ....} associe directement une fonction anonyme (sans nom) qui est exécutée lorsque la page est chargée (voir plus bas la documentation sur les événements du DOM). Les manipulations 1. et 2. ne nécessitent pas d'explication supplémentaire, tandis que la 3. et la 4. sont un peu plus complexes. Il faut considérer en effet que la méthode getElementsByTagName() renvoie un liste de noeuds. Une liste de noeuds partage plusieurs caractéristiques avec un array, mais n'est pas exactement la même chose. Par exemple il n'est pas possible d'itérer une liste de noeuds avec la fonction forEach(), mais on peut le faire avec un cycle for() en utilisant la notation liste[index] comme indiqué dans l'exemple 4. Pour simplicité, nous nous référons par la suite à une liste de noeuds comme un array, mais tenez présente cette distinction (voir cette page sur w3school pour plus de détails).

Dans la manipulation 3. nous avons identifié d'abord la balise body car il s'agit de la balise "parent" du paragraphe 3 qu'on veut supprimer. Bien qu'il n'y ait généralement qu'une seule balise body, la méthode getElementsByTagName() renvoie néanmoins une liste de noeuds (une sorte de array), dont le premier et seul élément est notre balise body. Vu que les indices des listes commencent à 0, pour identifier notre élément body nous devons ajouter l'indice [0] à la méthode getElementsByTagName("body").

Le même principe concerne la manipulation 4., dans laquelle la liste contient par contre plusieurs éléments. Pour changer chaque élément, il faut par conséquent un cycle. Nous avons créé ce cycle à l'aide de la fonction for et nous avons déclaré en tant que fonction de sortie la propriété .length de la liste. Cette propriété identifie le nombre d'éléments présents.

Tester cet exemple

Événements du DOM

Les événements du DOM permettent d'identifier l'interaction de l'utilisateur avec la page, par exemple à travers les mouvements de la souris, les touches du clavier, etc. Les événements concernent également les éléments eux-mêmes, par exemple dans le cas de l'objet window ou encore des éléments d'un formulaire.

L'événement onload

L'événement onload() est déclenché lorsqu'un élément (ou tout le DOM) a été téléchargé dans le navigateur web. Une notation qui est très utilisée et qui, par contre, nécessite de déclarer explicitement l'objet window concerne l'événement onload :

  • window.onload() : permet de déclencher du code une fois que la page a été chargée dans le navigateur. Il faut être attentif au fait que cette fonction peut être déclarée seulement une fois dans chaque page. Si plusieurs déclarations de window.onload sont disponibles dans la même page, seulement celle déclarée en dernière sera exécutée.
<script>
window.onload = alert("Je ne serai pas affiché");
window.onload = alert("Je serai affiché");
</script>

Un autre problématique relative à cette fonction concerne le fait que l'événement onload se déclenche lorsque tous les éléments du DOM ont bien été chargés, y compris images, feuilles de style, etc. Ceci peut parfois retarder le déclenchement de l'événement et par conséquent tous les éléments interactifs associés à cet événement ne seront pas disponibles.

L'événement onload() peut être également associé à d'autres objets de la page, comme par exemple les images, les iframes, etc.

Dans l'exemple suivant, la fonction start() sera exécutée dès que la page charge, ceci à cause de l'instruction window.onload = start qui associe à l'événement "onload" le nom d'une fonction qu'il faut exécuter. Rien de neuf. Par contre, la gestion du 2ème événement se fait différemment (voir événements liés à la souris plus bas).

<!DOCTYPE html>
<html>

<head>
    <title>Event handling</title>
    <script>
        window.onload = start; //Sans () ! 

        function start() {
            // put an event handler on the div box
            var my_para_button = document.getElementById("box");
            my_para_button.addEventListener("click", modifyText);
        }

        function modifyText() {
            // get the box
            var my_content = document.getElementById("content");
            my_content.innerHTML = "That was so good";
        }
    </script>
</head>

<body>
    <div id="box">
        <p style="background-color:yellow" id="content">CLICK ME !</p>
    </div>
</body>

</html>

Source: http://tecfa.unige.ch/guides/js/ex-intro/event-handler.html

La fonction start ajoute un gestionnaire d’événement au bouton my_para_button en utilisant la méthode addEventListener ("click", modifyText); . Le premier argument, "click", identifie le type d’événement, et le deuxième donne le nom de la fonction.

Veuillez noter que, grâce à l'ajoute du gestionnaire d'événement window.onload, le code JavaScript a pu être mis dans le head du document. En spécifiant cet événement, en effet, on force le navigateur à attendre que toute la page a été téléchargée et, par conséquent, les éléments HTML seront reconnus.

Une alternative : DOMContentLoaded

Il existe une alternative qui permet de déclencher du code JavaScript lorsque le DOM (et non pas tout le contenu de la fenêtre comme dans le cas de window.onload) a été chargé grâce à l'événement DOMContentLoaded (voir cette page sur MDN pour plus d'info) :

document.addEventListener("DOMContentLoaded", function(event) {
    console.log("Le DOM est disponible!");
});

document.addEventListener("DOMContentLoaded", function(event) {
    console.log("Je peux utiliser cette méthode une deuxième fois dans le même code!");
});

Veuillez noter que pour utiliser cet événement il faut utiliser le gestionnaire d'événements addEventListener(). Cette méthode de l'objet DOM se différencie de window.onload() également par le fait qu'on peut déclarer deux (ou plusieurs fois) cet listener dans des endroits différents du code et les deux événements seront considérés, à moins qu'il ne proposent pas des instructions contrastantes.

Événements liés à la souris

Parmi les événements les plus utilisés dans l'interaction avec le DOM, il y a sans doute les événements liés aux mouvements et clicks de la souris. Voici une liste non exhaustive de ces événements :

  • click : l'événement est déclenché avec un click de la souris
  • mouseover : l'événement est déclenché lorsque la souris passe sur l'élément
  • mouseout : l'événement est déclenché lorsque la souris quitte un élément
  • ...

Pour attribuer un événement à un élément il faut procéder ainsi :

  1. Identifier l'élément dans la structure du DOM (voir plus haut dans cette page)
  2. Spécifier un événement déclencheur à travers une des notations disponibles (e.g. document.getElementById("mon-bouton").onclick)
  3. Associer à cet événement un "event handler" (gestionnaire d'événement), c'est-à-dire le processus (normalement une fonction) qui doit se mettre en marche lorsque l'événement se produit

Il y a deux manières d'associer un événement à un élément :

  1. Utiliser la propriété de l'événement qui se compose de "on" + événement (élément.onclick, élément.onmouseover, élément.onmouseut, ...) à la quelle on associe une fonction :
       var myBtn = document.getElementById("theButtonId");
       myBtn.onclick = function () {
          console.log("The button has been clicked");
       }
    
  2. Utiliser la méthode addEventListener qui prévoit deux arguments : l'événement et la fonction à exécuter :
       var myBtn = document.getElementById("theButtonId");
       myBtn.addEvenetListener('click', function () {
         console.log("The button has been clicked");
       });
    

Dans les deux cas, la fonction associée au gestionnaire d'événements peut être :

  1. Une fonction anonyme (comme dans les exemples plus haut)
       var myDiv = document.getElementById("importantDiv");
       
       //version on->event
       myDiv.onmouseover = function() {
         console.log("The mouse of the user is over the importantDiv!");
       }
    
       //version addEventListener
       myDiv.addEventListener('mouseover', function () {
         console.log("The mouse of the user is over the importantDiv!");
       });
    
  2. Une fonction nommée
       var myDiv = document.getElementById("importantDiv");
       
       //Définir la fonction
       function doSomething() {
         console.log("The mouse of the user is over the importantDiv!");
       }
    
       //L'associer à la version on->event
       myDiv.onmouseover = doSomething; //Attention, pas de () ! Lire plus bas pour l'explication
    
       //L'associer à la version addEventListener
       myDiv.addEvenetListener('mouseover', doSomething); //Encore une fois sans () !
    
  3. Une méthode d'un objet
       var myDiv = document.getElementById("importantDiv");
    
       //Définir un objet avec une méthode
       var o = {};
       o.mouseOverHandler = function () {
         console.log("The mouse of the user is over the importantDiv!");
       }
    
       //L'associer à la version on->event
       myDiv.onmouseover = o.mouseOverHandler(); //Attention, cette fois ci avec les () !
      
       //L'associer à la version addEventListener
       myDiv.addEventListener('mouseover', o.mouseOverHandler()); //Encore une fois avec les () ! Faites attention aux double )) de clotûre.
    

La raison pour laquelle il ne faut pas utiliser les () pour une fonction nommée s'explique par le fait que avec les parenthèses la fonction serait exécutée dès que le code est lu, pas lorsque l'événement s'avère  :

function faireQuelqueChose() {
    //code
}
element.onevent = faireQuelqueChose; //OK!
element.onevent = faireQuelqueChose(); //Faux, de cette manière la fonction sera exécutée tout de suite, sans attendre l'événement déclencheur

Les objets, par contre, fonctionnent de manière différente : techniquement, on dit qu'ils sont passés par référence, mais la chose à retenir est tout simplement qu'avec les objets il faut mettre les parenthèses :

var o = {}: //Simule un objet quelconque
o.faireQuelqueChose = function () {
  //code qui détermine une méthode pour l'objet
}
element.onevent = o.faireQuelqueChose; //Faux!
element.onevent = o.faireQuelqueChose(); //OK!

Par rapport à la différence entre la version on->event et addEventListener, addEventListener a l'avantage de pouvoir s'ajouter à des gestionnaires d'événements déjà déclarés sur le même élément, sans les annuler (mais ne s'applique pas à window.onload). Voici un exemple pour illustrer ce principe qui se réfère au click sur un bouton :

<button id="myBtn">Button</button>
<script>
var myBtn = document.getElementById("myBtn");

//1. Utilisation de onclick
myBtn.onclick = function () {
  console.log("Événement 1");
}
myBtn.onclick = function () {
  console.log("Événement 2");
}

//-> Si on click sur myBtn, on verra dans la console seulement "Événement 2";

//2. Utilisation de addEventListener
myBtn.addEventListener("click", function () {
  console.log("Événement 1");
});
myBtn.addEventListener("click", function () {
  console.log("Événement 2");
});

//-> Si on click sur myBtn, cette fois-ci, on verra dans la console les deux messages.
</script>

Voici un exemple avec des commentaires pour résumer les différentes utilisations des événements liés à la souris :

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - événements liés à la souris</title>
</head>
<body>
  <h1>JavaScript - événements liés à la souris</h1>
  <button id="mon-bouton">Cliquez ici</button>
  <span id="feedback"></span>
  <script>
   //Déclarer une fonction en cas d'événement click
   function showFeedbackClick() {
     document.getElementById("feedback").innerHTML = "J'ai cliqué sur le bouton";
   }

   //Définir une fonction en cas d'événement mouseover
   function showFeedbackOver() {
     document.getElementById("feedback").innerHTML = "La souris se trouve sur le bouton";
   }

   //Identifier le bouton dans le DOM
   var monBouton = document.getElementById("mon-bouton");

   //Trois manières différentes d'associer une fonction à un événement :
   //1. Événement click avec association d'une fonction, sans ()!
   monBouton.onclick = showFeedbackClick
   //2. Événement mouseover avec méthode addEventListener();
   monBouton.addEventListener("mouseover", showFeedbackOver);
   //3. Événement mouseout avec fonction anonyme
   monBouton.onmouseout = function() {
     document.getElementById("feedback").innerHTML = "La souris n'est plus sur le bouton";
   }
  </script>
</body>
</html>

Tester cet exemple

Pour annuler un gestionnaire d'événement, vous pouvez :

  1. Affecter à null l'événement dans la version on->event
       var myBtn = document.getElementById("theButtonId");
       //Création du gestionnaire
       myBtn.onclick = function () {
         console.log("Je ne serais pas affiché");
       }
       //Annulation du gestionnaire
       myBtn.onclick = null;
    
  2. Utiliser la méthode removeEventListener() qui fonctionne exclusivement avec des fonctions nommées !
       var myBtn = document.getElementById("theButtonId");
       //Définir la fonction
       function logEvent() {
         console.log("Je ne serais pas affiché");
       }
       //Création du gestionnaire
       myBtn.addEventListener('click', logEvent);
       //Annulation du gestionnaire
       myBtn.removeEventListener('click', logEvent);
    

Comme pour la création des gestionnaires, la même différence s'applique : annuler la version on->event annule tous les événements qui sont associé, tandis que removeEventListener annule exclusivement l'exécution de la fonction particulière qui a été annulée.

L'objet event passé en argument

Lorsqu'on associe un gestionnaire d'événement, ce gestionnaire reçoit automatiquement l'objet event en tant qu'argument. On peut utiliser cet objet pour récupérer des informations utiles sur l'événement et/ou sur l'élément qui l'a déclenché. Par exemple, on peut attribuer un listener sur l'ensemble des clicks sur body, et récupérer des informations sur l'élément spécifique qui a été cliqué :

//Add a listener for clicks anywhere in the body
document.body.addEventListener("click", clickHandler);

//The listener receives the event object
function clickHandler(event) {
  //Retrieve the name of the tag clicked
  var tag = event.target.tagName;
  //Retrieve the content of the tag clicked
  var content = event.target.innerHTML;
  //Output some info about what has been clicked
  document.querySelector("#output").innerHTML += "You clicked on a " + tag + " with content <strong>" + content + "</strong><br>";
}

Imaginez maintenant d'avoir dans le body le code suivant :

...
<body>
<h1>The event argument/object</h1>
<p>Click over me<!</p>
<p>Or click over me!</p>
<button>Or even here</button> <button>Or finally here</button>
<hr>
<div id="output"></div>
</body>
...

Selon l'élément que vous cliquez dans la page, vous pouvez obtenir un output du type :

  • You clicked on a H1 with content The event argument/object
  • You clicked on a P with content Click over me
  • You clicked on a P with content Or click over me!
  • You clicked on a BUTTON with content Or even here
  • You clicked on a BUTTON with content Or finally here

Testez cet exemple

Bloquer les événements associées aux balises HTML

Certains balises HTML ont des comportements spécifiques associés. Par exemple si on clique sur l'élément a, le navigateur sera redirigé sur le lien correspondant à l'attribut href. JavaScript permet d'intercepter les comportements automatiques des balises et de les empêcher de se déclencher, à travers la notation event.preventDefault().

Voici un exemple avec deux liens qui pointent à l'home page de ce wiki, mais dont seulement le deuxième marchera "normalement". D'abord le code HTML :

<ul>
  <li>Prevented: <a id="prevented" href="http://edutechwiki.unige.ch/fr/Accueil">Go to EduTeckWiki (fr)</a>
  </li>
  <li>Normal : <a id="not-prevented" href="http://edutechwiki.unige.ch/fr/Accueil">Go to EduTeckWiki (fr)</a>
  </li>
</ul>

Et ensuite le code JavaScript qui permet de bloquer le comportement normal du premier lien.

//Prevented
document.getElementById("prevented").onclick = function(event) {
  //Prevent the default link behavior
  event.preventDefault();
  //Change the text of the link
  this.innerHTML = "JavaScript intercepted the normal event and prevented it!"
};

On utilise souvent la méthode preventDefault() pour éviter que la page soit rechargée, notamment avec les formulaires. Ceci permet de garder la session de la page active et donc de maintenir toutes les informations et manipulations de l'utilisateur au niveau client.

L'élément this dans le DOM

Lorsqu'une fonction est associée à un élément du DOM, cet élément est disponible à l'intérieur de la fonction elle-même, à travers l'élément this. Ceci permet de ne pas avoir à identifier à nouveau l'élément dans le DOM. Voici un exemple qui modifie le label d'un bouton et le désactive après le click :

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - this</title>
</head>
<body>
  <h1>JavaScript - this</h1>
  <button id="mon-bouton">Cliquez ici</button>
  <script>
    var monBouton = document.getElementById("mon-bouton");
    monBouton.onclick = function() {
      //Changer le label du bouton
      this.innerHTML = "J'ai cliqué sur le bouton";
      //Désactiver le bouton
      this.disabled = "disabled";
    } 
  </script>
</body>
</html>

L'élément this peut être très utile lorsqu'on genère plusieurs éléments dynamiquement pour associer un comportement à chaque élément. Voici un exemple similaire au précédent, mais dans lequel 5 boutons sont créés avec la fonction document.createElement("button"). Chaque bouton créé est associé ensuite à un événement de type onclick, à l'intérieur du quel on fait référence au bouton avec l'élément this :

var list = document.getElementById("btnList");
for(var i = 1; i <= 5; i++) {
  var btn = document.createElement("button");
  btn.innerText = "Cliquez sur le bouton " + i;
  btn.onclick = function () {
    this.innerText = "J'ai cliqué sur ce bouton";
    this.disabled = "disabled";
  }
  list.appendChild(btn);
}

Tester cet exemple et l'exemple précédent

JavaScript et CSS

Utiliser les propriétés de style

Javascript permet de modifier non seulement la structure du DOM, mais également les propriétés de style des éléments. Il est possible de modifier toutes les déclarations de style disponibles dans un fichier CSS à travers la notation :

élément.style.propriété = "nouvelle valeur";

Par exemple le code suivant modifie la couleur du texte d'un élément du DOM avec id="mon-paragraphe" :

document.getElementById("mon-paragraphe").style.color = "#F00";

Les changements de style peuvent être appliqués à tout moment dans le code et être donc associés, par exemple, à des événements (voir plus haut dans la page).

En considération du fait que les noms des propriétés des objets en JavaScript ne peuvent pas contenir le caractère -, toutes les propriétés CSS qui prévoient ce diviseur doivent être modifiées en "camel case", e.g :

  • background-color --> élément.style.backgroundColor
  • border-color --> élément.style.borderColor
  • font-size --> élément.style.fontSize
  • ...

En alternative vous pouveez utiliser la notation type array : élément.style["background-color"]

Utiliser les classes

JavaScript permet également de manipuler les noms de class des éléments. La manière la plus simple consiste à utiliser la propriété className pour lire ou définir la class d'un élément :

//Lire
var maClasse = élément.className; // --> e.g. active
//Définir
élément.className = 'active'

Il faut noter que la propriété className se réfère à tout l'attribut HTML. Voici un élément HTML qui a plusieurs classes :

<div id="myDiv" class="class1 class2 class3">Mon div</div>

Et voici le résultat de quelques opérations avec JavaScript

var myDiv = document.getElementById("myDiv");
var classes = myDiv.className; // --> class1 class2 class3
//Ajouter une quatrième class
myDiv.className = classes + " class4"; // --> class1 class2 class3 class4
//Remplacer avec une seule class
myDiv.className = "class99"; --> class99

Pour faciliter la gestion de plusieurs classes sur le même élément, JavaScript met à disposition la propriété classList qui possède plusieurs méthodes (voir la liste complète) parmi lesquelles on trouve :

  • élément.classList.add(class, [class]) : permet d'ajouter une ou plusieurs nouvelles classes à l'élément
  • élément.classList.remove(class, [class]) : permet d'enlever une ou plusieurs classes à l'élément

Les deux codes suivants sont donc équivalents :

var myDiv = document.getElementById("myDiv");

//Avec className
var classes = myDiv.className; // --> class1 class2 class3
myDiv.className = classes + " class4"; // --> class1 class2 class3 class4

//Avec classList
myDiv.classList.add("class4"); // --> class1 class2 class3 class4

Une autre méthode utile associée à la propriété classList est la méthode toggle() qui :

  1. Ajoute une classe si la classe n'est pas associée à l'élément
  2. Enlève une classe si la classe est déjà associée à l'élément

Tester un exemple

JavaScript et les formulaires

Même si JavaScript ne se limite plus simplement à ces tâches, la manipulation des formulaires et des éléments des formulaires (e.g. champs de texte, etc.) restent des fonctionnalités très utilisées (et utiles). JavaScript peut en effet identifier le contenu des éléments des formulaires et utiliser se contenu dans sa logique de programmation pour apporter des changements à la page. Par exemple la propriété .value permet d'identifier le contenu d'un champ de texte :

var maValeur = document.getElementById("mon-champ-de-texte").value;

Cette notation, comme toute propriété, peut être utilisé aussi pour modifier le contenu d'un champ.

window.onload = function() {
    document.getElementById("mon-champ-de-texte").value = "Nouvelle valeur";
}

Voici un exemple qui utilise l'événement onchange pour suggérer une valeur combiné du prénom et nom d'une personne. Si le champ complet est modifié, néanmoins, aucune suggestion ne sera plus faite.

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - formulaires</title>
</head>
<body>
<h1>JavaScript - formulaires</h1>
Prénom : <input type="text" id="prenom"><br>
Nom : <input type="text" id="nom"><br>
Nom complet : <input type="text" id="nom-complet"><br>
<script>
  var prenom = document.getElementById("prenom");
  var nom = document.getElementById("nom");
  var nomComplet = document.getElementById("nom-complet");
  function suggererNomComplet() {
    nomComplet.value = nom.value + ", " + prenom.value;
  }
  prenom.onchange = suggererNomComplet;
  nom.onchange = suggererNomComplet;
  nomComplet.onchange = function() {
    prenom.onchange = null;
    nom.onchange = null;
  }
</script>
</body>
</html>

Tester cet exemple

Validation des formulaires

Un autre cadre d'utilisation de JavaScript concerne la validation des formulaires avant qu'ils soient soumis au serveur (i.e. avec actualisation de la page). Cette fonction est désormais partiellement prise en charge par les attributs HTML5 tels que "required", mais il y néanmoins des validations plus complexes qui nécessitent du codage JavaScript.

Dans la structure du DOM, JavaScript peut identifier des champs d'un formulaire de plusieurs manières. On peut utiliser la méthode getElementById() et attribuer à chaque champ un id univoque, ce qui est probablement la manière plus sûre. Sinon, JavaScript identifie les formulaires et ses champs à travers un Array qui se construit sur l'attribut name du formulaire et des champs :

 <form name="mon-formulaire">
     <input type="texte" name="mon-champ1">
     <input type="texte" name="mon-champ2">
 </form>

Le form peut être identifié à travers la notation document.forms['mon-formulaire'] tandis que les champs respectivement avec :

  • document.forms['mon-formulaire']['mon-champ1']
  • document.forms['mon-formulaire']['mon-champ2'].

Il est également possible d'utiliser la notation "par point", au lieu des parenthèses carrées, si le nom du champ respecte la notation correcte pour les variables JavaScript.

Voici un simple exemple de validation pour montrer brièvement le mécanisme. Le code JavaScript contrôle que le champ email ne soit pas vide et que les conditions ont été acceptées à travers la checkbox.

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript - formulaires</title>
</head>
<body>
<h1>JavaScript - formulaires</h1>
<form name="mon-formulaire" method="post" action="/submit">
  Email : <input name="email" type="text"><br>
  <input type="checkbox" name="conditions"> J'accepte les conditions d'inscription<br>
  <input type="submit" value="Envoyer">
</form>
<script>
  var monForm = document.forms["mon-formulaire"];
  var monEmail = monForm["email"];
  var mesConditions = monForm["conditions"];
  monForm.onsubmit = function() { 
    if (monEmail.value !== "" && mesConditions.checked) {
      //Le formulaire sera soumis au serveur et la page actualisée
      return true; 
    } else {
      window.alert("Vous devez insérer votre email et accepter les conditions");
      //Le retour false fait que le formualire n'est pas soumis et la page pas actualisée
      return false;
    }
  }
</script>
</body>
</html>

La sécurité avec JavaScript

La sécurité en JavaScript n'est pas à négliger car de nombreux exploits existent et sont assez facilement mis en place. Avant de commencer à lire ce qui suit, il est important de savoir que le JavaScript est interprété du coté de la machine du client (et non pas du coté du serveur).

Pourquoi il ne faut pas faire confiance à Javascript si vous êtes propriétaire d’un site web

Pour comprendre, il suffit de regarder cet exemple qui peut être trouvé sur le site de certains novices.

Exemple :

  function Login(){
            var password=document.login.password.value;
            if (password=="kztYq8") {
                window.location="bravo.htm";
            }
            else
            {
                window.location="dommage.htm";
            }
        }

Vous l'aurez compris, le mot de passe est défini en clair dans le code source de la page. Tout le monde y a accès. L'URL censée être protégée par le mot de passe est aussi disponible et accessible sans le mot de passe! Ayez toujours en tête que ce que vous écrivez en javascript est accessible à tout le monde.

Vérifier du côté client et du côté serveur

Ce qu'on a vérifié du coté client avec le JavaScript n'est pas fiable et doit être revérifié du coté serveur (avec du PHP par exemple). En effet, en désactivant simplement le JavaScript, on peut passer outre les contrôles d'un formulaire.

Attaques de Cross-site scripting (XSS)

Lors de la création d'une application ou d'un site avec JavaScript, il faut savoir que les attaques XSS existent et sont encore couramment utilisées. En résumé, l'attaque consiste à injecter des scripts dans la réponse d'une application, ce qui permet de récupérer les données sensibles de l'application et de les envoyer sur le serveur de la personne qui est à l'origine de l'attaque. Il existe deux types d'attaque XSS:

La reflectected XSS (non permanente) : L'attaquant injecte des scripts dans une application web pour que ceux-ci soient exécutés du coté client. L'attaque n'est pas stockée dans l'application et ne laisse aucune trace sur le serveur. Pour exploiter cette faille (XSS), l'ingénierie sociale doit être utilisée afin de tromper la "future" victime. L'attaquant va fournir une URL piégée à sa victime (via mail par exemple), lorsque la victime clique sur l'URL piégée, une requête contenant du code malicieux (scripts) est envoyé vers le serveur (officiel). Le code malveillant va alors s'exécuter sur la page renvoyé par le serveur (officiel), ce qui donne à l'attaquant le contrôle dessus. Celui-ci pourra ensuite, à partir de l'application, récupérer des données sur la victime, comme par exemple sa session ou ses cookies et les recevoir directement sur son serveur. Cela lui permettra de réaliser des actions au nom de l'utilisateur ou de lui voler des informations privées.

Exemple vidéo (anglais) : ICI

La persistent XSS (permanente) : Contrairement au premier type d'attaque, celle-ci consiste à injecter le code malicieux directement dans le système de stockage de l'application Web. Pour que la faille puisse être exploitée, l'application doit générer ses réponses via ces données stockées. Elle est souvent utilisée sur des forums qui sont mal sécurisés. Ceux-ci stockent les messages des utilisateurs dans des bases de donnée. Si un message contient un code malicieux, à chaque fois qu'un utilisateur affichera la page du forum contenant le message qui présente le code malicieux, celui-ci sera exécuté. Cette attaque est donc beaucoup plus dévastatrice puisqu'elle touche potentiellement tous les utilisateurs.

Exemple vidéo (anglais) : ICI

Comment se protéger contre les attaques XSS

Il existe plusieurs moyens de se protéger, la NSA a d'ailleurs rédigé un bon document à ce propos.

Afin d'éviter que des personnes malveillantes puissent injecter du code malveillant, les administrateurs réseaux doivent traiter les informations que les personnes envoient, une fois qu'elles sont parvenues au serveur et les retraiter lors de leur envoi au navigateur. Des fonctions PHP existent afin de traiter les données envoyées via JavaScript comme "htmlentities", qui convertit tous les caractères éligibles en entités HTML et strip_tags, qui suppriment les balises HTML et PHP d'une chaîne. L'une dans l'autre permet déjà une protection de base efficace (mais pas infaillible) contre ce genre d'attaque qui exploite le JavaScript. Des mesures supplémentaires peuvent être mises en place comme l'utilisation de pare-feux applicatifs qui détectent les informations suspectes envoyées au serveur. Du coté des utilisateurs, il ne faut jamais cliquer sur un lien dont la provenance est douteuse et toujours accéder aux sites via l'URL officielle. Ils peuvent aussi utiliser des extensions comme par exemple "NoScript" sur Firefox, qui offre une bonne protection de base contre ce genre de vulnérabilité.

Références

Bibliographie