« Interactivité avec JavaScript » : différence entre les versions

De EduTech Wiki
Aller à la navigation Aller à la recherche
mAucun résumé des modifications
(44 versions intermédiaires par 6 utilisateurs non affichées)
Ligne 1 : Ligne 1 :
{{En construction}}
{{tutoriel
 
|fait_partie_du_cours=Initiation à la pensée computationnelle avec JavaScript
|fait_partie_du_module=Concepts de base de JavaScript
|module_suivant=JavaScript dans le navigateur
|pas_afficher_sous-page=Non
|page_precedente=Computation avec JavaScript
|page_suivante=JavaScript dans le navigateur
|statut=à finaliser
|difficulté=débutant
|voir_aussi=Tutoriel JavaScript côté client
|cat tutoriels=JavaScript
}}
== Introduction ==
== Introduction ==


Bien que [[JavaScript]] soit désormais un langage de programmation multi-purpose utilisé pour créer différents types d'applications, sa fonction primaire et la raison principale pour laquelle ce langage est aussi répandu concernent l'interactivité des pages web, ce qu'on appelle [[Tutoriel JavaScript côté client|JavaScript côté-client]].
Bien que [[JavaScript]] soit désormais un langage de programmation multi-purpose utilisé pour créer différents types d'applications, sa fonction primaire et la raison principale pour laquelle ce langage est aussi répandu concernent l'interactivité des pages web, ce qu'on appelle [[Tutoriel JavaScript côté client|JavaScript côté-client]].


Cette page complémente le [[Tutoriel JavaScript de base]] et le [[Tutoriel JavaScript côté client]] avec une approche plus ciblée sur l'interactivité qui est possible grâce à l'intégration entre JavaScript et le navigateur web. Plutôt que proposer un survol des aspects principaux, cette page illustre de manière plus approfondie et détaillée des examples de base pour mettre en relief le fonctionnement de l'interactivité à la fois d'un point de vue conceptuel et technique.
Cette page complémente le [[Tutoriel JavaScript de base]] et le [[Tutoriel JavaScript côté client]] avec une approche plus ciblée sur l'interactivité qui est possible grâce à l'intégration entre JavaScript et le navigateur web. Plutôt que proposer un survol des aspects principaux, cette page illustre de manière plus approfondie et détaillée des exemples de base pour mettre en relief le fonctionnement de l'interactivité à la fois d'un point de vue conceptuel et technique.


=== Prérequis ===
=== Prérequis ===


Pour lire cet article des connaissances de base de [[HTML5]] et [[CSS]] sont nécessaires. Il faut également des notions sur les [[Introduction à la programmation|éléments fondamentaux de la programmation]] et la syntaxe de base de [[JavaScript]] (e.g. variables, fonctions, etc. - voir [[Tutoriel JavaScript de base]]).
Pour lire cet article des connaissances de base de [[HTML5]] et [[CSS]] sont nécessaires. Pour des novices en JavaScript, nous conseillons d'abord de suivre le tutoriel :
 
* {{Goblock | [[Premiers pas avec JavaScript]] }}
 
L'article propose également certains aspects computationnels qui nécessite une compréhension du fonctionnement du langage JavaScript. Une lecture des parties introductives des pages [[computation avec JavaScript]] et [[tutoriel JavaScript de base]] pourrait également être utile, mais n'est pas nécessaire.


=== Exemples traités dans l'article ===
=== Exemples traités dans l'article ===
Ligne 19 : Ligne 33 :
* {{Goblock|[https://github.com/MALTT-STIC/stic-1-interaction-with-js Repository MALTT-STIC/stic-1-interaction-with-js]}} pour télécharger les fichiers ou voir le code source complet.
* {{Goblock|[https://github.com/MALTT-STIC/stic-1-interaction-with-js Repository MALTT-STIC/stic-1-interaction-with-js]}} pour télécharger les fichiers ou voir le code source complet.


Lorsque le code des exemples est expliqué dans l'article, pour des raisons d'espace, souvent seulement les parties indispensables à la compérhension du concept expliqué seront affichés. En général, les numéros des lignes intéressées sera fourni pour pouvoir repérer le code dans les fichiers, par exemple <code>00-01 Lignes 10-20</code>.
Lorsque le code des exemples est expliqué dans l'article, pour des raisons d'espace, souvent, seulement les parties indispensables à la compréhension du concept expliqué seront affichées. En général, les numéros des lignes intéressées sera fourni pour pouvoir repérer le code dans les fichiers, par exemple <code>00-01 Lignes 10-20</code>.
 
=== Présentation interactive ===
 
Une présentation interactive qui peut servir d'introduction et/ou synthétise des éléments traités dans cet article est disponible :
 
* {{Goblock | [https://mafritz.ch/slides/fr/interactivite-avec-js/ Présentation de l'interactivité avec JavaScript]}}


== Définition d'interactivité ==
== Définition d'interactivité ==


[[Fichier:Interactivité avec JavaScript composantes.png|500px|vignette|droite|Trois caractéristiques d'une application interactive qui utilise une interface utilisateur.]]Malgré l'utilisation répandue du terme interactivité, il n'existe pas une définition unanime qui peut être appliquée dans les nombreux domaines dans lequel ce mot est utilisé. En général, il y a un certain accord, surtout dans le domaine de l'interaction homme-machine, à considérer l'interactivité en relation avec une '''interface utilisateur''' : une application est interactive du moment qu'elle permet à l'utilisateur, à travers des éléments identifiables sur l'interface et/ou des gestes à exécuter sur des périphériques (clavier, souris, écran tactile, ...), d'intervenir activement sur l'état de l'application. En termes plus simples, une application peut être considérée interactive si l'utilisateur peut de quelque sorte la modifier en fonction de ses propres actions.
[[Fichier:Interactivité avec JavaScript composantes svg.svg|500px|vignette|droite|Trois caractéristiques d'une application interactive qui utilise une interface utilisateur.]]Malgré l'utilisation répandue du terme interactivité, il n'existe pas une définition unanime qui peut être appliquée dans les nombreux domaines dans lequel ce mot est utilisé. En général, il y a un certain accord, surtout dans le domaine de l'interaction homme-machine, à considérer l'interactivité en relation avec une '''interface utilisateur''' : une application est interactive du moment qu'elle permet à l'utilisateur, à travers des éléments identifiables sur l'interface et/ou des gestes à exécuter sur des périphériques (clavier, souris, écran tactile, ...), d'intervenir activement sur l'état de l'application. En termes plus simples, une application peut être considérée interactive si l'utilisateur peut de quelque sorte la modifier en fonction de ses propres actions.


Cette définition entraîne une série de conséquences conceptuelles et techniques qui dépassent l'objectif de cette page et qui concernent le vaste domaine de l'interaction homme-machine et l'expérience utilisateur. Néanmoins, d'un point de vue logique, cette définition comporte aux moins trois inferences qui seront utiles pour le reste de l'article. Ces inferences se réfèrent à l'état d'une application (ce qu'en anglais on appelle ''state''). Pour faciliter la compréhension de ce concept, imaginez tout simplement de faire une capture d'écran à différents moments lorsque vous utilisez une application ou un site web. Chaque fois que vous avez une image différente, vous avez un état différent de l'application. Voici donc les trois inferences :
Cette définition entraîne une série de conséquences conceptuelles et techniques qui dépassent l'objectif de cette page et qui concernent le vaste domaine de l'interaction homme-machine et l'expérience utilisateur. Néanmoins, d'un point de vue logique, cette définition comporte aux moins trois inférences qui seront utiles pour le reste de l'article. Ces inférences se réfèrent à l'état d'une application (ce qu'en anglais on appelle ''state''). Pour faciliter la compréhension de ce concept, imaginez tout simplement de faire une capture d'écran à différents moments lorsque vous utilisez une application ou un site web. Chaque fois que vous avez une image différente, vous avez un état différent de l'application. Voici donc les trois inférences :


# '''L'interactivité présuppose le concept de variabilité'''
# '''L'interactivité présuppose le concept de variabilité'''
#: Si l'état à un moment donné de l'application dépend de l'activité (ou non activité) de l'utilisateur, cela implique que '''l'application ''peut être différente'' de ce qu'elle est maintenant'''. Le plus une application est interactive, le plus d'états différents elle peut avoir à un moment donné suite aux décisions/interactions de l'utilisateur et/ou les états possibles envisagés par le concepteur.
#: Si l'état à un moment donné de l'application dépend de l'activité (ou non activité) de l'utilisateur, cela implique que '''l'application ''peut être différente'' de ce qu'elle est maintenant'''. Le plus une application est interactive, le plus d'états différents elle peut avoir à un moment donné suite aux décisions/interactions de l'utilisateur et/ou les états possibles envisagés par le concepteur.
#:
# '''L'interactivité est liée à des événements'''
# '''L'interactivité est liée à des événements'''
#: Le concept de variabilité des états d'une application implique des changements qui se manifestent à des moments spécifiques, notamment suite aux actions de l'utilisateur. En informatique, les éléments responsables des changements dans l'état d'une application sont regroupés sous le terme de '''événements'''. De manière formelle, on peut définir un événements avec la formule '''Si <code>''p''</code> alors <code>''q''</code>''', ce qui correspond à '''Pour que <code>''q''</code> s'avère, il faut que <code>''p''</code> se passe d'abord'''.
#: Le concept de variabilité des états d'une application implique des changements qui se manifestent à des moments spécifiques, notamment suite aux actions de l'utilisateur. En informatique, les éléments responsables des changements dans l'état d'une application sont regroupés sous le terme de '''événements'''. De manière formelle, on peut définir un événements avec la formule '''Si <code>''p''</code> alors <code>''q''</code>''', ce qui correspond à '''Pour que <code>''q''</code> s'avère, il faut que <code>''p''</code> se passe d'abord'''.
#:
# '''L'interactivité défère le contrôle à l'utilisateur'''
# '''L'interactivité défère le contrôle à l'utilisateur'''
#: Parmi tous les événements possibles qui génèrent des changements dans l'état de l'application, pour qu'une application puisse être considérée interactive, '''il faut qu'au moins une partie de ces événements soient ''sous le contrôle directe'' de l'utilisateur'''. Le plus une application est interactive, le plus de contrôle l'utilisateur a sur les événements qui peuvent modifier l'application.
#: Parmi tous les événements possibles qui génèrent des changements dans l'état de l'application, pour qu'une application puisse être considérée interactive, '''il faut qu'au moins une partie de ces événements soient ''sous le contrôle direct'' de l'utilisateur'''. Le plus une application est interactive, le plus de contrôle l'utilisateur a sur les événements qui peuvent modifier l'application.


{{bloc important | '''En résumé''' : une application interactive nécessité d'une certaine variabilité, déterminée par exemple par une série d'événements possibles, dont au moins certains sont sous le contrôle directe de l'utilisateur.}}
{{bloc important | '''En résumé''' : une application interactive nécessité d'une certaine variabilité, déterminée par exemple par une série d'événements possibles, dont au moins certains sont sous le contrôle directe de l'utilisateur.}}


=== La structure d'une interaction  ===
=== La structure d'une interaction  ===
[[Fichier:Interactivité avec JavaScript - structure of an interaction svg.svg|400px|vignette|droite|Structure d'une interaction, adaptation de [http://microinteractions.com/what-is-a-microinteraction/ What is a microinteraction] de Saffer (2014)]]
Dans cet article, nous allons nous focaliser sur des interactions simples d'un point de vue technique et qui ne nécessitent qu'une manipulation limitée de l'utilisateur. Saffer (2014) qualifie ce type d'interaction en tant que '''micro-interaction''' et il les définit ainsi :


Dans cet article, nous allons nous focaliser sur des interactions simples d'un point de vue technique et qui nécessitent d'une manipulation limitée de l'utilisateur. Saffer (2014) qualifie ce type d'interaction en tant que '''micro-interactions''' et il les définit ainsi :
{{citation | Microinteractions differ from features in both their size and scope. Features tend to be complex (multiuse case), time consuming, and cognitively engaging. Microinteractions on the other hand are simple, brief, and should be nearly effortless. A music player is a feature; adjusting the volume is a microinteraction inside that feature. }} (Saffer, 2014, p. 5)  


{{ citation | Microinteractions differ from features in both their size and scope. Features tend to be complex (multiuse case), time consuming, and cognitively engaging. Microinteractions on the other hand are simple, brief, and should be nearly effortless. A music player is a feature; adjusting the volume is a microinteraction inside that feature. (Saffer, 2014, p. 5 }}
Cette définition pourrait tout à fait convenir à nos objectifs, si ce n'est que, en ayant des (petites) applications interactives avec finalité pédagogique comme objectif de développement, nos ''micro-interactions'' peuvent requérir un effort cognitif même maximal, par exemple, si l'apprenant doit réfléchir intensivement pour décider quelle réponse sélectionner. Peters (2014) résume parfaitement ce concept en paraphrasant le "Don't make me think" de Steve Krug (2006) lorsqu'il écrit :


Cette définition pourrait tout à fait convenir à nos objectifs si ce n'est pour le fait que, en ayant des (petites) applications interactives avec finalité pédagogique comme objectif de développement, nos ''micro-interactions'' peuvent requérir un effort cognitif même maximal, psr exemple si l'apprenant doit réfléchir intensivement pour décider quelle réponse sélectionner. Peters (2014) résume parfaitement ce concept en paraphrasant le "Don't make me think" de Steve Krug (2006) lorqu'il écrit :
{{citation | Don't make me think about the interface, because I need to be thinking abouthe the learning. }}  (Peters, 2014)  


{{ citation | Don't make me think about the interface, because I need to be thinking abouthe the learning. (Peters, 2014) }}
La simplicité de la micro-interaction est donc relative, dans l'exemple précédent, à la facilité de lire et comprendre la question d'abord, et d'identifier et exécuter facilement l'action pour sélectionner la réponse sur l'interface ensuite. Une fois spécifiée cette distinction importante, nous pouvons utiliser [http://microinteractions.com/what-is-a-microinteraction/ la structure d'une micro-interaction] proposée par Saffer (2014, p.14). Saffer propose quatre composantes :
 
La simplicité de la micro-interactions est donc relative, dans l'exemple précédent, à la facilité de lire et comprendre la question d'abord, et ensuite d'identifier et exécuter facilement l'action pour sélectionner la réponse sur l'interface. Une fois spécifié cette distinction importante, nous pouvons utiliser [http://microinteractions.com/what-is-a-microinteraction/ la structure d'une micro-interaction] proposée par Saffer (2014, p.14). Saffer propose quatre composantes :


# '''''Trigger'''''
# '''''Trigger'''''
Ligne 56 : Ligne 74 :
#: Elles déterminent le comportement de l'application suite à l'événement déclencheur, l'équivalent formel de '''Alors <code>''q''</code>'''
#: Elles déterminent le comportement de l'application suite à l'événement déclencheur, l'équivalent formel de '''Alors <code>''q''</code>'''
# '''''Feedback'''''
# '''''Feedback'''''
#: Il détermine les conséquences du comportement de l'application sur l'interface utilisateur en termes de changements perceptibles par l'utilisateur. Il faut comprendre le terme feedback au sens large, pas strictement pédagogiques. Un feedback interactif peut être tout simplement le curseur de la souris qui bouge lorsqu'on déplace physiquement la périphérique avec la main, ou les lettres qui s'affichent dans un champ de texte lorsqu'elles sont saisies au clavier.  
#: Il détermine les conséquences du comportement de l'application sur l'interface utilisateur en termes de changements perceptibles par l'utilisateur. Il faut comprendre le terme feedback au sens large, pas strictement pédagogique. Un feedback interactif peut être tout simplement le curseur de la souris qui bouge lorsqu'on déplace physiquement le périphérique avec la main, ou les lettres qui s'affichent dans un champ de texte lorsqu'elles sont saisies au clavier.  
#:
#:
# '''''Loops and Modes'''''
# '''''Loops and Modes'''''
#: Saffer ajoute une quatrième composante à sa structure d'une micro-interactions que nous ne verrons cependant pas dans le détail. En synthèse, il s'agit de l'effet que la micro-interactions a eu sur l'ensemble de l'application.
#: Saffer ajoute une quatrième composante à sa structure d'une micro-interaction que nous ne verrons cependant pas dans le détail. En synthèse, il s'agit de l'effet que la micro-interaction a eu sur l'ensemble de l'application.


Nous proposons donc une version adaptée de la structure qui se compose des premiers trois éléments et qui est représentée par l'image suivante :
Nous proposons donc une version adaptée de la structure qui se compose des premiers trois éléments et qui est représentée par l'image sur la droite.


[[Fichier:Interactivité avec JavaScript - structure of an interaction.png|700px|vignette|néant|Structure d'une interaction, adaptation de [http://microinteractions.com/what-is-a-microinteraction/ What is a microinteraction] de Saffer (2014)]]
{{bloc important | Structurellement, une interaction se compose (1) d'un élément déclencheur qui est associé à (2) des règles de comportement de l'application. Ces règles déterminent (3) les changements sur l'interface utilisateur qui informent l'utilisateur du résultat de l'interaction. }}


{{ bloc important | Structurellement, une interaction se compose (1) d'un élément déclencheur qui est associé à (2) des règles de comportement de l'application. Ces règles déterminent (3) les changements sur l'interface utilisateur qui informent l'utilisateur du résultat de l'interaction. }}
== Principe technique de l'interactivité avec JavaScript ==
[[Fichier:DOM html exemple avec couleurs svg.svg|400px|vignette|droite|Le [[Document Object Model]] (DOM) d'une page web]]


== Principe technique de l'interactivité avec JavaScript ==
Dans une page web, l'interface utilisateur est représentée par le [[Document Object Model]] (DOM), c'est-à-dire la représentation en forme d'arborescence des noeuds/ balises HTML. Lorsque le navigateur télécharge une page web, il utilise le code source de cette page pour construire le DOM et l'afficher à l'écran en fonction d'éventuelles propriétés CSS qui déterminent le style des éléments HTML.  
[[Fichier:DOM html exemple avec couleurs.png|400px|vignette|droite|Le [[Document Object Model]] (DOM) d'une page web.]]
Dans une page web, l'interface utilisateur est représenté par le [[Document Object Model]] (DOM), c'est-à-dire la représentation en forme d'arborescence des noeuds/ balises HTML. Lorsque le navigateur télécharge une page web, il utilise le code source de cette page pour construire le DOM et l'afficher à l'écran en fonction d'éventuelles propriétés CSS qui déterminent le style des éléments HTML.  


Or, dans une page web non dynamique, le code source qui est téléchargé n'a pas de variabilité potentielle, si ce n'est pour le fait que l'utilisateur peut pointer sur une autre page et donc répéter le même mécanisme de génération du DOM à partir de nouveau code source. Au contraire, si le code source de la page téléchargé contient des scripts JavaScript, alors ces scripts peuvent fournir au navigateurs les instructions nécessaires pour modifier le DOM et, par reflet, l'interface utilisateur.   
Or, dans une page web non dynamique, le code source qui est téléchargé n'a pas de variabilité potentielle, si ce n'est que l'utilisateur peut pointer sur une autre page et donc répéter le même mécanisme de génération du DOM à partir de nouveau code source. Au contraire, si le code source de la page téléchargée contient des scripts JavaScript, alors ces scripts peuvent fournir au navigateur les instructions nécessaires pour modifier le DOM et, par reflet, l'interface utilisateur.   


Voici de suite trois pages similaires qui expliquent ce concept à l'aide des trois inferences introduites plus haut. À ce stade il ne faut comprendre leur code, mais plutôt le concept. Ouvrez les outils développeurs de votre navigateur et choisissez l'option qui vous permet de voir la représentation actuelle du DOM (pour Google Chrome cliquez sur '''F12''' et puis sur le tab '''Elements'''). Comparez le code que vous voyez avec le code source de la page (en Chrome clique droit > Afficher le code source de la page).
Voici de suite trois pages similaires qui expliquent ce concept à l'aide des trois inférences introduites plus haut. À ce stade il ne faut pas comprendre leur code, mais plutôt le concept. Ouvrez les outils développeurs de votre navigateur et choisissez l'option qui vous permet de voir la représentation actuelle du DOM (pour Google Chrome cliquez sur '''F12''' et puis sur le tab '''Elements'''). Comparez le code que vous voyez avec le code source de la page (en Chrome clique droit > Afficher le code source de la page).


# '''[https://maltt-stic.github.io/stic-1-interaction-with-js/00-dom/00-01-dom-no-script.html Page sans variabilité]''' <code>00-01</code>
# '''[https://maltt-stic.github.io/stic-1-interaction-with-js/00-dom/00-01-dom-no-script.html Page sans variabilité]''' <code>00-01</code>
#: Il n'y a aucune différence (si ce n'est pour quelques détails marginaux) entre le code source et la représentation du DOM. Vous pouvez essayer de cliquer à différents endroits dans la page, mais aucune interactivité va se passer si ce n'est pour des comportements standard du navigateur (e.g. sélectionner du texte). L'interface utilisateur de cette page va rester la même jusqu'au moment où l'utilisateur ferme la page ou pointe vers une autre adresse.
#: Il n'y a aucune différence (si ce n'est pour quelques détails marginaux) entre le code source et la représentation du DOM. Vous pouvez essayer de cliquer à différents endroits dans la page, mais aucune interactivité ne va se passer, si ce n'est des comportements standards du navigateur (e.g. sélectionner du texte). L'interface utilisateur de cette page va rester la même jusqu'au moment où l'utilisateur ferme la page ou pointe vers une autre adresse.
#:
#:
# '''[https://maltt-stic.github.io/stic-1-interaction-with-js/00-dom/00-02-dom-timer-script.html Page avec variabilité liée à un événement temporel]''' <code>00-02</code>
# '''[https://maltt-stic.github.io/stic-1-interaction-with-js/00-dom/00-02-dom-timer-script.html Page avec variabilité liée à un événement temporel]''' <code>00-02</code>
#: Avec la page, vous téléchargez un script avec l'instruction d'afficher un nouveau paragraph chaque 5 seconds. Vous pouvez noter comme à des intervalles régulières, un nouveau noeud <code><nowiki><p>...</p></nowiki></code> s'ajouter à l'intérieur du <code><nowiki><div id="injectTarget>...</div></nowiki></code> qui, au départ, ne contient qu'un seul paragraphe. Ce type de variabilité n'est pas intéressante du tout et, surtout, est hors du contrôle de l'utilisateur qui ne peut pas arrêter le script si ce n'est en fermant la page ou pointant vers une autre adresse.
#: Avec la page, vous téléchargez un script avec l'instruction d'afficher un nouveau paragraphe toutes les 5 secondes. Vous pouvez noter comme à des intervalles réguliers, un nouveau noeud <code><nowiki><p>...</p></nowiki></code> s'ajouter à l'intérieur du <code><nowiki><div id="injectTarget>...</div></nowiki></code> qui, au départ, ne contient qu'un seul paragraphe. Ce type de variabilité n'est pas intéressante du tout et, surtout, est hors du contrôle de l'utilisateur qui ne peut pas arrêter le script si ce n'est en fermant la page ou pointant vers une autre adresse.
#:
#:
# '''[https://maltt-stic.github.io/stic-1-interaction-with-js/00-dom/00-03-dom-user-script.html Page avec variabilité liée à un événement déclenché par l'utilisateur]''' <code>00-03</code>
# '''[https://maltt-stic.github.io/stic-1-interaction-with-js/00-dom/00-03-dom-user-script.html Page avec variabilité liée à un événement déclenché par l'utilisateur]''' <code>00-03</code>
Ligne 86 : Ligne 103 :
Selon la définition de l'interactivité suggérée dans cet article, seulement la troisième page répond aux trois critères nécessaires :
Selon la définition de l'interactivité suggérée dans cet article, seulement la troisième page répond aux trois critères nécessaires :


# La page présente de la variabilité, avec potentiellement un nombre d'état "différents" infini. Bien entendu, d'un point de vue utilisateur, les états ne diffèrent pas vraiment, car on ajoute à chaque fois le même contenu. Néanmoins, du côté technique, ceci représente tout à fait un nouveau état, car on a à chaque fois une représentation du DOM différente de la précédente.
# La page présente de la variabilité, avec potentiellement un nombre d'état "différents" infini. Bien entendu, d'un point de vue utilisateur, les états ne diffèrent pas vraiment, car on ajoute à chaque fois le même contenu. Néanmoins, du côté technique, ceci représente tout à fait un nouvel état, car on a à chaque fois une représentation du DOM différente de la précédente.
#:
#:
# La variabilité est déclenchée par un événement: le clique sur le bouton.
# La variabilité est déclenchée par un événement: le clique sur le bouton.
Ligne 92 : Ligne 109 :
# C'est l'utilisateur qui décide si et quand cliquer sur ce bouton, en ayant ainsi le contrôle sur le comportement de l'application.
# C'est l'utilisateur qui décide si et quand cliquer sur ce bouton, en ayant ainsi le contrôle sur le comportement de l'application.


{{bloc important | '''En résumé''' : l'interactivité avec JavaScript consiste dans le changement programmé du DOM à travers les instructions contenu dans un ou plusieurs scripts. Ces changements se reflètent dans la mise à jour de l'interface utilisateur affichée par le navigateur.}}
{{bloc important | '''En résumé''' : l'interactivité avec JavaScript consiste dans le changement programmé du DOM à travers les instructions contenues dans un ou plusieurs scripts. Ces changements se reflètent dans la mise à jour de l'interface utilisateur affichée par le navigateur.}}


== Exemples étape par étape ==
== Exemples étape par étape ==


Nous allons présenter une série d'exemples, avec l'explication des passages étape par étape. Les exemples sont organisés en 4 sections :
Nous allons présenter une série d'exemples, avec l'explication des passages étape par étape. Les exemples sont organisés en 3 sections :


# '''Boutons'''
# '''Bouton'''
#: Introduction du principe de base de de l'interactivité à travers un simple bouton qui peut être cliqué par l'utilisateur. Le principe fondamentale de l'identification d'un élément et l'association à un gestionnaire d'événement sont les deux aspects principaux de cette section.
#: Introduction du principe de base de de l'interactivité à travers un simple bouton qui peut être cliqué par l'utilisateur. Le principe fondamental de l'identification d'un élément et l'association à un gestionnaire d'événement sont les deux aspects principaux de cette section.
# '''Plusieurs boutons'''
# '''Plusieurs boutons'''
#: Extension de l'exemple précédent à plusieurs éléments en même temps. Nous allons généraliser le principe de l'identification à plusieurs boutons de manière programmé et verrons comment associer des comportements différents à travers la programmation.
#: Extension de l'exemple précédent à plusieurs éléments en même temps. Nous allons généraliser le principe de l'identification à plusieurs boutons de manière programmée et verrons comment associer des comportements différents à travers la programmation.
# '''Input'''
# '''Input'''
#: Gestion de l'information fourni par l'utilisateur. Nous allons traiter des interactions plus articulées par rapport au point-and-click, notamment à travers la saisie de texte.
#: Gestion de l'information fournie par l'utilisateur. Nous allons traiter des interactions plus articulées par rapport au point-and-click, notamment à travers la saisie de texte.


Pour la première section, chaque exemple dispose de '''références croisées''' aux [[Tutoriel JavaScript de base]] et [[Tutoriel JavaScript côté client]] pour approfondir au besoin certains aspects. Par la suite, les références seront limitées aux aspects nouveaux par rapport aux sections/exemples précédentes.  
Pour la première section, chaque exemple dispose de '''références croisées''' aux [[Tutoriel JavaScript de base]] et [[Tutoriel JavaScript côté client]] pour approfondir au besoin certains aspects. Par la suite, les références seront limitées aux aspects nouveaux par rapport aux sections/exemples précédents.  


Enfin, pour chaque section, nous proposons en dernier exemple une petite application pédagogique qui synthétise les concepts expliqués, ainsi qu'un petit exercice pour consolider les connaissances acquises.
Enfin, pour chaque section, nous proposons en dernier exemple une petite application pédagogique qui synthétise les concepts expliqués, ainsi qu'un petit exercice pour consolider les connaissances acquises.


=== Boutons ===
=== Bouton ===


Nous allons commencer par créer un simple bouton sur lequel l'utilisateur peut cliquer et déclencher un comportement de l'application. Avant de voir l'exemple, il faut d'abord préciser que ce qu'on va faire avec un bouton peut s'appliquer à tout élément d'une page web et que le même principe s'adapte à d'autres types d'interactions (mouseover, mouseut, drag&drop, etc.).
Nous allons commencer par créer un simple bouton sur lequel l'utilisateur peut cliquer et déclencher un comportement de l'application. Avant de voir l'exemple, il faut d'abord préciser que ce qu'on va faire avec un bouton peut s'appliquer à tout élément d'une page web et que le même principe s'adapte à d'autres types d'interactions (mouseover, mouseut, drag&drop, etc.).
Ligne 115 : Ligne 132 :
==== Créer l'élément dans l'interface utilisateur ====
==== Créer l'élément dans l'interface utilisateur ====


La première étape consiste tout simplement à créer ''physiquement'' le bouton sur la page. Même s'il y existe différentes manières pour le faire, nous allons utiliser la stratégie la plus simple : coder à la main le bouton à travers la balise HTML <code><button>...</button></code>. Voici le code complet de l'exemple <code>01-01</code>
La première étape consiste tout simplement à créer ''physiquement'' le bouton sur la page. Même s'il existe différentes manières pour le faire, nous allons utiliser la stratégie la plus simple : coder à la main le bouton à travers la balise HTML <code><button>...</button></code>. Voici le code complet de l'exemple <code>01-01</code>


<source lang="HTML5" line highlight="13">
<source lang="HTML5" line="" highlight="13">
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<html lang="en">
Ligne 139 : Ligne 156 :
Nous avons ajouté ici l'intégralité du code du fichier, même si la partie qui nous intéresse, dans ce cas, se limite au contenu du <code><body>...</body></code>. Par la suite nous allons montrer l'intégralité du code seulement si des changements ont été appliqués dans le <code><head>...</head></code>.
Nous avons ajouté ici l'intégralité du code du fichier, même si la partie qui nous intéresse, dans ce cas, se limite au contenu du <code><body>...</body></code>. Par la suite nous allons montrer l'intégralité du code seulement si des changements ont été appliqués dans le <code><head>...</head></code>.


Comme vous pouvez le tester dans la [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-01-html-button.html page de l'exmple 01-01], nous avons tout simplement un bouton, dans le style de default de votre navigateur. En effet, le navigateur associe au bouton déjà certains comportement "interactifs" quand vous passez votre souris sur la surface du bouton ou quand vous le cliquez. Cependant, il ne se passe rien après le clique car, en tant que développeurs, nous n'avons pas fourni les instructions pour que le bouton réagisse au clique de l'utilisateur.
Comme vous pouvez le tester dans la [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-01-html-button.html page de l'exemple 01-01], nous avons tout simplement un bouton, dans le style de default de votre navigateur. En effet, le navigateur associe au bouton déjà certains comportements "interactifs" quand vous passez votre souris sur la surface du bouton ou quand vous le cliquez. Cependant, il ne se passe rien après le clique car, en tant que développeurs, nous n'avons pas fourni les instructions pour que le bouton réagisse au clique de l'utilisateur.


Ceci aurait été différent si, au lieu de <code><button>...</button></code>, on avait utilisé un lien hypertextuel <code><a href="http://tecfa.unige.ch>Tecfa</a></code>. Dans ce cas le navigateur associe automatiquement le comportement de pointer vers l'adresse fournie dans l'attribut <code>href</code>.  
Ceci aurait été différent si, au lieu de <code><button>...</button></code>, on avait utilisé un lien hypertextuel <code><a href="http://tecfa.unige.ch>Tecfa</a></code>. Dans ce cas le navigateur associe automatiquement le comportement de pointer vers l'adresse fournie dans l'attribut <code>href</code>.  
Ligne 149 : Ligne 166 :
Une interface utilisateur ou une page web se composent généralement de plusieurs éléments, souvent plusieurs éléments du même "type" (e.g. plusieurs paragraphes, plusieurs boutons, etc.). Pour associer à un élément un comportement, il faut donc pouvoir le discriminer, l'identifier par rapport aux autres éléments qui composent l'interface. Ceci peut s'obtenir de différentes manières, nous allons utiliser ici la plus simple: associer un identificateur unique au bouton à travers l''''attribut <code>id="..."</code>'''. Voici le code de l'exemple <code>01-02</code>
Une interface utilisateur ou une page web se composent généralement de plusieurs éléments, souvent plusieurs éléments du même "type" (e.g. plusieurs paragraphes, plusieurs boutons, etc.). Pour associer à un élément un comportement, il faut donc pouvoir le discriminer, l'identifier par rapport aux autres éléments qui composent l'interface. Ceci peut s'obtenir de différentes manières, nous allons utiliser ici la plus simple: associer un identificateur unique au bouton à travers l''''attribut <code>id="..."</code>'''. Voici le code de l'exemple <code>01-02</code>


<source lang="HTML5" highlight="4" start="11" line>
<source lang="HTML5" highlight="4" start="11" line="">
<h1>Interactive button 2/10</h1>
<h1>Interactive button 2/10</h1>
<!-- By default, only some specific element on a webpage (e.g. <a href="page.html">page</a>) are interactive -->
<!-- By default, only some specific element on a webpage (e.g. <a href="page.html">page</a>) are interactive -->
Ligne 156 : Ligne 173 :
</source>
</source>


La valeur de l'attribut <code>id="..."</code> est arbitraire, vous pouvez utiliser ce que vous voulez. Mais c'est de bonne pratique d'utiliser des valeurs saillantes, qui vous permettent par la suite de savoir quel est l'intérêt/utilité de l'élément. Une bonne stratégie consiste à utiliser un identificateur qui donne des informations sur l'action que le bouton est censé faire plutôt que se référer à des caractéristiques de surface. Évitez donc des identificateurs de type id="boutonRouge", car vous pouvez changer d'avis sur la couleur de votre bouton, et utilisez plutôt des valeurs du type id="showMessageBtn" ou id="checkResponseBtn".
La valeur de l'attribut <code>id="..."</code> est arbitraire, vous pouvez utiliser ce que vous voulez. Mais c'est une bonne pratique d'utiliser des valeurs saillantes, qui vous permettent par la suite de savoir quel est l'intérêt/utilité de l'élément. Une bonne stratégie consiste à utiliser un identificateur qui donne des informations sur l'action que le bouton est censé faire, plutôt que se référer à des caractéristiques de surface. Évitez donc des identificateurs de type id="boutonRouge", car vous pouvez changer d'avis sur la couleur de votre bouton, et utilisez plutôt des valeurs du type id="showMessageBtn" ou id="checkResponseBtn".


{{bloc important | Pour qu'un élément soit interactif, il faut d'abord pouvoir l'identifier parmi d'autres éléments. La stratégie la plus simple est de lui donner un identificateur à travers un attribut '''id''' avec une valeur saillante, qui permet de deviner son utilité/comportement dans l'application.}}
{{bloc important | Pour qu'un élément soit interactif, il faut d'abord pouvoir l'identifier parmi d'autres éléments. La stratégie la plus simple est de lui donner un identificateur à travers un attribut '''id''' avec une valeur saillante, qui permet de deviner son utilité/comportement dans l'application.}}
Ligne 162 : Ligne 179 :
==== Créer une référence au bouton en JavaScript ====
==== Créer une référence au bouton en JavaScript ====


Une fois que l'élément peut être identifié, l'étape suivante consiste à l'intégrer dans un script. Pour ce faire, nous allons créer une variable (i.e. une boîte qui peut contenir différents choses) et lui affecter la référence à notre bouton. Pour créer la référence, nous allons justement nous servir de l'attribut <code>id="interactiveIdentifier"</code>. Voici le code de l'exemple <code>01-03</code> :
Une fois que l'élément peut être identifié, l'étape suivante consiste à l'intégrer dans un script. Pour ce faire, nous allons créer une variable (i.e. une boîte qui peut contenir différentes choses) et lui affecter la référence à notre bouton. Pour créer la référence, nous allons justement nous servir de l'attribut <code>id="interactiveIdentifier"</code>. Voici le code de l'exemple <code>01-03</code> :


<source lang="HTML5" highlight="8, 10" line start="11">
<source lang="HTML5" highlight="8, 10" line="" start="11">
<h1>Interactive button 3/10</h1>
<h1>Interactive button 3/10</h1>
<!-- Once the elemnt can be identified, you must create a reference to it in JavaScript -->
<!-- Once the elemnt can be identified, you must create a reference to it in JavaScript -->
Ligne 180 : Ligne 197 :
Ce code fait deux choses :
Ce code fait deux choses :


# '''Ligne 18''' : il créer une référence symbolique (i.e. une variable) à notre bouton. Le bouton est identifié à travers la méthode <code>document.getElementById('interactiveIdentifier')</code>
# '''Ligne 18''' : il crée une référence symbolique (i.e. une variable) à notre bouton. Le bouton est identifié à travers la méthode <code>document.getElementById('interactiveIdentifier')</code>
# '''Ligne 20''' : il output à la console la valeur de la variable
# '''Ligne 20''' : il output à la console la valeur de la variable


La partie qui nous intéresse le plus est celle où on créer une référence symbolique au bouton. Il y a différentes manières pour le faire et selon le cas ce passage n'est même pas nécessaire, mais cela nous sert pour expliquer le concept illustré à l'image :
La partie qui nous intéresse le plus est celle où on crée une référence symbolique au bouton. Il y a différentes manières pour le faire et selon le cas ce passage n'est même pas nécessaire, mais cela nous sert pour expliquer le concept illustré à l'image :


[[Fichier:Interactivité avec JavaScript - reference to a DOM object.png|700px|vignette|néant|Créer une référence à un élément du DOM en JavaScript]]
[[Fichier:Interactivité avec JavaScript - reference to a DOM object svg.svg|700px|vignette|néant|Créer une référence à un élément du DOM en JavaScript]]


Grâce au fait qu'on utilise la valeur de l'attribut <code>id="interactiveIdentifier"</code> en tant qu'argument de la méthode <code>document.getElementById('interactiveIdentifier')</code>, nous sommes maintenant en grès d'accéder à notre bouton dans un script. Pour praticité, nous avons utilisé une variable que nous avons nommés <code>var theButton</code>, mais comme il a été le cas pour l'attribut id, ce nom est arbitraire. Encore une fois, le choix de noms saillants facilite néanmoins la lisibilité et la compréhension de l'intentionalité du code.
Grâce au fait qu'on utilise la valeur de l'attribut <code>id="interactiveIdentifier"</code> en tant qu'argument de la méthode <code>document.getElementById('interactiveIdentifier')</code>, nous sommes maintenant en grès d'accéder à notre bouton dans un script. Pour que ce soit plus pratique, nous avons utilisé une variable que nous avons nommée <code>var theButton</code>, mais comme il a été le cas pour l'attribut id, ce nom est arbitraire. Encore une fois, le choix de noms saillants facilite néanmoins la lisibilité et la compréhension de l'intention du code.


Lorsque vous ouvrez la console de votre navigateur web dans la [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-03-javascript-reference.html page de l'exemple <code>01-03</code>], vous pouvez bien noter comme il s'affiche tout simplement le noeud HTML représenté par notre bouton :
Lorsque vous ouvrez la console de votre navigateur web dans la [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-03-javascript-reference.html page de l'exemple <code>01-03</code>], vous pouvez bien noter comme il s'affiche tout simplement le noeud HTML représenté par notre bouton :


[[Fichier:Interactivité avec JavaScript - output DOM element in console.png|700px|vignette|néant|La variable theButton est maintenant une référence exacte au noeud HTML représenté par le bouton.]]
[[Fichier:Interactivité avec JavaScript - output DOM element in console svg.svg|700px|vignette|néant|La variable theButton est maintenant une référence exacte au noeud HTML représenté par le bouton.]]
 
{{bloc important | Pour associer des comportements interactifs avec JavaScript, il faut pouvoir accéder à l'élément à l'intérieur d'un script. Nous avons exploité l'id du bouton pour l'identifier dans le document et créer une variable pour avoir une référence symbolique à l'élément.}}
{{bloc important | Pour associer des comportements interactifs avec JavaScript, il faut pouvoir accéder à l'élément à l'intérieur d'un script. Nous avons exploité l'id du bouton pour l'identifier dans le document et créer une variable pour avoir une référence symbolique à l'élément.}}


Ligne 203 : Ligne 219 :
* [[Tutoriel_JavaScript_c%C3%B4t%C3%A9_client#Trouver_un_.C3.A9l.C3.A9ment|Trouver un élément dans le DOM]] (Tutoriel JS côté-client)
* [[Tutoriel_JavaScript_c%C3%B4t%C3%A9_client#Trouver_un_.C3.A9l.C3.A9ment|Trouver un élément dans le DOM]] (Tutoriel JS côté-client)


==== Accéder aux informations du boutons à travers JavaScript ====
==== Accéder aux informations du bouton à travers JavaScript ====


Une fois qu'on a une référence symbolique en JavaScript, on peut accéder aux informations de l'élément. D'abord, on va intégrer un peu de CSS pour styliser le bouton. Pour ce faire, nous allons associer une classe de style au bouton. Voici le code complet de l'exemple <code>01-04</code> :
Une fois qu'on a une référence symbolique en JavaScript, on peut accéder aux informations de l'élément. D'abord, on va intégrer un peu de CSS pour styliser le bouton. Pour ce faire, nous allons associer une classe de style au bouton. Voici le code complet de l'exemple <code>01-04</code> :


<source lang="HTML5" line highlight="31-34">
<source lang="HTML5" line="" highlight="31-34">
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<html lang="en">
Ligne 249 : Ligne 265 :
</source>
</source>


Ce qui nous intéresse le plus dans ce code réside en réalité dans le output de la console de [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-04-element-in-javascript.html la page de l'exemple <code>01-04</code>]. Vous pouvez en effet noter comme à travers la variable <code>theButton</code> on peut récupérer en JavaScript des informations/caractéristiques du noeud/bouton :
Ce qui nous intéresse le plus dans ce code réside en réalité dans l'output de la console de [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-04-element-in-javascript.html la page de l'exemple <code>01-04</code>]. Vous pouvez en effet noter comme à travers la variable <code>theButton</code> on peut récupérer en JavaScript des informations/caractéristiques du noeud/bouton :


* <code>theButton.id</code> output '''interactiveIdentifier'''
* <code>theButton.id</code> output '''interactiveIdentifier'''
Ligne 268 : Ligne 284 :
==== Ajouter un gestionnaire d'événement ====
==== Ajouter un gestionnaire d'événement ====


Jusqu'à présent, nous avons ajouté une référence symbolique dans le script et améliorer (vaguement) le style du bouton, mais nous n'avons toujours pas d'interactivité. Il nous faut que le navigateur puisse, parmi tous les cliques possibles sur la page, écouter en particulier les cliques qui sont faits sur la surface de notre bouton. C'est le rôle du '''gestionnaire d'événement'''. Voici le code de l'exemple <code>01-05</code> :
Jusqu'à présent, nous avons ajouté une référence symbolique dans le script et amélioré (vaguement) le style du bouton, mais nous n'avons toujours pas d'interactivité. Il faut que le navigateur puisse, parmi tous les cliques possibles sur la page, écouter en particulier les cliques qui sont faits sur la surface de notre bouton. C'est le rôle du '''gestionnaire d'événement'''. Voici le code de l'exemple <code>01-05</code> :


<source lang="HTML5" line highlight="10-12" start="20">
<source lang="HTML5" line="" highlight="10-12" start="20">
<h1>Interactive button 5/10</h1>
<h1>Interactive button 5/10</h1>
<!-- The interactive element -->
<!-- The interactive element -->
Ligne 294 : Ligne 310 :
# On associe à <code>theButton</code> la méthode <code>addEventListener()</code> ('''ligne 29''') qui accepte deux paramètres :
# On associe à <code>theButton</code> la méthode <code>addEventListener()</code> ('''ligne 29''') qui accepte deux paramètres :
## Le type d'événement que nous voulons écouter, dans ce cas '''click'''
## Le type d'événement que nous voulons écouter, dans ce cas '''click'''
## Une fonction qui est déclenchée lorsque cet événement s'avère. Dans ce cas, nous utilisons une fonction anonyme (i.e. déclarée exactement à l'endroit où elle est appelée), mais on aurait pu également faire autrement.
## Une fonction qui est déclenchée lorsque cet événement se produit. Dans ce cas, nous utilisons une fonction anonyme (i.e. déclarée exactement à l'endroit où elle est appelée), mais on aurait pu faire autrement.
#:
#:
# À l'intérieur de cette fonction, nous avons ajouté le code qui doit être exécutée à chaque fois que l'événement '''click''' s'avère. Dans ce cas spécifique, il s'agit d'un simple <code>console.log()</code> ('''ligne 30''') qui va confirmer en console que le gestionnaire d'événement a bien marché.
# À l'intérieur de cette fonction, nous avons ajouté le code qui doit être exécuté à chaque fois que l'événement '''click''' se produit. Dans ce cas spécifique, il s'agit d'un simple <code>console.log()</code> ('''ligne 30''') qui va confirmer en console que le gestionnaire d'événement a bien marché.


L'image suivante résumé de manière graphique ce principe :
L'image suivante résume de manière graphique ce principe :


[[Fichier:Interactivité avec JavaScript - event listener reference.png|800px|vignette|néant|Explication d'un gestionnaire d'événement.]]
[[Fichier:Interactivité avec JavaScript - event listener reference svg.svg|800px|vignette|néant|Explication d'un gestionnaire d'événement]]


Vous pouvez essayer de cliquer le bouton sur [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-05-add-listener.html la page de l'exemple <code>01-05</code>] en ouvrant la console du navigateur : chaque fois qu'on clique sur le bouton, le chiffre à côté du message '''theButton has been clicked!''' va augmenter.
Vous pouvez essayer de cliquer le bouton sur [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-05-add-listener.html la page de l'exemple <code>01-05</code>] en ouvrant la console du navigateur : chaque fois qu'on clique sur le bouton, le chiffre à côté du message '''theButton has been clicked!''' va augmenter.
Ligne 316 : Ligne 332 :
En programmation il y a toujours moyen de faire la même chose de manière différente. Nous proposons ici une syntaxe alternative, '''mais moins conseillée''', pour obtenir exactement le même résultat de l'exemple précédent. Voici le code le code de l'exemple <code>01-06</code>, limité au contenu de la balise <code><script>...</script></code> :
En programmation il y a toujours moyen de faire la même chose de manière différente. Nous proposons ici une syntaxe alternative, '''mais moins conseillée''', pour obtenir exactement le même résultat de l'exemple précédent. Voici le code le code de l'exemple <code>01-06</code>, limité au contenu de la balise <code><script>...</script></code> :


<source lang="JavaScript" line highlight="4" start="26">
<source lang="JavaScript" line="" highlight="4" start="26">
//Create a symbolic reference (i.e. a variable) to the HTML element
//Create a symbolic reference (i.e. a variable) to the HTML element
var theButton = document.getElementById('interactiveIdentifier');
var theButton = document.getElementById('interactiveIdentifier');
Ligne 333 : Ligne 349 :
# À l'intérieur de cette fonction, nous plaçons les instructions à exécuter. Dans ce cas, un simple <code>console.log()</code>
# À l'intérieur de cette fonction, nous plaçons les instructions à exécuter. Dans ce cas, un simple <code>console.log()</code>


{{ bloc important | On peut ajouter un gestionnaire d'événement avec une syntaxe alternative, mais addEventListener() reste la meilleure option.}}
{{bloc important | On peut ajouter un gestionnaire d'événement avec une syntaxe alternative, mais addEventListener() reste la meilleure option.}}


; Références croisées :
; Références croisées :
Ligne 345 : Ligne 361 :
À ce point, nous avons techniquement un bouton interactif. Cependant, du côté de l'utilisateur, il n'y a rien qui suggère que quelque chose se passe lorsqu'on a cliqué sur le bouton. Du point de vue expérience utilisateur, donc, il est nécessaire que l'algorithme associé au gestionnaire d'événement produise une variation dans l'interface dont l'utilisateur puisse s'apercevoir. C'est ce qu'on va faire avec l'exemple <code>01-06</code>. Nous allons modifier le contenu d'un noeud que nous allons identifier, tout comme on a fait pour le bouton, à travers l'attribut <code>id="..."</code> :
À ce point, nous avons techniquement un bouton interactif. Cependant, du côté de l'utilisateur, il n'y a rien qui suggère que quelque chose se passe lorsqu'on a cliqué sur le bouton. Du point de vue expérience utilisateur, donc, il est nécessaire que l'algorithme associé au gestionnaire d'événement produise une variation dans l'interface dont l'utilisateur puisse s'apercevoir. C'est ce qu'on va faire avec l'exemple <code>01-06</code>. Nous allons modifier le contenu d'un noeud que nous allons identifier, tout comme on a fait pour le bouton, à travers l'attribut <code>id="..."</code> :


<source lang="HTML5" line highlight="6, 13, 17" start="20">
<source lang="HTML5" line="" highlight="6, 13, 17" start="20">
<h1>Interactive button 7/10</h1>
<h1>Interactive button 7/10</h1>
<!-- The interactive element -->
<!-- The interactive element -->
Ligne 369 : Ligne 385 :
Lorsqu'on clique sur le bouton dans la [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-07-show-output.html page de l'exemple <code>01-07</code>], on peut s'apercevoir que le texte '''I will be changed''' devient '''I have been changed through the interaction!'''. Pour obtenir ce simple résultat nous avons :
Lorsqu'on clique sur le bouton dans la [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-07-show-output.html page de l'exemple <code>01-07</code>], on peut s'apercevoir que le texte '''I will be changed''' devient '''I have been changed through the interaction!'''. Pour obtenir ce simple résultat nous avons :


# '''Ligne 25''' : ajouté un paragraph avec attribut '''<code>id="elementToChange"</code>''' pour pouvoir l'identifier dans le script
# '''Ligne 25''' : ajouté un paragraphe avec attribut '''<code>id="elementToChange"</code>''' pour pouvoir l'identifier dans le script
#:
#:
# ''' Ligne 32''' : créé une référence symbolique à ce noeud à traves '''<code>var theOutput = document.getElementById('elementToChange')</code>'''. Encore une fois, le nom de cette variable est arbitraire et devrait suivre plutôt des règles de nomenclature sémantique comme nous avons suggéré plus haut.
# ''' Ligne 32''' : créé une référence symbolique à ce noeud à travers '''<code>var theOutput = document.getElementById('elementToChange')</code>'''. Encore une fois, le nom de cette variable est arbitraire et devrait suivre plutôt des règles de nomenclature sémantique comme nous avons suggéré plus haut.
#:
#:
# '''Ligne 36''' : injecté dans la fonction déclenchée par le gestionnaire d'événement une instruction qui permet de modifier le contenu du noeud avec '''<code>theOutput.innerHTML = 'I have been changed through the interaction!';</code>'''
# '''Ligne 36''' : injecté dans la fonction déclenchée par le gestionnaire d'événement une instruction qui permet de modifier le contenu du noeud avec '''<code>theOutput.innerHTML = 'I have been changed through the interaction!';</code>'''
Ligne 377 : Ligne 393 :
L'image suivante représente graphiquement ce processus.
L'image suivante représente graphiquement ce processus.


[[Fichier:Interactivité avec JavaScript - change element content after interaction.png|800px|vignette|néant|Modification du contenu d'un noeud suite au déclenchement d'un événement.]]
[[Fichier:Interactivité avec JavaScript - change element content after interaction svg.svg|800px|vignette|néant|Modification du contenu d'un noeud suite au déclenchement d'un événement]]


{{ bloc important | '''Important''' : si on veut modifier un élément de l'interface suite à un événement, il faudra l'identifier pour pouvoir y accéder dans le script, et ensuite insérer à l'intérieur du gestionnaire d'événement une instruction qui modifie l'élément, ainsi que cette instruction soit exécutée seulement lorsque l'événement s'avère. }}
{{bloc important | '''Important''' : si on veut modifier un élément de l'interface suite à un événement, il faudra l'identifier pour pouvoir y accéder dans le script, et ensuite insérer à l'intérieur du gestionnaire d'événement une instruction qui modifie l'élément, ainsi que cette instruction soit exécutée seulement lorsque l'événement s'avère. }}


; Références croisées :
; Références croisées :
Ligne 393 : Ligne 409 :
==== Ajouter plusieurs manipulations au gestionnaire d'événement ====
==== Ajouter plusieurs manipulations au gestionnaire d'événement ====


Dans l'exemple précédent, notre gestionnaire d'événement se limite à exécuter une seule instruction lorsqu'il est déclenché. Ceci n'est certainement pas une contrainte, il est tout à fait possible, et d'ailleurs intéressant, de exécuter plusieurs instructions à la fois. Voici le code, limité au contenu de la balise <code><script>...</script></code> pour l'exemple <code>01-08</code> :
Dans l'exemple précédent, notre gestionnaire d'événement se limite à exécuter une seule instruction lorsqu'il est déclenché. Ceci n'est certainement pas une contrainte, il est tout à fait possible, et d'ailleurs intéressant, d'exécuter plusieurs instructions à la fois. Voici le code, limité au contenu de la balise <code><script>...</script></code> pour l'exemple <code>01-08</code> :


<source lang="JavaScript" line highlight="10, 12-14" start="29">
<source lang="JavaScript" line="" highlight="10, 12-14" start="29">
//Create a symbolic reference (i.e. a variable) to the INTERACTIVE HTML element
//Create a symbolic reference (i.e. a variable) to the INTERACTIVE HTML element
var theButton = document.getElementById('interactiveIdentifier');
var theButton = document.getElementById('interactiveIdentifier');
Ligne 402 : Ligne 418 :
//Add a listener that modifies the content and style of the paragraph, as well as the button itself
//Add a listener that modifies the content and style of the paragraph, as well as the button itself
theButton.addEventListener('click', function () {
theButton.addEventListener('click', function () {
     //You can have multiple istructions inside the event handler
     //You can have multiple instructions inside the event handler
     theOutput.innerHTML = 'I have been changed through the interaction!';
     theOutput.innerHTML = 'I have been changed through the interaction!';
     //You can change the interactive element itself
     //You can change the interactive element itself
Ligne 413 : Ligne 429 :
</source>
</source>


Comme vous pouvez le noter sur la [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-08-multiple-manipulations.html page de l'exemple <code>01-08</code>], lorsque vous cliquez sur le bouton il y différents changements qui concernent à la fois le paragraphe de feedback, mais également la labellisation du bouton lui-même qui change de '''I am interactive now''' à '''I have been clicked'''.
Comme vous pouvez le noter sur la [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-08-multiple-manipulations.html page de l'exemple <code>01-08</code>], lorsque vous cliquez sur le bouton il y a différents changements qui concernent à la fois le paragraphe de feedback, mais également la labellisation du bouton lui-même qui change de '''I am interactive now''' à '''I have been clicked'''.


À l'intérieur de la fonction associée au gestionnaire d'événements on peut en effet mettre autant d'instructions dont on a besoin et on peut faire référence à l'intérieur de cette fonction à tous les éléments qu'on peut identifier. Dans ce cas, nous utilisons les références symboliques aux éléments <code>theButton</code> et <code>theOutput</code>, mais rien n'empêche d'identifier les éléments directement à l'intérieur de la fonction. Il s'agit encore une fois d'une question d'organisation du code.  
À l'intérieur de la fonction associée au gestionnaire d'événements on peut en effet mettre autant d'instructions dont on a besoin et on peut faire référence à l'intérieur de cette fonction à tous les éléments qu'on peut identifier. Dans ce cas, nous utilisons les références symboliques aux éléments <code>theButton</code> et <code>theOutput</code>, mais rien n'empêche d'identifier les éléments directement à l'intérieur de la fonction. Il s'agit encore une fois d'une question d'organisation du code.  


Comparé à l'exemple précédent, nous utilisons encore une fois <code>.innerHTML = "..."</code> pour modifier le contenu des noeuds référencé par les deux variables. De plus, pour <code>theOutput</code> nous avons expoité la possibilité d'utiliser <code>.style.''propriété''</code> pour modifier certaines caractéristiques de style du paragraphe comme la couleur du texte et du fond, ainsi que la taille de la police. Veuillez noter que les noms des propriétés n'est pas exactement celle qui est utilisée dans les CSS (fontSize au lieu de font-size, backgroundColor au lieu de background-color) pour respecter les règles syntaxique de JavaScript.  
Comparé à l'exemple précédent, nous utilisons encore une fois <code>.innerHTML = "..."</code> pour modifier le contenu des noeuds référencé par les deux variables. De plus, pour <code>theOutput</code> nous avons exploité la possibilité d'utiliser <code>.style.''propriété''</code> pour modifier certaines caractéristiques de style du paragraphe comme la couleur du texte et du fond, ainsi que la taille de la police. Veuillez noter que les noms des propriétés n'est pas exactement celui qui est utilisée dans les CSS (fontSize au lieu de font-size, backgroundColor au lieu de background-color) pour respecter les règles syntaxique de JavaScript.  


{{ bloc important | Un événement peut déclencher plusieurs changements au niveau de l'interface utilisateur. Pour ce faire, il suffit que tous les changements soient définis à l'intérieur de la fonction associée au gestionnaire d'événements. }}
{{bloc important | Un événement peut déclencher plusieurs changements au niveau de l'interface utilisateur. Pour ce faire, il suffit que tous les changements soient définis à l'intérieur de la fonction associée au gestionnaire d'événements. }}


; Références croisées :
; Références croisées :
Ligne 434 : Ligne 450 :
==== Ajouter de la logique computationnelle au gestionnaire d'événement ====
==== Ajouter de la logique computationnelle au gestionnaire d'événement ====


Dans la fonction qui réagit au gestionnaire d'événement, nous pouvons injecter toute sorte de logique computationnelle, par exemple pour réagir différemment en fonction de certaines variables. Dans l'exemple <code>01-09</code> nous ajoutons une simple instruction de contrôle qui définit le type de feedback à montrer :
Dans la fonction qui réagit au gestionnaire d'événement, nous pouvons injecter toutes sortes de logique computationnelle, par exemple pour réagir différemment en fonction de certaines variables. Dans l'exemple <code>01-09</code> nous ajoutons une simple instruction de contrôle qui définit le type de feedback à montrer :


* S'il est plus tôt que midi, l'output est '''Good morning!'''
* S'il est plus tôt que midi, l'output est '''Good morning!'''
Ligne 441 : Ligne 457 :
Le code qui nous intéresse est limité à l'intérieur du <code><script>...</script></code> :
Le code qui nous intéresse est limité à l'intérieur du <code><script>...</script></code> :


<source lang="JavaScript" line highlight="9-14" start="29">
<source lang="JavaScript" line="" highlight="9-14" start="29">
//Create a symbolic reference (i.e. a variable) to the INTERACTIVE HTML element
//Create a symbolic reference (i.e. a variable) to the INTERACTIVE HTML element
var theButton = document.getElementById('interactiveIdentifier');
var theButton = document.getElementById('interactiveIdentifier');
Ligne 459 : Ligne 475 :
</source>
</source>


Grâce à l'intégration de la structure de contrôle, nous avons augmenté la variabilité de notre application mais sans augmenter le nombre d'interactions possibles : l'utilisateur est toujours limité à la seule possibilité de cliquer, ou pas, sur le bouton. En fonction de l'heure dans laquelle vous visitez la [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-09-add-logic.html page avec l'exemple <code>00-09</code>], vous allez obtenir un output différent qui s'affiche dans le paragraphe.
Grâce à l'intégration de la structure de contrôle, nous avons augmenté la variabilité de notre application mais sans augmenter le nombre d'interactions possibles : l'utilisateur est toujours limité à la seule possibilité de cliquer, ou pas, sur le bouton. En fonction de l'heure à laquelle vous visitez la [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-09-add-logic.html page avec l'exemple <code>00-09</code>], vous allez obtenir un output différent qui s'affiche dans le paragraphe.


{{ bloc important | La fonction qui est associée au gestionnaire d'événement peut exécuter toute type de logique, de la plus simple à la plus complexe, et augmenter donc la variabilité de l'application avec le même type d'interaction. }}
{{bloc important | La fonction qui est associée au gestionnaire d'événement peut exécuter toute type de logique, de la plus simple à la plus complexe, et augmenter donc la variabilité de l'application avec le même type d'interaction. }}


; Références croisées :
; Références croisées :
Ligne 474 : Ligne 490 :
==== Exemple d'application pédagogique ====
==== Exemple d'application pédagogique ====


Dans les exemples précédents, nous avons abordé les principes de l'interaction avec l'explication de cas très simple. Dans tout ce cas, les utilisateurs avaient à disposition fondamentalement seulement un type de variation possible lorsqu'ils cliquaient le bouton, à l'exclusion du cas d'un utilisateur qui clique une première fois sur le bouton de l'exemple autour de 11:59 et attend jusqu'à midi pour cliquer la deuxième fois. Dans les autres cas, l'utilisateur ne va pas détecter aucune variation ultérieure sur l'interface utilisateur après le premier clique sur le bouton.
Dans les exemples précédents, nous avons abordé les principes de l'interaction avec l'explication de cas très simples. Dans tout ces cas, les utilisateurs avaient à disposition fondamentalement seulement un type de variation possible lorsqu'ils cliquaient le bouton, à l'exclusion du cas d'un utilisateur qui clique une première fois sur le bouton de l'exemple autour de 11:59 et attend jusqu'à midi pour cliquer la deuxième fois. Dans les autres cas, l'utilisateur ne va détecter aucune variation ultérieure sur l'interface utilisateur après le premier clique sur le bouton.


Dans le dernier exemple de cette section, nous allons complexifier légèrement la logique de la fonction associée au gestionnaire d'événement pour créer un canevas d'application avec finalité pédagogique. Chaque fois que l'utilisateur clique sur le bouton, l'interface utilisateur lui propose de dire entre 1 et 10 mots qui commencent avec une lettre au hasard de l’alphabète. L'interface ne propose pas la possibilité de saisir les mots (on verra comment traiter les inputs de l'utilisateur dans la section correspondante plus bas), mais néanmoins nous avons une petite application qui peut servir à tester/améliorer les capacités langagières d'une personne. Dans ce dernier cas, il est peut être utile de tester l'exemple avant de voir son code : [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-10-multiple-logic.html page de l'exemple <code>01-10</code>].
Dans le dernier exemple de cette section, nous allons complexifier légèrement la logique de la fonction associée au gestionnaire d'événement pour créer un canevas d'application avec finalité pédagogique. Chaque fois que l'utilisateur clique sur le bouton, l'interface utilisateur lui propose de dire entre 1 et 10 mots qui commencent avec une lettre au hasard de l’alphabet. L'interface ne propose pas la possibilité de saisir les mots (on verra comment traiter les inputs de l'utilisateur dans la section correspondante plus bas), mais néanmoins nous avons une petite application qui peut servir à tester/améliorer les capacités langagières d'une personne. Dans ce dernier cas, il est peut être utile de tester l'exemple avant de voir son code : [https://maltt-stic.github.io/stic-1-interaction-with-js/01-button/01-10-multiple-logic.html page de l'exemple <code>01-10</code>].


Voici le code complet de l'exemple <code>01-10</code>, car nous avons ajouté quelques déclarations de style pour améliorer l'interface :
Voici le code complet de l'exemple <code>01-10</code>, car nous avons ajouté quelques déclarations de style pour améliorer l'interface :


<source lang="HTML5" line>
<source lang="HTML5" line="">
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<html lang="en">
Ligne 553 : Ligne 569 :
</source>
</source>


Comparé aux exemples précédents, il n'y a aucun changement substantiel au niveau de l'interface utilisateur du départ. Nous avons toujours un bouton et un paragraphe de output comme éléments nécessaire à l'interactivité. Nous avons ajouté une simple, mais insuffisante, introduction à la tâche (i.e. depuis l'instruction on ne comprend pas qu'on peut obtenir des nouvelles consignes en cliquant encore sur le bouton). La partie qui nous intéresse est donc contenue à l'intérieur de la balise <code><script>...</script></code> :
Comparé aux exemples précédents, il n'y a aucun changement substantiel au niveau de l'interface utilisateur du départ. Nous avons toujours un bouton et un paragraphe de output comme éléments nécessaires à l'interactivité. Nous avons ajouté une simple, mais insuffisante, introduction à la tâche (i.e. depuis l'instruction on ne comprend pas qu'on peut obtenir des nouvelles consignes en cliquant encore sur le bouton). La partie qui nous intéresse est donc contenue à l'intérieur de la balise <code><script>...</script></code> :


<source lang="JavaScript" line highlight="8-10, 13-15, 20-21" start="43">
<source lang="JavaScript" line="" highlight="8-10, 13-15, 20-21" start="43">
//Create a symbolic reference (i.e. a variable) to the INTERACTIVE HTML element
//Create a symbolic reference (i.e. a variable) to the INTERACTIVE HTML element
var theButton = document.getElementById('interactiveIdentifier');
var theButton = document.getElementById('interactiveIdentifier');
Ligne 589 : Ligne 605 :
La logique interne de ces fonctions dépasse l'objectif de cette page. Nous pouvons tout simplement en faire abstraction et faire confiance à ce qui est écrit dans les commentaires du code. Chaque fois qu'on appelle <code>generateRandomNumber()</code> nous aurons un nombre 1-10, et chaque fois qu'on appelle <code>generateRandomLetter()</code> une lettre a-z.
La logique interne de ces fonctions dépasse l'objectif de cette page. Nous pouvons tout simplement en faire abstraction et faire confiance à ce qui est écrit dans les commentaires du code. Chaque fois qu'on appelle <code>generateRandomNumber()</code> nous aurons un nombre 1-10, et chaque fois qu'on appelle <code>generateRandomLetter()</code> une lettre a-z.


À ce point, nous pouvons intégrer les deux fonctions à l'intérieur de la fonction associée au gestionnaire d'événement pour déterminer le output du paragraphe dans lequel afficher la consigne avec le nombre des mots à dire qui commencent avec la lettre aléatoirement choisie :
À ce point, nous pouvons intégrer les deux fonctions à l'intérieur de la fonction associée au gestionnaire d'événement pour déterminer le output du paragraphe dans lequel afficher la consigne avec le nombre de mots à dire qui commencent avec la lettre aléatoirement choisie :


<source lang="JavaScript" start="60" line>
<source lang="JavaScript" start="60" line="">
//You can add more complex logic calling functions inside the event listener
//You can add more complex logic calling functions inside the event listener


Ligne 598 : Ligne 614 :
</source>
</source>


Nous avons utilisé une simple concatenation à l'aide de l'opérateur <code>+</code> pour insérer d'abord le nombre et ensuite la lettre aléatoire dans la phrase qui sera affiché en tant que contenu du noeud/paragraphe <code>theOutput</code>.
Nous avons utilisé une simple concaténation à l'aide de l'opérateur <code>+</code> pour insérer d'abord le nombre et ensuite la lettre aléatoire dans la phrase qui sera affichée en tant que contenu du noeud/paragraphe <code>theOutput</code>.


Grâce aux deux fonctions qui génèrent un chiffre ou une lettre aléatoire, notre application maintenant dispose d'une grande variabilité, assurée par la probabilité de tomber sur une l'une des 260 combinaisons possibles, tout en gardant une seule interaction sur l'interface utilisateur. Il y des bonnes chances, donc, que l'utilisateur se retrouve avec un état différent à chaque fois qu'il clique sur le bouton. Ce qui, en termes pédagogiques, représente à la fois un challenge est une motivation à utiliser plus souvent l'application car il est "impossible de finir le jeu".
Grâce aux deux fonctions qui génèrent un chiffre ou une lettre aléatoire, notre application maintenant dispose d'une grande variabilité, assurée par la probabilité de tomber sur l'une des 260 combinaisons possibles, tout en gardant une seule interaction sur l'interface utilisateur. Il y des bonnes chances, donc, que l'utilisateur se retrouve avec un état différent à chaque fois qu'il clique sur le bouton. Ce qui, en termes pédagogiques, représente à la fois un challenge et une motivation à utiliser plus souvent l'application car il est "impossible de finir le jeu".


{{ bloc important | '''Important''': lorsque la logique interne de l'application se complexifie, il est bien de la décomposer en morceaux plus petits en utilisant plusieurs fonctions qui sont par la suite appelée à l'intérieur du gestionnaire d'événements. Si on exploite dans ces fonctions la capacité des ordinateurs à générer des éléments aléatoires, on peut facilement ajouter une grande variabilité même à une interaction simple comme le clique d'un bouton. }}
{{bloc important | '''Important''': lorsque la logique interne de l'application se complexifie, il est bien de la décomposer en morceaux plus petits en utilisant plusieurs fonctions qui sont par la suite appelées à l'intérieur du gestionnaire d'événements. Si on exploite dans ces fonctions la capacité des ordinateurs à générer des éléments aléatoires, on peut facilement ajouter une grande variabilité même à une interaction simple comme le clique d'un bouton. }}


; Références croisées :
; Références croisées :
Ligne 622 : Ligne 638 :
=== Plusieurs boutons ===
=== Plusieurs boutons ===


Dans cette section, nous allons appliquer les concepts abordés lors de la section précédente à plusieurs boutons en même temps. L'un des avantages de la programmation est en effet la capacité des ordinateurs à répéter la même opération (ou des opérations assez similaires) de manière vite, efficace et pour un grand nombre de fois, ce qui n'est pas le cas des humains qui ont une tendance naturelle à s'ennuyer assez vite dans les tâches répétitives.  
Dans cette section, nous allons appliquer les concepts abordés lors de la section précédente à plusieurs boutons en même temps. L'un des avantages de la programmation est en effet la capacité des ordinateurs à répéter la même opération (ou des opérations assez similaires) rapidement, de manière efficace et pour un grand nombre de fois, ce qui n'est pas le cas des humains qui ont une tendance naturelle à s'ennuyer assez vite dans les tâches répétitives.  


L'interface utilisateur va rester très similaires aux exemples de la section 1 : il y aura toujours une zone de output où afficher des changements suite aux interactions, mais au lieu d'un seule bouton, nous en aurons plusieurs.  
L'interface utilisateur va rester très similaires aux exemples de la section 1 : il y aura toujours une zone de output où afficher des changements suite aux interactions, mais au lieu d'un seule bouton, nous en aurons plusieurs.  


Dans cette section et les suivantes, nous considérons certains aspects illustrés dans la première section comme acquis. En conséquence, nous allons réduire les explications aux aspects du code les plus importants. Si des aspects ne sont pas claires, nous vous conseillons de revoir les exemples de la section 1.
Dans cette section et les suivantes, nous considérons certains aspects illustrés dans la première section comme acquis. En conséquence, nous allons réduire les explications aux aspects du code les plus importants. Si des aspects ne sont pas clairs, nous vous conseillons de revoir les exemples de la section 1.


==== Identifier plusieurs boutons sur l'interface utilisateur ====
==== Identifier plusieurs boutons sur l'interface utilisateur ====


Dans ce premier exemple, nous allons voir comment sélectionner plusieurs boutons qui sont présent sur l'interface utilisateur. Encore plus que dans le premier exemple, où on avait un seule bouton, il existe différentes manières pour générer plusieurs boutons. Pour garder cet exemple simple, nous allons encore une fois les coder "à la main" avec des noeuds HTML de type <code><button>...</button></code>. Voici le contenu du <code><body>...</body></code> de l'exemple <code>02-01</code> :
Dans ce premier exemple, nous allons voir comment sélectionner plusieurs boutons qui sont présents sur l'interface utilisateur. Encore plus que dans le premier exemple, où on avait un seul bouton, il existe différentes manières pour générer plusieurs boutons. Pour garder cet exemple simple, nous allons encore une fois les coder "à la main" avec des noeuds HTML de type <code><button>...</button></code>. Voici le contenu du <code><body>...</body></code> de l'exemple <code>02-01</code> :


<source lang="HTML5">
<source lang="HTML5" line="" start="17">
<h1>Multiple buttons 1/5</h1>
<h1>Multiple buttons 1/5</h1>
<!-- If you have multiple interactive elements, you can't use the id attribute, which is meant to be unique -->
<!-- If you have multiple interactive elements, you can't use the id attribute, which is meant to be unique -->
Ligne 661 : Ligne 677 :
</source>
</source>


Plutôt que de créer 3 références symboliques à chaque boutons individuellement avec trois fois la méthode <code>document.getElementById("...")</code>, nous avons sélectionné les boutons à l'aide de leur attribut <code>'''class="interactiveElement'''</code> en utilisant la méthode <code>'''document.querySelectorAll('.interactiveElement')'''</code>. Cette méthode accepte tous les sélecteurs [[CSS]], et donc grâce au <code>.interactiveElement</code> en argument, tous les éléments avec cette classe seront sélectionnés et stockés dans la référence symbolique <code>'''theButtons'''</code>.
Plutôt que de créer 3 références symboliques à chaque bouton individuellement avec trois fois la méthode <code>document.getElementById("...")</code>, nous avons sélectionné les boutons à l'aide de leur attribut <code>'''class="interactiveElement'''</code> en utilisant la méthode <code>'''document.querySelectorAll('.interactiveElement')'''</code>. Cette méthode accepte tous les sélecteurs [[CSS]], et donc grâce au <code>.interactiveElement</code> en argument, tous les éléments avec cette classe seront sélectionnés et stockés dans la référence symbolique <code>'''theButtons'''</code>.


[[Fichier:Interactivité avec JavaScript - querySelectorAll with class.png|700px|vignette|néant|La sélection multiple s'applique à tous les éléments qui répondent au critères de sélection, dans ce cas class="interactiveElement"]]
[[Fichier:Interactivité avec JavaScript - querySelectorAll with class svg.svg|700px|vignette|néant|La sélection multiple s'applique à tous les éléments qui répondent au critères de sélection, dans ce cas class="interactiveElement"]]


Vous pouvez bien noter depuis le code que seulement les trois premiers boutons de la liste possèdent cet attribut, mais pas le quatrième. En conséquence, si vous ouvrez la console sur la [https://maltt-stic.github.io/stic-1-interaction-with-js/02-multiple-buttons/02-01-multiple-buttons.html page de l'exemple 02-01], vous allez obtenir ce résultat :
Vous pouvez bien noter depuis le code que seulement les trois premiers boutons de la liste possèdent cet attribut, mais pas le quatrième. En conséquence, si vous ouvrez la console sur la [https://maltt-stic.github.io/stic-1-interaction-with-js/02-multiple-buttons/02-01-multiple-buttons.html page de l'exemple 02-01], vous allez obtenir ce résultat :


[[Fichier:Interactivité avec JavaScript - multiple selection.png|cadre|néant|Lorsque l'identification des éléments concernent plusieurs noeuds, le résultat est une liste de noeuds.]]
[[Fichier:Interactivité avec JavaScript - multiple selection svg.svg|cadre|néant|Lorsque l'identification des éléments concernent plusieurs noeuds, le résultat est une liste de noeuds]]


Contrairement aux exemple de la section 1, où la référence symbolique <code>theButton</code> représentait le HTML du noeud/button, <code>'''theButtons'''</code> représente une '''liste de noeuds'''. Comme vous pouvez le voir depuis le output de la console, cette liste contient en effet 3 noeuds et même si une liste de noeud n'est pas vraiment un array (c.f. [[Tutoriel JavaScript côté client]]), la numération des noeuds commence à 0. Si vous saisissez donc <code>theButtons[0]</code> dans votre console, vous allez obtenir seulement le premier bouton, et donc un output tout à fait similaire à l'exemple de la section 1 :
Contrairement aux exemple de la section 1, où la référence symbolique <code>theButton</code> représentait le HTML du noeud/button, <code>'''theButtons'''</code> représente une '''liste de noeuds'''. Comme vous pouvez le voir depuis le output de la console, cette liste contient en effet 3 noeuds et même si une liste de noeud n'est pas vraiment un array (c.f. [[Tutoriel JavaScript côté client]]), la numération des noeuds commence à 0. Si vous saisissez donc <code>theButtons[0]</code> dans votre console, vous allez obtenir seulement le premier bouton, et donc un output tout à fait similaire à l'exemple de la section 1 :
Ligne 675 : Ligne 691 :
</source>
</source>


{{ bloc important | '''Important''': pour sélectionner plusieurs éléments en même temps, on peut exploiter la méthode querySelectorAll(), en utilisant par exemple l'attribut class des éléments. Tous les éléments qui répondent aux critères de sélection sont insérés dans une liste de noeuds, qui n'est pas exactement un array, mais dont la numération commence à 0 et par conséquent les éléments de la liste peuvent être extrait avec la notation nomDeLaListe[0], nomDeLaListe[1], ... }}
{{bloc important | '''Important''': pour sélectionner plusieurs éléments en même temps, on peut exploiter la méthode querySelectorAll(), en utilisant par exemple l'attribut class des éléments. Tous les éléments qui répondent aux critères de sélection sont insérés dans une liste de noeuds, qui n'est pas exactement un array, mais dont la numération commence à 0 et par conséquent les éléments de la liste peuvent être extraits avec la notation nomDeLaListe[0], nomDeLaListe[1], ... }}


==== Faire une itération entre les noeuds/boutons ====
==== Faire une itération entre les noeuds/boutons ====


Dans notre exemple, nous savons à l'avance que nous avons seulement trois boutons qui répondent au critère de sélection et donc on pourrait utiliser individuellement <code>theButtons[0]</code>, <code>theButtons[1]</code>, et <code>theButtons[2]</code> en tant que références symboliques aux respectives noeuds/boutons. Très souvent, en revanche, nous ne pouvons pas savoir à l'avance combien d'éléments seront disponibles sur l'interface (surtout s'ils sont générés dynamiquement et/ou le nombre d'éléments varie en fonction de l'état de l'application). Ou encore ils sont trop nombreux pour les énumérer tous manuellement. À ce moment, on peut utiliser l'itération pour accéder de manière récursive à tous les éléments dans la liste des noeuds, indépendamment de sa longueur. Voici le code de l'exemple <code>01-02</code> qui applique se principe en utilisant un '''cycle <code>for</code>''' :
Dans notre exemple, nous savons à l'avance que nous avons seulement trois boutons qui répondent au critère de sélection et donc on pourrait utiliser individuellement <code>theButtons[0]</code>, <code>theButtons[1]</code>, et <code>theButtons[2]</code> en tant que références symboliques aux noeuds/boutons respectifs. Très souvent, en revanche, nous ne pouvons pas savoir à l'avance combien d'éléments seront disponibles sur l'interface (surtout s'ils sont générés dynamiquement et/ou le nombre d'éléments varie en fonction de l'état de l'application). Ou encore ils sont trop nombreux pour les énumérer tous manuellement. À ce moment, on peut utiliser l'itération pour accéder de manière récursive à tous les éléments dans la liste des noeuds, indépendamment de sa longueur. Voici le code de l'exemple <code>01-02</code> qui applique ce principe en utilisant un '''cycle <code>for</code>''' :


<source lang="JavaScript">
<source lang="JavaScript" line="" start="38">
//Select all buttons with class="interactiveElement"
//Select all buttons with class="interactiveElement"
var theButtons = document.querySelectorAll('.interactiveElement');
var theButtons = document.querySelectorAll('.interactiveElement');
Ligne 703 : Ligne 719 :
  Third interactive button
  Third interactive button


{{ bloc important | '''Important''' : pour accéder à tous les éléments d'une liste de noeuds, on peut utiliser l'itération du cycle for. À l'intérieur du cycle, nous pouvons accéder à l'élément spécifique grâce à son index progressif [0], [1], ... [n] où [n] est déterminée par la longueur de la liste (propriété .length) }}
{{bloc important | '''Important''' : pour accéder à tous les éléments d'une liste de noeuds, on peut utiliser l'itération du cycle for. À l'intérieur du cycle, nous pouvons accéder à l'élément spécifique grâce à son index progressif [0], [1], ... [n] où [n] est déterminée par la longueur de la liste (propriété .length) }}


; Références croisées :
; Références croisées :
Ligne 713 : Ligne 729 :
Une fois que nous avons accès individuellement et de manière programmée à chaque noeud/bouton contenu dans notre liste, nous pouvons lui appliquer toute sorte de caractéristique, y compris un gestionnaire d'événement comme nous avons fait dans la section 1. Il suffira de le faire à l'intérieur du cycle for et faisant bien attention d'utiliser toujours la référence à son index dans la liste à travers la notation <code>theButtons[i]</code>. Voici le code de l'exemple <code>02-03</code> qui associe un gestionnaire d'événement au '''click''' sur chaque bouton :
Une fois que nous avons accès individuellement et de manière programmée à chaque noeud/bouton contenu dans notre liste, nous pouvons lui appliquer toute sorte de caractéristique, y compris un gestionnaire d'événement comme nous avons fait dans la section 1. Il suffira de le faire à l'intérieur du cycle for et faisant bien attention d'utiliser toujours la référence à son index dans la liste à travers la notation <code>theButtons[i]</code>. Voici le code de l'exemple <code>02-03</code> qui associe un gestionnaire d'événement au '''click''' sur chaque bouton :


<source lang="JavaScript">
<source lang="JavaScript" line="" start="38">
//Select all buttons with class="interactiveElement"
//Select all buttons with class="interactiveElement"
var theButtons = document.querySelectorAll('.interactiveElement');
var theButtons = document.querySelectorAll('.interactiveElement');
Ligne 728 : Ligne 744 :
La partie qui nous intéresse est la suivante :
La partie qui nous intéresse est la suivante :


<source lang="JavaScript">
<source lang="JavaScript" line="" start="43" highlight="1">
theButtons[i].addEventListener('click', function () {
theButtons[i].addEventListener('click', function () {
     //Print the label of the clicked button
     //Print the label of the clicked button
Ligne 741 : Ligne 757 :
'''Hint''' : pour bien comprendre l'importance d'utiliser <code>let</code> au lieu de <code>var</code>, vous pouvez essayer de changer à la ligne <code>02-03 Ligne 41</code>. L'exemple ne marchera plus. L'explication de ce phénomène dépasse les objectifs de cet article, mais retenez juste d'utiliser <code>let</code> à l'intérieur des cycles, surtout si vous voulez appliquer des gestionnaires d'événements aux noeuds.
'''Hint''' : pour bien comprendre l'importance d'utiliser <code>let</code> au lieu de <code>var</code>, vous pouvez essayer de changer à la ligne <code>02-03 Ligne 41</code>. L'exemple ne marchera plus. L'explication de ce phénomène dépasse les objectifs de cet article, mais retenez juste d'utiliser <code>let</code> à l'intérieur des cycles, surtout si vous voulez appliquer des gestionnaires d'événements aux noeuds.


{{ bloc important | Une fois que nous avons accès, grâce à l'itération d'un cycle for, individuellement aux noeuds d'une liste, nous pouvons leur appliquer des gestionnaires d'événements tout comme nous avons fait dans la section 1. Il faudra juste bien penser à référencer l'élément à travers son index dans la liste. }}
{{bloc important | Une fois que nous avons accès, grâce à l'itération d'un cycle for, individuellement aux noeuds d'une liste, nous pouvons leur appliquer des gestionnaires d'événements tout comme nous avons fait dans la section 1. Il faudra juste bien penser à référencer l'élément à travers son index dans la liste. }}


==== Afficher un feedback lorsqu'on clique sur chaque bouton ====
==== Afficher un feedback lorsqu'on clique sur chaque bouton ====
Ligne 747 : Ligne 763 :
Cet exemple ne fait que modifier la fonction associée au gestionnaire d'événement pour qu'un feedback visuel modifie l'interface utilisateur, ainsi que l'utilisateur puisse s'apercevoir du changement. Voici le code de l'exemple <code>02-04</code> :
Cet exemple ne fait que modifier la fonction associée au gestionnaire d'événement pour qu'un feedback visuel modifie l'interface utilisateur, ainsi que l'utilisateur puisse s'apercevoir du changement. Voici le code de l'exemple <code>02-04</code> :


<source lang="JavaScript">
<source lang="JavaScript" line="" start="38">
//Select all buttons with class="interactiveElement"
//Select all buttons with class="interactiveElement"
var theButtons = document.querySelectorAll('.interactiveElement');
var theButtons = document.querySelectorAll('.interactiveElement');
Ligne 764 : Ligne 780 :
À ce stade, le code devrait être auto-explicatif. Nous signalons tout simplement l'utilisation à la ligne <code>02-04 Ligne 41</code> de <code>querySelector('#elementToChange')</code> qui est équivalent (mais préférable) à <code>getElementById('elementToChange')</code>. La [https://maltt-stic.github.io/stic-1-interaction-with-js/02-multiple-buttons/02-04-show-output.html page de l'exemple <code>02-04</code>] modifie le contenu du paragraphe <code>theOutput</code> en fonction du bouton cliqué.
À ce stade, le code devrait être auto-explicatif. Nous signalons tout simplement l'utilisation à la ligne <code>02-04 Ligne 41</code> de <code>querySelector('#elementToChange')</code> qui est équivalent (mais préférable) à <code>getElementById('elementToChange')</code>. La [https://maltt-stic.github.io/stic-1-interaction-with-js/02-multiple-buttons/02-04-show-output.html page de l'exemple <code>02-04</code>] modifie le contenu du paragraphe <code>theOutput</code> en fonction du bouton cliqué.


{{ bloc important | À l'intérieur du gestionnaire d'événement, on peut faire référence aux particularités d'un noeud par rapport aux autres noeud de la liste, toujours à travers la notation theButtons[i]. }}
{{bloc important | À l'intérieur du gestionnaire d'événement, on peut faire référence aux particularités d'un noeud par rapport aux autres noeud de la liste, toujours à travers la notation theButtons[i]. }}


==== Exemple d'application pédagogique ====
==== Exemple d'application pédagogique ====


Dans le dernier exemple de cette section, nous allons appliquer les concepts illustrés dans les exemples précédent pour créer un petit quiz à choix multiple, ou les différentes choix sont représentés par des boutons. Vous pouvez tester [https://maltt-stic.github.io/stic-1-interaction-with-js/02-multiple-buttons/02-05-add-logic.html la page de l'exemple <code>02-05</code>] avant de voir le code pour mieux comprendre la logique.
Dans le dernier exemple de cette section, nous allons appliquer les concepts illustrés dans les exemples précédents pour créer un petit quiz à choix multiple, ou les différentes choix sont représentés par des boutons. Vous pouvez tester [https://maltt-stic.github.io/stic-1-interaction-with-js/02-multiple-buttons/02-05-add-logic.html la page de l'exemple <code>02-05</code>] avant de voir le code pour mieux comprendre la logique.


Nous affichons le code complet de la page pour faciliter le copier/coller dans le cas vous désirez la réutiliser vite-fait, sans télécharger tous les exemples, mais il n'y a que des changements mineurs au niveau de l'interface utilisateur et même dans le code la différence est limitée à la fonction associée au gestionnaire d'événement. Voici le code de l'exemple <code>02-05</code> :
Nous affichons le code complet de la page pour faciliter le copier/coller dans le cas vous désirez la réutiliser vite-fait, sans télécharger tous les exemples, mais il n'y a que des changements mineurs au niveau de l'interface utilisateur et même dans le code la différence est limitée à la fonction associée au gestionnaire d'événement. Voici le code de l'exemple <code>02-05</code> :


<source lang="HTML5">
<source lang="HTML5" line="">


<!DOCTYPE html>
<!DOCTYPE html>
Ligne 840 : Ligne 856 :
Le code qui nous intéresse est limité au gestionnaire d'événement :
Le code qui nous intéresse est limité au gestionnaire d'événement :


<source lang="JavaScript">
<source lang="JavaScript" line="" start="47">
//You can add an event listener during the iteration
//You can add an event listener during the iteration
theButtons[i].addEventListener('click', function () {
theButtons[i].addEventListener('click', function () {
Ligne 854 : Ligne 870 :
</source>
</source>


Comme il a été le cas pour l'exemple <code>01-09</code>, nous avons ajouté un structure de contrôle dans la fonction associée au gestionnaire d'événement et qui est déclenchée chaque fois que l'un des boutons avec le nom de la ville est cliqué. Contrairement à l'exemple de la section 1, cependant, la variable qui est testée est le label/contenu du bouton qui est cliqué, récupéré grâce à la notation <code>theButtons[i].innerHTML</code>. Chaque fois qu'un bouton est cliqué, donc, on évalue l'expression suivante :
Comme c'était le cas pour l'exemple <code>01-09</code>, nous avons ajouté un structure de contrôle dans la fonction associée au gestionnaire d'événement et qui est déclenchée chaque fois que l'un des boutons avec le nom de la ville est cliqué. Contrairement à l'exemple de la section 1, cependant, la variable qui est testée est le label/contenu du bouton qui est cliqué, récupéré grâce à la notation <code>theButtons[i].innerHTML</code>. Chaque fois qu'un bouton est cliqué, donc, on évalue l'expression suivante :


* <code>theButtons[i].innerHTML == 'Paris'</code>
* <code>theButtons[i].innerHTML == 'Paris'</code>


Cette expression est <code>'''true'''</code> (i.e. "Paris" == "Paris") seulement si le bouton cliqué est effectivement celui avec le label/innerHTML Paris. Dans ce cas, un feedback confirme à l'utilisateur le bon choix en modifiant en même temps la couleur de l'output pour renforcer la réponse correcte. Dans les autres cas (i.e. "Rome" == "Paris" et "Berlin" == "Paris") l'expression est <code>'''false'''</code> est donc le output "Nope, try again!" sera affiché en rouge.
Cette expression est <code>'''true'''</code> (i.e. "Paris" == "Paris") seulement si le bouton cliqué est effectivement celui avec le label/innerHTML Paris. Dans ce cas, un feedback confirme à l'utilisateur le bon choix en modifiant en même temps la couleur de l'output pour renforcer la réponse correcte. Dans les autres cas (i.e. "Rome" == "Paris" et "Berlin" == "Paris") l'expression est <code>'''false'''</code> et donc le output "Nope, try again!" sera affiché en rouge.


{{ bloc important | '''Important''': en ajoutant une simple structure de contrôle à l'intérieur du gestionnaire d'événement, on peut assez facilement créer une application de type multiple-choice. Le gestionnaire d'événement répond différemment en fonction d'une caractéristique (dans ce cas le .innerHTML) de l'élément qui l'a délenché. }}
{{bloc important | '''Important''': en ajoutant une simple structure de contrôle à l'intérieur du gestionnaire d'événement, on peut assez facilement créer une application de type multiple-choice. Le gestionnaire d'événement répond différemment en fonction d'une caractéristique (dans ce cas le .innerHTML) de l'élément qui l'a déclenché. }}


==== Petit exercice de consolidation ====
==== Petit exercice de consolidation ====
Ligne 867 : Ligne 883 :


* Ajoutez deux boutons supplémentaires avec des réponses fausses (juste HTML)
* Ajoutez deux boutons supplémentaires avec des réponses fausses (juste HTML)
* Modifiez le code pour faire ainsi que le feedback en cas d'erreur affiche le nom de la ville choici (e.g. passe de '''Nope, try again!''' à '''Nope, the correct answer is not XXX'''). De cette manière l'utilisateur peut avoir toujours un changement perceptible dans l'interface, même suite à deux choix incorrectes consécutives.
* Modifiez le code pour faire ainsi que le feedback en cas d'erreur affiche le nom de la ville choisi (e.g. passe de '''Nope, try again!''' à '''Nope, the correct answer is not XXX'''). De cette manière l'utilisateur peut avoir toujours un changement perceptible dans l'interface, même suite à deux choix incorrectes consécutives.


=== Input ===
=== Input ===
Ligne 875 : Ligne 891 :
Les utilisateur sont désormais assez habitués aux éléments de input traditionnels qu'on trouve dans les formulaires à remplir pour effectuer un ordre, accéder à une zone protégée d'un site, ajouter des contenus aux réseaux sociaux, etc. Il est donc possible d'exploiter ces habitudes est utiliser les éléments de input pour des finalités interactives/pédagogiques.
Les utilisateur sont désormais assez habitués aux éléments de input traditionnels qu'on trouve dans les formulaires à remplir pour effectuer un ordre, accéder à une zone protégée d'un site, ajouter des contenus aux réseaux sociaux, etc. Il est donc possible d'exploiter ces habitudes est utiliser les éléments de input pour des finalités interactives/pédagogiques.


Dans cette section, nous allons surtout nous concentrer sur l'élément de input de type texte, qui est le plus répandue et le plus simple, mais il existe plusieurs types de input, dont certaines ont été introduits assez récemment avec [[HTML5]].
Dans cette section, nous allons surtout nous concentrer sur l'élément de input de type texte, qui est le plus répandu et le plus simple, mais il existe plusieurs types de input, dont certains ont été introduits assez récemment avec [[HTML5]].


==== Aperçu de quelques types d'input ====
==== Aperçu de quelques types d'input ====


Dans ce premier exemple, nous allons tous simplement illustré quelques types de input disponibles pour recueillir de l'information depuis l'utilisateur. Veuillez noter que nous nous limiterons aux aspects essentiels des éléments, sans montrer toutes les options de configuration ou stylisation possibles. Vous pouvez d'abord voir ces éléments sur la [https://maltt-stic.github.io/stic-1-interaction-with-js/03-input/03-01-inputs.html page de l'exemple <code>03-01</code>].
Dans ce premier exemple, nous allons tous simplement illustrer quelques types de input disponibles pour recueillir de l'information depuis l'utilisateur. Veuillez noter que nous nous limiterons aux aspects essentiels des éléments, sans montrer toutes les options de configuration ou stylisation possibles. Vous pouvez d'abord voir ces éléments sur la [https://maltt-stic.github.io/stic-1-interaction-with-js/03-input/03-01-inputs.html page de l'exemple <code>03-01</code>].


; Input de type texte
; Input de type texte
Ligne 909 : Ligne 925 :
; Input de type radio
; Input de type radio


Ce type d'input est pensé pour proposer à l'utilisateur différentes options prédéterminés parmi lesquels en choisir seulement une. Dans le code suivant les inputs ont été mis à l'intérieur d'une liste non ordonnée, mais cela n'est pas une obligation.
Ce type d'input est pensé pour proposer à l'utilisateur différentes options prédéterminées parmi lesquelles en choisir seulement une. Dans le code suivant les inputs ont été mis à l'intérieur d'une liste non ordonnée, mais cela n'est pas une obligation.


<source lang="HTML5">
<source lang="HTML5">
Ligne 929 : Ligne 945 :
; Input de type checkbox
; Input de type checkbox


Contrairement aux radio, les checkbox sont censés être utilisés pour sélectionner plusieurs choix en même temps. On utilise souvent ce type de input également de manière individuelle, par exemple pour activer/désactiver une option. Ici nous illustrons la version multiple.
Contrairement aux radio, les checkboxes sont censés être utilisées pour sélectionner plusieurs choix en même temps. On utilise souvent ce type de input également de manière individuelle, par exemple pour activer/désactiver une option. Ici nous illustrons la version multiple.


<source lang="HTML5">
<source lang="HTML5">
Ligne 945 : Ligne 961 :
</source>
</source>


Les mêmes principes valables pour les radios s'appliquent aux checkboxes. Nous signalons ici, mais cela concerne également les radios, qu'il faut bien distinguer entre la valeur associée aux input et la labellisation qu'on ajoute en dehors. Dans cet exemple, les deux correpondent (value="Bern" -> Bern, ...), mais parfois ce n'est pas le cas. Il faut bien se souvenir par la suite que c'est l'attribut <code>value="..."</code> qui est déterminant.  
Les mêmes principes valables pour les radios s'appliquent aux checkboxes. Nous signalons ici, mais cela concerne également les radios, qu'il faut bien distinguer entre la valeur associée aux input et la labellisation qu'on ajoute en dehors. Dans cet exemple, les deux correspondent (value="Bern" -> Bern, ...), mais parfois ce n'est pas le cas. Il faut bien se souvenir par la suite que c'est l'attribut <code>value="..."</code> qui est déterminant.  


; Select
; Select
Ligne 954 : Ligne 970 :
<select>
<select>
     <option value="AF">Africa</option>
     <option value="AF">Africa</option>
     <option vaue="AM">America</option>
     <option value="AM">America</option>
     <option value="AS">Asia</option>
     <option value="AS">Asia</option>
     <option value="EU">Europe</option>
     <option value="EU">Europe</option>
Ligne 963 : Ligne 979 :
; Textarea
; Textarea


Lorsque la quantité de texte à insérér est conséquent, il faut utiliser plutôt un textarea. Ce type d'élément est un peu particulier car il ne possède pas l'attribut <code>value="..."</code>. Pour déterminer une valeur initiale il faut écrire le texte à l'intérieur de la balise d'ouverture et de fermeture. Retenez néanmoins qu'on récupère le contenu du champ de la même manière que les autres.
Lorsque la quantité de texte à insérer est conséquente, il faut utiliser plutôt un textarea. Ce type d'élément est un peu particulier car il ne possède pas l'attribut <code>value="..."</code>. Pour déterminer une valeur initiale il faut écrire le texte à l'intérieur de la balise d'ouverture et de fermeture. Retenez néanmoins qu'on récupère le contenu du champ de la même manière que les autres.


<source lang="HTML5">
<source lang="HTML5">
Ligne 978 : Ligne 994 :
* [http://html5doctor.com/html5-forms-input-types/ HTML5 Doctor forms inputs]
* [http://html5doctor.com/html5-forms-input-types/ HTML5 Doctor forms inputs]


{{ bloc important | Il existe plusieurs types d'éléments qui permet aux utilisateurs de fournir de l'information. Dans tous les cas, l'information est gérée par l'attribut '''value'''. }}
{{bloc important | Il existe plusieurs types d'éléments qui permet aux utilisateurs de fournir de l'information. Dans tous les cas, l'information est gérée par l'attribut '''value'''. }}


==== Identifier un élément de input et sa valeur ====
==== Identifier un élément de input et sa valeur ====


Même si les éléments de input jouent un rôle particulier par rapport à l'interactivité, au niveau du DOM ils sont tout à fait des éléments comme les autres. Cela implique que pour les identifier dans une perspective script/interactivité on peut utiliser exactement la même procédure qu'on a vu pour le bouton dans la section 1. Voici le code complet de l'exemple <code>03-02</code>. Nous avons ajouté une petite variation de style car par default les éléments de input sont assez petit :
Même si les éléments de input jouent un rôle particulier par rapport à l'interactivité, au niveau du DOM ils sont des éléments tout à fait comme les autres. Cela implique que pour les identifier dans une perspective script/interactivité on peut utiliser exactement la même procédure qu'on a vu pour le bouton dans la section 1. Voici le code complet de l'exemple <code>03-02</code>. Nous avons ajouté une petite variation de style car par default les éléments de input sont assez petits :


<source lang="HTML5">
<source lang="HTML5" line="">
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<html lang="en">
Ligne 1 020 : Ligne 1 036 :
Le code qui nous intéresse se trouve comme d'habitude dans le <code><script>...</script></code> :
Le code qui nous intéresse se trouve comme d'habitude dans le <code><script>...</script></code> :


<source lang="JavaScript">
<source lang="JavaScript" line="" start="22" highlight="6">
<!-- Identify it with JavaScript -->
<!-- Identify it with JavaScript -->
<script>
<script>
Ligne 1 030 : Ligne 1 046 :
</source>
</source>


Ce code reflet exactement l'exemple <code>01-03</code> si ce n'est pour le fait qu'on utilise la méthode <code>document.querySelector('#myInteractiveTextInput')</code> pour associer l'élément de input à la référence symbolique <code>var theInput</code>.
Ce code reflète exactement l'exemple <code>01-03</code> si ce n'est qu'on utilise la méthode <code>document.querySelector('#myInteractiveTextInput')</code> pour associer l'élément de input à la référence symbolique <code>var theInput</code>.


La partie du code plus importante se trouve à l'intérieur du <code>console.log()</code> à la ligne <code>03-01 Ligne 27</code>. Comme vous pouvez le voir dans la [https://maltt-stic.github.io/stic-1-interaction-with-js/03-input/03-02-identify-inputs.html page de l'exemple <code>03-02</code>], la console affiche exactement le contenu initial du champ de input '''I am not interactive yet!'''. Pour accéder au contenu, il suffit de traiter l'attribut <code>value="..."</code> comme tout autre attribut HTML :
La partie du code plus importante se trouve à l'intérieur du <code>console.log()</code> à la ligne <code>03-01 Ligne 27</code>. Comme vous pouvez le voir dans la [https://maltt-stic.github.io/stic-1-interaction-with-js/03-input/03-02-identify-inputs.html page de l'exemple <code>03-02</code>], la console affiche exactement le contenu initial du champ de input '''I am not interactive yet!'''. Pour accéder au contenu, il suffit de traiter l'attribut <code>value="..."</code> comme tout autre attribut HTML :


<source lang="JavaScript">
<source lang="JavaScript" line="" start="27">
theInput.value
theInput.value
</source>
</source>


{{ bloc important | Pour accéder au contenu d'un champ de input, il suffit de l'identifier dans la structure du DOM et récupérer le contenu à travers l'attribut '''value'''. }}
{{bloc important | Pour accéder au contenu d'un champ de input, il suffit de l'identifier dans la structure du DOM et récupérer le contenu à travers l'attribut '''value'''. }}


; Références croisées :
; Références croisées :


* [[Tutoriel_JavaScript_c%C3%B4t%C3%A9_client#JavaScript_et_les_formulaires|JavaScript et les formulaires]] (Tutoriel JS de base)
* [[Tutoriel_JavaScript_c%C3%B4t%C3%A9_client#JavaScript_et_les_formulaires|JavaScript et les formulaires]] (Tutoriel JS côté client)


==== Ajouter un gestionnaire d'événements à un élément de input ====
==== Ajouter un gestionnaire d'événements à un élément de input ====
Ligne 1 048 : Ligne 1 064 :
Une fois que nous avons identifié l'élément de input dans le DOM et que nous savons comment récupérer sa valeur, on peut associer à l'élément un gestionnaire d'événement comme nous avons fait avec les boutons. Au lieu de l'événement '''click''', en revanche, nous allons "écouter" des changements dans le champ à travers l'événement '''input'''. Par rapport à l'exemple précédent, nous avons ajouté un paragraphe de output qui a été légèrement stylisé, donc nous illustrons le code limité au contenu de la balise <code><body>...</body></code> de l'exemple <code>03-03</code>.  
Une fois que nous avons identifié l'élément de input dans le DOM et que nous savons comment récupérer sa valeur, on peut associer à l'élément un gestionnaire d'événement comme nous avons fait avec les boutons. Au lieu de l'événement '''click''', en revanche, nous allons "écouter" des changements dans le champ à travers l'événement '''input'''. Par rapport à l'exemple précédent, nous avons ajouté un paragraphe de output qui a été légèrement stylisé, donc nous illustrons le code limité au contenu de la balise <code><body>...</body></code> de l'exemple <code>03-03</code>.  


<source lang="HTML5">
<source lang="HTML5" line="" start="26">
<h1>Inputs 3/4</h1>
<h1>Inputs 3/4</h1>
<!-- Outside a form, inputs can be identified as any other element, for instance using the id="myUniqueId" attribute -->
<!-- Outside a form, inputs can be identified as any other element, for instance using the id="myUniqueId" attribute -->
Ligne 1 073 : Ligne 1 089 :


# Même si le paragraphe de output n'a pas de contenu dans le code HTML, une fois la page téléchargé le paragraphe reflet le contenu initial du champ de input. Ceci est possible grâce à la ligne de code <code>03-03 Ligne 38</code> qui récupère le contenu du champ et l'utiliser pour déterminer le <code>.innerHTML</code> du paragraphe :  
# Même si le paragraphe de output n'a pas de contenu dans le code HTML, une fois la page téléchargé le paragraphe reflet le contenu initial du champ de input. Ceci est possible grâce à la ligne de code <code>03-03 Ligne 38</code> qui récupère le contenu du champ et l'utiliser pour déterminer le <code>.innerHTML</code> du paragraphe :  
#: <source lang="JavaScript">theOutput.innerHTML = theInput.value</source>
#:<source lang="JavaScript">theOutput.innerHTML = theInput.value</source>
#:
#:
# Nous utilisons ce même principe mais à l'intérieur d'un gestionnaire d'événement des lignes <code>03-03 Lignes 40-42</code> :
# Nous utilisons ce même principe mais à l'intérieur d'un gestionnaire d'événement des lignes <code>03-03 Lignes 40-42</code> :
#: <source lang="JavaScript">
#: <source lang="JavaScript" line="" start="39" highlight="4">
//Add an event listener for input changes (i.e. every change will be reflected as is happens)
//Add an event listener for input changes (i.e. every change will be reflected as is happens)
theInput.addEventListener('input', function () {
theInput.addEventListener('input', function () {
Ligne 1 087 : Ligne 1 103 :
'''Important''' : l'événement de type '''input''' n'est pas déterminé par le fait qu'on a utilisé un champ de type input. On utilise ce type d'événement même avec un champ de type <code>textarea</code>. Pour le champ de type <code>select</code> il est mieux d'utiliser l'événement '''change''', qui peut être utilisé également avec les autres types de input, mais qui est déclenché seulement une fois que le champ n'est plus actif (i.e. l'utilisateur sort le focus de la souris du champ en cliquant ailleurs dans la page).
'''Important''' : l'événement de type '''input''' n'est pas déterminé par le fait qu'on a utilisé un champ de type input. On utilise ce type d'événement même avec un champ de type <code>textarea</code>. Pour le champ de type <code>select</code> il est mieux d'utiliser l'événement '''change''', qui peut être utilisé également avec les autres types de input, mais qui est déclenché seulement une fois que le champ n'est plus actif (i.e. l'utilisateur sort le focus de la souris du champ en cliquant ailleurs dans la page).


{{ bloc important | On peut associer un gestionnaire d'événement à un champ de input tout comme il est possible de le faire sur les autres éléments. Dans ce cas, nous avons utilisé l''''événement de type input''' pour récupérer la valeur du champ après chaque changement et l'afficher dans un paragraphe de output. }}
{{bloc important | On peut associer un gestionnaire d'événement à un champ de input tout comme il est possible de le faire sur les autres éléments. Dans ce cas, nous avons utilisé l''''événement de type input''' pour récupérer la valeur du champ après chaque changement et l'afficher dans un paragraphe de output. }}


==== Exemple d'application pédagogique ====
==== Exemple d'application pédagogique ====


[[Fichier:Interactivité avec JavaScript - digital to binary example.png|400px|vignette|droite|Exemple d'application qui permet de passer d'un nombre digital au format binaire. Grâce au input de type number, dans certains navigateur l'utilisateur peut utiliser deux petits boutons pour modifier la valeur.]]
[[Fichier:Interactivité avec JavaScript - digital to binary example.png|400px|vignette|droite|Exemple d'application qui permet de passer d'un nombre digital au format binaire. Grâce au input de type number, dans certains navigateur l'utilisateur peut utiliser deux petits boutons pour modifier la valeur.]]
Dans le dernier exemple de cette section, nous utilisons les connaissances acquises dans les étapes précédentes pour construire une petite application pédagogique qui permet aux utilisateurs de rentrer un chiffre en format décimal et d'obtenir l'équivalent en format binaire. Comme vous pouvez le voir depuis la [https://maltt-stic.github.io/stic-1-interaction-with-js/03-input/03-04-add-logic.html page de l'exemple <code>03-04</code>, la transformation ce fait à chaque fois que l'utilisateur modifie le champ de input.  
Dans le dernier exemple de cette section, nous utilisons les connaissances acquises dans les étapes précédentes pour construire une petite application pédagogique qui permet aux utilisateurs de rentrer un chiffre en format décimal et d'obtenir l'équivalent en format binaire. Comme vous pouvez le voir depuis la [https://maltt-stic.github.io/stic-1-interaction-with-js/03-input/03-04-add-logic.html page de l'exemple <code>03-04</code>, la transformation se fait à chaque fois que l'utilisateur modifie le champ de input.  


Il y a deux particularités ultérieur à noter avant de regarder le code :
Il y a deux particularités ultérieures à noter avant de regarder le code :


# Grâce au fait que nous utilisons un champ de input de <code>type="number"</code>, au moins dans certains navigateurs (comme Google Chrome à l'image), dans le champ apparaissent deux petits boutons qui permettent d'incrémenter/décrémenter la valeur d'une unité à la fois, ce qui peut être utile si l'apprenant veut observer les changements progressifs dans la suite binaire, sans avoir à saisir rapidement les chiffres lui-même.
# Grâce au fait que nous utilisons un champ de input de <code>type="number"</code>, au moins dans certains navigateurs (comme Google Chrome à l'image), dans le champ apparaissent deux petits boutons qui permettent d'incrémenter/décrémenter la valeur d'une unité à la fois, ce qui peut être utile si l'apprenant veut observer les changements progressifs dans la suite binaire, sans avoir à saisir rapidement les chiffres lui-même.
#:
#:
# Si l'utilisateur saisie (par erreur) un caractère '''non-numérique''', un message d'erreur s'affiche dans le paragraphe de output. Ce message est généré par la logique de l'application, plus précisément à l'intérieur du gestionnaire d'événement. '''Important''' : certains navigateurs bloquent automatiquement la saisie des lettres dans le input de type number, mais laisse rentrer le caractère <code>-</code> pour les chiffres négatives et les lettres <code>e</code> ou <code>E</code> pour les exponentiels. Utilisez ces caractères pour tester.
# Si l'utilisateur saisit (par erreur) un caractère '''non-numérique''', un message d'erreur s'affiche dans le paragraphe de output. Ce message est généré par la logique de l'application, plus précisément à l'intérieur du gestionnaire d'événement. '''Important''' : certains navigateurs bloquent automatiquement la saisie des lettres dans le input de type number, mais laisse rentrer le caractère <code>-</code> pour les chiffres négatifs et les lettres <code>e</code> ou <code>E</code> pour les exponentiels. Utilisez ces caractères pour tester.


Voici le code complet de l'exemple <code>03-04</code> :
Voici le code complet de l'exemple <code>03-04</code> :


<source lang="HTML5">
<source lang="HTML5" line="">
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<html lang="en">
Ligne 1 143 : Ligne 1 159 :
         //Use a document method to identify the element, e.g. document.querySelector or document.getElementById
         //Use a document method to identify the element, e.g. document.querySelector or document.getElementById
         var theInput = document.querySelector('#myInteractiveTextInput');
         var theInput = document.querySelector('#myInteractiveTextInput');
         //Identiy the output element
         //Identify the output element
         var theOutput = document.querySelector('#output');
         var theOutput = document.querySelector('#output');
         //We output the current value in the output element when the page is loaded for consistency
         //We output the current value in the output element when the page is loaded for consistency
Ligne 1 167 : Ligne 1 183 :
Le code reprend complètement l'exemple précédent, si ce n'est pour la partie à l'intérieur du gestionnaire que nous analysons plus en détail :
Le code reprend complètement l'exemple précédent, si ce n'est pour la partie à l'intérieur du gestionnaire que nous analysons plus en détail :


<source lang="JavaScript">
<source lang="JavaScript" line="" start="45">
//Add an event listener for input changes (i.e. every change will be reflected as is happens)
//Add an event listener for input changes (i.e. every change will be reflected as is happens)
theInput.addEventListener('input', function () {
theInput.addEventListener('input', function () {
Ligne 1 182 : Ligne 1 198 :
</source>
</source>


'''Important''' : par default, la valeur d'un champ de input, indépendamment du type utilisé, est considéré comme du texte. Ceci signifie que lorsque vous saisissez le chiffre 3 dans le champ, JavaScript récupère la suite de caractères "3". Ceci implique, par exemple, que si vous allez faire une addition entre deux chiffres récupérés à travers deux champs de input, mettons "3" et "7", au lieu d'obtenir 10, vous obtenez "37".  
'''Important''' : par default, la valeur d'un champ de input, indépendamment du type utilisé, est considéré comme du texte. Ceci signifie que lorsque vous saisissez le chiffre 3 dans le champ, JavaScript récupère la suite de caractères "3". Ceci implique, par exemple, que si vous faites une addition entre deux chiffres récupérés à travers deux champs de input, mettons "3" et "7", au lieu d'obtenir 10, vous obtenez "37".  


À l'intérieur de la logique du gestionnaire d'événement nous avons ajouté des instructions (peut-être un peu tordues...) pour gérer ce phénomène :
À l'intérieur de la logique du gestionnaire d'événement nous avons ajouté des instructions (peut-être un peu tordues...) pour gérer ce phénomène :
Ligne 1 188 : Ligne 1 204 :
# D'abord, à la ligne <code>03-04 Ligne 49</code>, nous créons une variable qui va contenir la valeur du champ de texte transformé en Number :
# D'abord, à la ligne <code>03-04 Ligne 49</code>, nous créons une variable qui va contenir la valeur du champ de texte transformé en Number :
#* Si l'utilisateur rentre '''100''', la valeur récupérée est "100" (String) et grâce à <code>Number(theInput.value)</code> la valeur de <code>var num</code> sera de 100 (Number).
#* Si l'utilisateur rentre '''100''', la valeur récupérée est "100" (String) et grâce à <code>Number(theInput.value)</code> la valeur de <code>var num</code> sera de 100 (Number).
#* Si l'utilisateur se trompe et rentre par exemple '''123e''', la valeur récupérée est "123e" et grâche à la transformation de <code>Number(theInput.value)</code> la valeur de <code>var num</code> sera NaN (Not a Number).
#* Si l'utilisateur se trompe et rentre par exemple '''123e''', la valeur récupérée est "123e" et grâce à la transformation de <code>Number(theInput.value)</code> la valeur de <code>var num</code> sera NaN (Not a Number).
#:
#:
# Ensuite, dans la structure de contrôle, nous comparons la valeur du champ de texte (String) avec la ré-transformation de <code>num</code> en String. De cette manière :
# Ensuite, dans la structure de contrôle, nous comparons la valeur du champ de texte (String) avec la ré-transformation de <code>num</code> en String. De cette manière :
Ligne 1 194 : Ligne 1 210 :
#* Dans le cas de la valeur '''123e'', la comparaison sera <code>"123e" === "NaN"</code> qui est <code>false</code> et donc le message d'erreur sera affiché.
#* Dans le cas de la valeur '''123e'', la comparaison sera <code>"123e" === "NaN"</code> qui est <code>false</code> et donc le message d'erreur sera affiché.


Cet exemple un peu complexe (qui aurait pu être géré de manière différente à l’occurrence) montre qu'il faut toujours faire bien attention au type de données que nous attendons depuis les utilisateurs et apporter les transformations nécessaires si on s'attend à quelque chose de différents (ou plus précis) par rapport à du simple texte.  
Cet exemple un peu complexe (qui aurait pu être géré de manière différente à l’occurrence) montre qu'il faut toujours faire bien attention au type de données que nous attendons depuis les utilisateurs et apporter les transformations nécessaires si on s'attend à quelque chose de différent (ou plus précis) par rapport à du simple texte.  


{{ bloc important | Dans cet exemple d'application pédagogique, nous avons exploité l'événement de type input pour transformer dynamiquement et en temps réel un chiffre décimal dans son correspondant binaire. Dans la démarche, nous avons dû faire attention au fait que la valeur d'un champ de input est traitée automatiquement en tant que texte, n'importe quel type de input nous avons spécifié. Il nous a fallu donc en tenir compte et apporter des transformations dans notre logique de l'application. }}
{{bloc important | Dans cet exemple d'application pédagogique, nous avons exploité l'événement de type input pour transformer dynamiquement et en temps réel un chiffre décimal dans son correspondant binaire. Dans la démarche, nous avons dû faire attention au fait que la valeur d'un champ de input est traitée automatiquement en tant que texte, n'importe quel type de input nous avons spécifié. Il nous a fallu donc en tenir compte et apporter des transformations dans notre logique de l'application. }}


; Références croisées :
; Références croisées :
Ligne 1 208 : Ligne 1 224 :
; Exercice simple
; Exercice simple


La méthode .toString() utilisée pour transformer les chiffres de digital à binaire peut faire également des transformations en octal (base 8) ou en hexadécimal (base 16). Surtout les hexadécimal sont intéressant car ils sont utilisé souvent pour exprimer les couleurs, par exemple dans les [[CSS]].
La méthode .toString() utilisée pour transformer les chiffres de digital à binaire peut faire également des transformations en octale (base 8) ou en hexadécimale (base 16). Surtout les hexadécimales sont intéressantes car elles sont utilisées souvent pour exprimer les couleurs, par exemple dans les [[CSS]].


Modifiez l'application pour transformer le chiffre en hexadécimal.  
Modifiez l'application pour transformer le chiffre en hexadécimal.  
Ligne 1 214 : Ligne 1 230 :
; Exercice plus "challenging" au niveau conceptuel et technique
; Exercice plus "challenging" au niveau conceptuel et technique


JavaScript peut gérer des chiffres qui arrivent au maximum à '''100000000000000000'''. Toute chiffre supérieur à celle-ci sera automatiquement réduite à cette limite supérieur à cause d'un mécanisme connu en informatique sous le nom de [https://en.wikipedia.org/wiki/Integer_overflow Integer overflow]. En sachant que les utilisateurs ont la tendance à tester les limites des applications (surtout quand l'effort est minimal pour ajouter des inputs aux hasard), il y a des chances qu'ils rentrent des chiffres qui dépassent la limite. S'ils le font (vous pouvez le tester), l'application va afficher le message d'erreur '''Please, provide a valid digital number''', même si, d'un point de vue formelle, le chiffre rentré est tout à fait valable.
JavaScript peut gérer des chiffres qui arrivent au maximum à '''100000000000000000'''. Toute chiffre supérieur à celui-ci sera automatiquement réduite à cette limite supérieure à cause d'un mécanisme connu en informatique sous le nom de [https://en.wikipedia.org/wiki/Integer_overflow Integer overflow]. En sachant que les utilisateurs ont la tendance à tester les limites des applications (surtout quand l'effort est minimal pour ajouter des inputs aux hasard), il y a des chances qu'ils rentrent des chiffres qui dépassent la limite. S'ils le font (vous pouvez le tester), l'application va afficher le message d'erreur '''Please, provide a valid digital number''', même si, d'un point de vue formel, le chiffre rentré est tout à fait valable.


Essayer d'apportez donc des modifications à la logique de l'application (et si vous voulez aux consignes à l'utilisateur dans le HTML) pour limiter cette possibilité ou afficher un message d'erreur plus cohérent.
Essayez d'apporter donc des modifications à la logique de l'application (et si vous voulez aux consignes à l'utilisateur dans le HTML) pour limiter cette possibilité ou afficher un message d'erreur plus cohérent.


'''Hint''' : il s'agit d'un problème assez complexe car on ne peut pas tout simplement tester si le chiffre rentré est supérieur à 100000000000000000 car JavaScript ne connait pas des chiffres supérieurs ! Il serait comme lui demander si infini est supérieur à infini ;)  
'''Hint''' : il s'agit d'un problème assez complexe car on ne peut pas tout simplement tester si le chiffre rentré est supérieur à 100000000000000000 car JavaScript ne connait pas des chiffres supérieurs ! Ce serait comme lui demander si infini est supérieur à infini ;)  


Vous avez donc en gros deux choix :
Vous avez donc en gros deux choix :
Ligne 1 234 : Ligne 1 250 :


* '''Examples''' : fichiers avec du code qui montre l'application des éléments fondamentaux de la programmation
* '''Examples''' : fichiers avec du code qui montre l'application des éléments fondamentaux de la programmation
* '''Hands-on''' : ce dossier est mis à disposition pour que vous puissez expérimenter les exemples de votre côté (e.g. essayer de réproduire ce que vous avez vu sans faire du copier/coller)
* '''Hands-on''' : ce dossier est mis à disposition pour que vous puissiez expérimenter les exemples de votre côté (e.g. essayer de reproduire ce que vous avez vu sans faire du copier/coller)
* '''Tasks''' : ce dossier propose une série de challenges pour tester vos connaissances. Pour chaque tâche il y a l'enoncé du problème (...-challenge.js) et la solution (..-solution.js)
* '''Tasks''' : ce dossier propose une série de challenges pour tester vos connaissances. Pour chaque tâche il y a l'ennoncé du problème (...-challenge.js) et la solution (..-solution.js)


Les exemples varient en difficulté. Pour résoudre certains exemples le contenu de cette page n'est pas suffisant, il faut une lecture plus approfondie du [[Tutoriel JavaScript côté client]].
Les exemples varient en difficulté. Pour résoudre certains exemples le contenu de cette page n'est pas suffisant, il faut une lecture plus approfondie du [[Tutoriel JavaScript côté client]].
Ligne 1 260 : Ligne 1 276 :
== Bibliographie ==
== Bibliographie ==


* Peters, D. (2014). Interface Deisgn for Learning. Design Strategies for Learning Experiences. New Riders.
* Peters, D. (2014). Interface Design for Learning. Design Strategies for Learning Experiences. New Riders.
* Krug, S. (2006). Don’t Make Me Think (2nd ed.). Berkeley, CA: New Riders.
* Krug, S. (2006). Don’t Make Me Think (2nd ed.). Berkeley, CA: New Riders.
* Saffer, D. (2014). Microinteractions. Designing with details. Sebastopol, CA: O’Reilly Media. Voir également le [http://microinteractions.com/ Site web]
* Saffer, D. (2014). Microinteractions. Designing with details. Sebastopol, CA: O’Reilly Media. Voir également le [http://microinteractions.com/ Site web]
Ligne 1 266 : Ligne 1 282 :
== Ressources ==
== Ressources ==


=== Number Sorting Game ===
[http://tecfa.unige.ch/perso/mafritz/teaching/stic-1/apps/number-sorting-game/ Number Sorting Game] est une application/démo développée avec JavaScript qui permet de trier des nombres avec trois modalités interactives différentes :
# Saisir les chiffres avec le clavier
# Pointer et cliquer sur les chiffres dans l'ordre
# Ordonner les chiffres en faisant du drag&drop
Cette démo montre comme la même application peut être déclinée avec différents types d'interactivité, c'est-à-dire réagir à des types d'événements différents. Dans la première déclinaison, les événements/inputs sont déterminés par le clavier de l'utilisateur, tandis que dans la deuxième et troisième par la souris. De plus, dans la deuxième version, l'événement déclencheur est limité au clique, tandis que dans la troisième l'événement se complexifie avec le mécanisme du drag&drop.
=== Liens ===
* [https://alistapart.com/article/from-url-to-interactive/ From URL to interactive] : une collection d'articles qui expliquent les éléments techniques à la base de l'interactivité dans une page web


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

Version du 30 novembre 2021 à 17:46

Initiation à la pensée computationnelle avec JavaScript
Module: Concepts de base de JavaScript ▬▶
◀▬▬▶
à finaliser débutant
2021/11/30
Voir aussi
Catégorie: JavaScript

Introduction

Bien que JavaScript soit désormais un langage de programmation multi-purpose utilisé pour créer différents types d'applications, sa fonction primaire et la raison principale pour laquelle ce langage est aussi répandu concernent l'interactivité des pages web, ce qu'on appelle JavaScript côté-client.

Cette page complémente le Tutoriel JavaScript de base et le Tutoriel JavaScript côté client avec une approche plus ciblée sur l'interactivité qui est possible grâce à l'intégration entre JavaScript et le navigateur web. Plutôt que proposer un survol des aspects principaux, cette page illustre de manière plus approfondie et détaillée des exemples de base pour mettre en relief le fonctionnement de l'interactivité à la fois d'un point de vue conceptuel et technique.

Prérequis

Pour lire cet article des connaissances de base de HTML5 et CSS sont nécessaires. Pour des novices en JavaScript, nous conseillons d'abord de suivre le tutoriel :

L'article propose également certains aspects computationnels qui nécessite une compréhension du fonctionnement du langage JavaScript. Une lecture des parties introductives des pages computation avec JavaScript et tutoriel JavaScript de base pourrait également être utile, mais n'est pas nécessaire.

Exemples traités dans l'article

Tous les exemples illustrés dans cette page sont disponibles dans un repository de GitHub. Ils suivent une numérotation qui sera utilisée pour les référencer également dans le texte, par exemple: 00-01.

Lorsque le code des exemples est expliqué dans l'article, pour des raisons d'espace, souvent, seulement les parties indispensables à la compréhension du concept expliqué seront affichées. En général, les numéros des lignes intéressées sera fourni pour pouvoir repérer le code dans les fichiers, par exemple 00-01 Lignes 10-20.

Présentation interactive

Une présentation interactive qui peut servir d'introduction et/ou synthétise des éléments traités dans cet article est disponible :

Définition d'interactivité

Trois caractéristiques d'une application interactive qui utilise une interface utilisateur.

Malgré l'utilisation répandue du terme interactivité, il n'existe pas une définition unanime qui peut être appliquée dans les nombreux domaines dans lequel ce mot est utilisé. En général, il y a un certain accord, surtout dans le domaine de l'interaction homme-machine, à considérer l'interactivité en relation avec une interface utilisateur : une application est interactive du moment qu'elle permet à l'utilisateur, à travers des éléments identifiables sur l'interface et/ou des gestes à exécuter sur des périphériques (clavier, souris, écran tactile, ...), d'intervenir activement sur l'état de l'application. En termes plus simples, une application peut être considérée interactive si l'utilisateur peut de quelque sorte la modifier en fonction de ses propres actions.

Cette définition entraîne une série de conséquences conceptuelles et techniques qui dépassent l'objectif de cette page et qui concernent le vaste domaine de l'interaction homme-machine et l'expérience utilisateur. Néanmoins, d'un point de vue logique, cette définition comporte aux moins trois inférences qui seront utiles pour le reste de l'article. Ces inférences se réfèrent à l'état d'une application (ce qu'en anglais on appelle state). Pour faciliter la compréhension de ce concept, imaginez tout simplement de faire une capture d'écran à différents moments lorsque vous utilisez une application ou un site web. Chaque fois que vous avez une image différente, vous avez un état différent de l'application. Voici donc les trois inférences :

  1. L'interactivité présuppose le concept de variabilité
    Si l'état à un moment donné de l'application dépend de l'activité (ou non activité) de l'utilisateur, cela implique que l'application peut être différente de ce qu'elle est maintenant. Le plus une application est interactive, le plus d'états différents elle peut avoir à un moment donné suite aux décisions/interactions de l'utilisateur et/ou les états possibles envisagés par le concepteur.
  2. L'interactivité est liée à des événements
    Le concept de variabilité des états d'une application implique des changements qui se manifestent à des moments spécifiques, notamment suite aux actions de l'utilisateur. En informatique, les éléments responsables des changements dans l'état d'une application sont regroupés sous le terme de événements. De manière formelle, on peut définir un événements avec la formule Si p alors q, ce qui correspond à Pour que q s'avère, il faut que p se passe d'abord.
  3. L'interactivité défère le contrôle à l'utilisateur
    Parmi tous les événements possibles qui génèrent des changements dans l'état de l'application, pour qu'une application puisse être considérée interactive, il faut qu'au moins une partie de ces événements soient sous le contrôle direct de l'utilisateur. Le plus une application est interactive, le plus de contrôle l'utilisateur a sur les événements qui peuvent modifier l'application.
En résumé : une application interactive nécessité d'une certaine variabilité, déterminée par exemple par une série d'événements possibles, dont au moins certains sont sous le contrôle directe de l'utilisateur.

La structure d'une interaction

Structure d'une interaction, adaptation de What is a microinteraction de Saffer (2014)

Dans cet article, nous allons nous focaliser sur des interactions simples d'un point de vue technique et qui ne nécessitent qu'une manipulation limitée de l'utilisateur. Saffer (2014) qualifie ce type d'interaction en tant que micro-interaction et il les définit ainsi :

« Microinteractions differ from features in both their size and scope. Features tend to be complex (multiuse case), time consuming, and cognitively engaging. Microinteractions on the other hand are simple, brief, and should be nearly effortless. A music player is a feature; adjusting the volume is a microinteraction inside that feature. » (Saffer, 2014, p. 5)

Cette définition pourrait tout à fait convenir à nos objectifs, si ce n'est que, en ayant des (petites) applications interactives avec finalité pédagogique comme objectif de développement, nos micro-interactions peuvent requérir un effort cognitif même maximal, par exemple, si l'apprenant doit réfléchir intensivement pour décider quelle réponse sélectionner. Peters (2014) résume parfaitement ce concept en paraphrasant le "Don't make me think" de Steve Krug (2006) lorsqu'il écrit :

« Don't make me think about the interface, because I need to be thinking abouthe the learning. » (Peters, 2014)

La simplicité de la micro-interaction est donc relative, dans l'exemple précédent, à la facilité de lire et comprendre la question d'abord, et d'identifier et exécuter facilement l'action pour sélectionner la réponse sur l'interface ensuite. Une fois spécifiée cette distinction importante, nous pouvons utiliser la structure d'une micro-interaction proposée par Saffer (2014, p.14). Saffer propose quatre composantes :

  1. Trigger
    Il s'agit de l'événement qui déclenche l'interaction, l'équivalent formel de Si p
  2. Rules
    Elles déterminent le comportement de l'application suite à l'événement déclencheur, l'équivalent formel de Alors q
  3. Feedback
    Il détermine les conséquences du comportement de l'application sur l'interface utilisateur en termes de changements perceptibles par l'utilisateur. Il faut comprendre le terme feedback au sens large, pas strictement pédagogique. Un feedback interactif peut être tout simplement le curseur de la souris qui bouge lorsqu'on déplace physiquement le périphérique avec la main, ou les lettres qui s'affichent dans un champ de texte lorsqu'elles sont saisies au clavier.
  4. Loops and Modes
    Saffer ajoute une quatrième composante à sa structure d'une micro-interaction que nous ne verrons cependant pas dans le détail. En synthèse, il s'agit de l'effet que la micro-interaction a eu sur l'ensemble de l'application.

Nous proposons donc une version adaptée de la structure qui se compose des premiers trois éléments et qui est représentée par l'image sur la droite.

Structurellement, une interaction se compose (1) d'un élément déclencheur qui est associé à (2) des règles de comportement de l'application. Ces règles déterminent (3) les changements sur l'interface utilisateur qui informent l'utilisateur du résultat de l'interaction.

Principe technique de l'interactivité avec JavaScript

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

Dans une page web, l'interface utilisateur est représentée par le Document Object Model (DOM), c'est-à-dire la représentation en forme d'arborescence des noeuds/ balises HTML. Lorsque le navigateur télécharge une page web, il utilise le code source de cette page pour construire le DOM et l'afficher à l'écran en fonction d'éventuelles propriétés CSS qui déterminent le style des éléments HTML.

Or, dans une page web non dynamique, le code source qui est téléchargé n'a pas de variabilité potentielle, si ce n'est que l'utilisateur peut pointer sur une autre page et donc répéter le même mécanisme de génération du DOM à partir de nouveau code source. Au contraire, si le code source de la page téléchargée contient des scripts JavaScript, alors ces scripts peuvent fournir au navigateur les instructions nécessaires pour modifier le DOM et, par reflet, l'interface utilisateur.

Voici de suite trois pages similaires qui expliquent ce concept à l'aide des trois inférences introduites plus haut. À ce stade il ne faut pas comprendre leur code, mais plutôt le concept. Ouvrez les outils développeurs de votre navigateur et choisissez l'option qui vous permet de voir la représentation actuelle du DOM (pour Google Chrome cliquez sur F12 et puis sur le tab Elements). Comparez le code que vous voyez avec le code source de la page (en Chrome clique droit > Afficher le code source de la page).

  1. Page sans variabilité 00-01
    Il n'y a aucune différence (si ce n'est pour quelques détails marginaux) entre le code source et la représentation du DOM. Vous pouvez essayer de cliquer à différents endroits dans la page, mais aucune interactivité ne va se passer, si ce n'est des comportements standards du navigateur (e.g. sélectionner du texte). L'interface utilisateur de cette page va rester la même jusqu'au moment où l'utilisateur ferme la page ou pointe vers une autre adresse.
  2. Page avec variabilité liée à un événement temporel 00-02
    Avec la page, vous téléchargez un script avec l'instruction d'afficher un nouveau paragraphe toutes les 5 secondes. Vous pouvez noter comme à des intervalles réguliers, un nouveau noeud <p>...</p> s'ajouter à l'intérieur du <div id="injectTarget>...</div> qui, au départ, ne contient qu'un seul paragraphe. Ce type de variabilité n'est pas intéressante du tout et, surtout, est hors du contrôle de l'utilisateur qui ne peut pas arrêter le script si ce n'est en fermant la page ou pointant vers une autre adresse.
  3. Page avec variabilité liée à un événement déclenché par l'utilisateur 00-03
    Dans ce cas, en revanche, le script s'active lorsque l'utilisateur clique sur le bouton. Seulement à ce moment un nouveau paragraphe, et par reflet un nouveau noeud, s'ajoute à l'intérieur du <div id="injectTarget>...</div>.

Selon la définition de l'interactivité suggérée dans cet article, seulement la troisième page répond aux trois critères nécessaires :

  1. La page présente de la variabilité, avec potentiellement un nombre d'état "différents" infini. Bien entendu, d'un point de vue utilisateur, les états ne diffèrent pas vraiment, car on ajoute à chaque fois le même contenu. Néanmoins, du côté technique, ceci représente tout à fait un nouvel état, car on a à chaque fois une représentation du DOM différente de la précédente.
  2. La variabilité est déclenchée par un événement: le clique sur le bouton.
  3. C'est l'utilisateur qui décide si et quand cliquer sur ce bouton, en ayant ainsi le contrôle sur le comportement de l'application.
En résumé : l'interactivité avec JavaScript consiste dans le changement programmé du DOM à travers les instructions contenues dans un ou plusieurs scripts. Ces changements se reflètent dans la mise à jour de l'interface utilisateur affichée par le navigateur.

Exemples étape par étape

Nous allons présenter une série d'exemples, avec l'explication des passages étape par étape. Les exemples sont organisés en 3 sections :

  1. Bouton
    Introduction du principe de base de de l'interactivité à travers un simple bouton qui peut être cliqué par l'utilisateur. Le principe fondamental de l'identification d'un élément et l'association à un gestionnaire d'événement sont les deux aspects principaux de cette section.
  2. Plusieurs boutons
    Extension de l'exemple précédent à plusieurs éléments en même temps. Nous allons généraliser le principe de l'identification à plusieurs boutons de manière programmée et verrons comment associer des comportements différents à travers la programmation.
  3. Input
    Gestion de l'information fournie par l'utilisateur. Nous allons traiter des interactions plus articulées par rapport au point-and-click, notamment à travers la saisie de texte.

Pour la première section, chaque exemple dispose de références croisées aux Tutoriel JavaScript de base et Tutoriel JavaScript côté client pour approfondir au besoin certains aspects. Par la suite, les références seront limitées aux aspects nouveaux par rapport aux sections/exemples précédents.

Enfin, pour chaque section, nous proposons en dernier exemple une petite application pédagogique qui synthétise les concepts expliqués, ainsi qu'un petit exercice pour consolider les connaissances acquises.

Bouton

Nous allons commencer par créer un simple bouton sur lequel l'utilisateur peut cliquer et déclencher un comportement de l'application. Avant de voir l'exemple, il faut d'abord préciser que ce qu'on va faire avec un bouton peut s'appliquer à tout élément d'une page web et que le même principe s'adapte à d'autres types d'interactions (mouseover, mouseut, drag&drop, etc.).

Créer l'élément dans l'interface utilisateur

La première étape consiste tout simplement à créer physiquement le bouton sur la page. Même s'il existe différentes manières pour le faire, nous allons utiliser la stratégie la plus simple : coder à la main le bouton à travers la balise HTML <button>...</button>. Voici le code complet de l'exemple 01-01

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 
 4 <head>
 5     <title>Interactive button 1/10</title>
 6     <meta charset="UTF-8">
 7     <meta name="viewport" content="width=device-width, initial-scale=1">
 8 </head>
 9 
10 <body>
11     <h1>Interactive button 1/10</h1>
12     <!-- The first step is to determine an element that will be interactive. In this case, a button. But it can be wathever you want to. -->
13     <button>I will be interactive</button>
14 
15 </body>
16 
17 </html>

Nous avons ajouté ici l'intégralité du code du fichier, même si la partie qui nous intéresse, dans ce cas, se limite au contenu du <body>...</body>. Par la suite nous allons montrer l'intégralité du code seulement si des changements ont été appliqués dans le <head>...</head>.

Comme vous pouvez le tester dans la page de l'exemple 01-01, nous avons tout simplement un bouton, dans le style de default de votre navigateur. En effet, le navigateur associe au bouton déjà certains comportements "interactifs" quand vous passez votre souris sur la surface du bouton ou quand vous le cliquez. Cependant, il ne se passe rien après le clique car, en tant que développeurs, nous n'avons pas fourni les instructions pour que le bouton réagisse au clique de l'utilisateur.

Ceci aurait été différent si, au lieu de <button>...</button>, on avait utilisé un lien hypertextuel <a href="http://tecfa.unige.ch>Tecfa</a>. Dans ce cas le navigateur associe automatiquement le comportement de pointer vers l'adresse fournie dans l'attribut href.

En règle général, les éléments n'ont de base aucun comportement interactif, à l'exception de certains balises dont le comportement est géré automatiquement par le navigateur.

Rendre le bouton identifiable

Une interface utilisateur ou une page web se composent généralement de plusieurs éléments, souvent plusieurs éléments du même "type" (e.g. plusieurs paragraphes, plusieurs boutons, etc.). Pour associer à un élément un comportement, il faut donc pouvoir le discriminer, l'identifier par rapport aux autres éléments qui composent l'interface. Ceci peut s'obtenir de différentes manières, nous allons utiliser ici la plus simple: associer un identificateur unique au bouton à travers l'attribut id="...". Voici le code de l'exemple 01-02

11 <h1>Interactive button 2/10</h1>
12 <!-- By default, only some specific element on a webpage (e.g. <a href="page.html">page</a>) are interactive -->
13 <!-- It is thus necessary to identify the element, the simple way is through the id attrbute -->
14 <button id="interactiveIdentifier">I will be interactive</button>

La valeur de l'attribut id="..." est arbitraire, vous pouvez utiliser ce que vous voulez. Mais c'est une bonne pratique d'utiliser des valeurs saillantes, qui vous permettent par la suite de savoir quel est l'intérêt/utilité de l'élément. Une bonne stratégie consiste à utiliser un identificateur qui donne des informations sur l'action que le bouton est censé faire, plutôt que se référer à des caractéristiques de surface. Évitez donc des identificateurs de type id="boutonRouge", car vous pouvez changer d'avis sur la couleur de votre bouton, et utilisez plutôt des valeurs du type id="showMessageBtn" ou id="checkResponseBtn".

Pour qu'un élément soit interactif, il faut d'abord pouvoir l'identifier parmi d'autres éléments. La stratégie la plus simple est de lui donner un identificateur à travers un attribut id avec une valeur saillante, qui permet de deviner son utilité/comportement dans l'application.

Créer une référence au bouton en JavaScript

Une fois que l'élément peut être identifié, l'étape suivante consiste à l'intégrer dans un script. Pour ce faire, nous allons créer une variable (i.e. une boîte qui peut contenir différentes choses) et lui affecter la référence à notre bouton. Pour créer la référence, nous allons justement nous servir de l'attribut id="interactiveIdentifier". Voici le code de l'exemple 01-03 :

11 <h1>Interactive button 3/10</h1>
12 <!-- Once the elemnt can be identified, you must create a reference to it in JavaScript -->
13 <button id="interactiveIdentifier">I will be interactive</button>
14 
15 <!-- You need a script for it -->
16 <script>
17     //Create a symbolic reference (i.e. a variable) to the HTML element
18     var theButton = document.getElementById('interactiveIdentifier');
19     //Show the reference in the console (open the console to see what it gives)
20     console.log(theButton);
21 </script>

Ce code fait deux choses :

  1. Ligne 18 : il crée une référence symbolique (i.e. une variable) à notre bouton. Le bouton est identifié à travers la méthode document.getElementById('interactiveIdentifier')
  2. Ligne 20 : il output à la console la valeur de la variable

La partie qui nous intéresse le plus est celle où on crée une référence symbolique au bouton. Il y a différentes manières pour le faire et selon le cas ce passage n'est même pas nécessaire, mais cela nous sert pour expliquer le concept illustré à l'image :

Créer une référence à un élément du DOM en JavaScript

Grâce au fait qu'on utilise la valeur de l'attribut id="interactiveIdentifier" en tant qu'argument de la méthode document.getElementById('interactiveIdentifier'), nous sommes maintenant en grès d'accéder à notre bouton dans un script. Pour que ce soit plus pratique, nous avons utilisé une variable que nous avons nommée var theButton, mais comme il a été le cas pour l'attribut id, ce nom est arbitraire. Encore une fois, le choix de noms saillants facilite néanmoins la lisibilité et la compréhension de l'intention du code.

Lorsque vous ouvrez la console de votre navigateur web dans la page de l'exemple 01-03, vous pouvez bien noter comme il s'affiche tout simplement le noeud HTML représenté par notre bouton :

La variable theButton est maintenant une référence exacte au noeud HTML représenté par le bouton.
Pour associer des comportements interactifs avec JavaScript, il faut pouvoir accéder à l'élément à l'intérieur d'un script. Nous avons exploité l'id du bouton pour l'identifier dans le document et créer une variable pour avoir une référence symbolique à l'élément.
Références croisés

Accéder aux informations du bouton à travers JavaScript

Une fois qu'on a une référence symbolique en JavaScript, on peut accéder aux informations de l'élément. D'abord, on va intégrer un peu de CSS pour styliser le bouton. Pour ce faire, nous allons associer une classe de style au bouton. Voici le code complet de l'exemple 01-04 :

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 
 4 <head>
 5     <title>Interactive button 4/10</title>
 6     <meta charset="UTF-8">
 7     <meta name="viewport" content="width=device-width, initial-scale=1">
 8     <!-- We add some styling to the button through CSS -->
 9     <style>
10         .betterButtonInterface {
11             background-color: #066;
12             color: #FFF;
13             font-size: 20px;
14             padding: 5px 10px;
15         }
16     </style>
17 </head>
18 
19 <body>
20     <h1>Interactive button 4/10</h1>
21     <!-- The interactive element -->
22     <button id="interactiveIdentifier" class="betterButtonInterface">I will be interactive</button>
23 
24     <!-- You need a script for it -->
25     <script>
26         //Create a symbolic reference (i.e. a variable) to the HTML element
27         var theButton = document.getElementById('interactiveIdentifier');
28         //Show the reference in the console (open the console to see what it gives)
29         console.log(theButton);
30         //We can access the button attributes
31         console.log(theButton.id);
32         console.log(theButton.className);
33         //But also its content
34         console.log(theButton.innerHTML);
35     </script>
36 
37 </body>
38 
39 </html>

Ce qui nous intéresse le plus dans ce code réside en réalité dans l'output de la console de la page de l'exemple 01-04. Vous pouvez en effet noter comme à travers la variable theButton on peut récupérer en JavaScript des informations/caractéristiques du noeud/bouton :

  • theButton.id output interactiveIdentifier
  • theButton.className output betterButtonInterface (à noter que c'est className et non class, car class est un mot réservé)
  • theButton.innerHTML output le contenu du noeud, dans ce cas il s'agit simplement du texte/label du bouton I will be interactive
Une fois que nous avons une référence symbolique à un élément du DOM en JavaScript, on peut accéder à des informations/caractéristiques de cet élément.
Références croisées

Ajouter un gestionnaire d'événement

Jusqu'à présent, nous avons ajouté une référence symbolique dans le script et amélioré (vaguement) le style du bouton, mais nous n'avons toujours pas d'interactivité. Il faut que le navigateur puisse, parmi tous les cliques possibles sur la page, écouter en particulier les cliques qui sont faits sur la surface de notre bouton. C'est le rôle du gestionnaire d'événement. Voici le code de l'exemple 01-05 :

20 <h1>Interactive button 5/10</h1>
21 <!-- The interactive element -->
22 <button id="interactiveIdentifier" class="betterButtonInterface">I am interactive now!</button>
23 
24 <!-- You need a script for it -->
25 <script>
26 //Create a symbolic reference (i.e. a variable) to the HTML element
27 var theButton = document.getElementById('interactiveIdentifier');
28 //Add a listener that just print a message when the button is clicked
29 theButton.addEventListener('click', function () {
30      console.log('theButton has been clicked!');
31 });
32 </script>

La partie qui nous intéresse est encore une fois à l'intérieur du tag <script>...</script>, où on retrouve la variable theButton associée à la référence au noeud/bouton, mais en plus cette fois-ci nous avons ajouté le gestionnaire d'événements (lignes 29-31)

Le code s'explique de la manière suivante :

  1. On réutilise la variable theButton pour exploiter la référence symbolique à notre bouton. Il s'agit tout simplement d'un raccourci, on aurait pu réutiliser document.getElementById('interactiveIdentifier') à la place, mais comme ça c'est plus simple et cela nous permet éventuellement par la suite de réutiliser theButton également ailleurs.
  2. On associe à theButton la méthode addEventListener() (ligne 29) qui accepte deux paramètres :
    1. Le type d'événement que nous voulons écouter, dans ce cas click
    2. Une fonction qui est déclenchée lorsque cet événement se produit. Dans ce cas, nous utilisons une fonction anonyme (i.e. déclarée exactement à l'endroit où elle est appelée), mais on aurait pu faire autrement.
  3. À l'intérieur de cette fonction, nous avons ajouté le code qui doit être exécuté à chaque fois que l'événement click se produit. Dans ce cas spécifique, il s'agit d'un simple console.log() (ligne 30) qui va confirmer en console que le gestionnaire d'événement a bien marché.

L'image suivante résume de manière graphique ce principe :

Explication d'un gestionnaire d'événement

Vous pouvez essayer de cliquer le bouton sur la page de l'exemple 01-05 en ouvrant la console du navigateur : chaque fois qu'on clique sur le bouton, le chiffre à côté du message theButton has been clicked! va augmenter.

Important : pour rendre un élément interactif il faut lui associer un gestionnaire d'événements. Ce gestionnaire à deux fonctions principales : (1) identifier le type d'événement spécifique (e.g. click, mouseover, ...), et (2) déterminer quelle fonction (i.e. quelles instructions) doit être exécutée à chaque fois que l'événement s'avère.
Références croisées

Ajouter un gestionnaire d'événement (syntaxe alternative)

En programmation il y a toujours moyen de faire la même chose de manière différente. Nous proposons ici une syntaxe alternative, mais moins conseillée, pour obtenir exactement le même résultat de l'exemple précédent. Voici le code le code de l'exemple 01-06, limité au contenu de la balise <script>...</script> :

26 //Create a symbolic reference (i.e. a variable) to the HTML element
27 var theButton = document.getElementById('interactiveIdentifier');
28 //Add a listener that just print a message when the button is clicked (alternative syntaxe)
29 theButton.onclick = function () {
30     console.log('theButton has been clicked!');
31 };

Le principe est le même :

  1. On identifie un événement, cette fois-ci avec la notation theButton.onclick
  2. On associe à cet événement une fonction anonyme function () { ... }
  3. À l'intérieur de cette fonction, nous plaçons les instructions à exécuter. Dans ce cas, un simple console.log()
On peut ajouter un gestionnaire d'événement avec une syntaxe alternative, mais addEventListener() reste la meilleure option.
Références croisées

Montrer un feedback après le clique du bouton

À ce point, nous avons techniquement un bouton interactif. Cependant, du côté de l'utilisateur, il n'y a rien qui suggère que quelque chose se passe lorsqu'on a cliqué sur le bouton. Du point de vue expérience utilisateur, donc, il est nécessaire que l'algorithme associé au gestionnaire d'événement produise une variation dans l'interface dont l'utilisateur puisse s'apercevoir. C'est ce qu'on va faire avec l'exemple 01-06. Nous allons modifier le contenu d'un noeud que nous allons identifier, tout comme on a fait pour le bouton, à travers l'attribut id="..." :

20 <h1>Interactive button 7/10</h1>
21 <!-- The interactive element -->
22 <button id="interactiveIdentifier" class="betterButtonInterface">I am interactive now!</button>
23 
24 <!-- If we want to change some element in the DOM after the interaction, we need to identify it (as it was for the button) -->
25 <p id="elementToChange">I will be changed!</p>
26 
27 <!-- You need a script for it -->
28 <script>
29 //Create a symbolic reference (i.e. a variable) to the INTERACTIVE HTML element
30 var theButton = document.getElementById('interactiveIdentifier');
31 //Create a symbolic reference to the ELEMENT TO CHANGE after the interaction
32 var theOutput = document.getElementById('elementToChange');
33 //Add a listener that modifies the content of the paragraph
34 theButton.addEventListener('click', function () {
35     //Inside the function we give the instruction to change the content of the paragraph
36     theOutput.innerHTML = 'I have been changed through the interaction!';
37 });
38 </script>

Lorsqu'on clique sur le bouton dans la page de l'exemple 01-07, on peut s'apercevoir que le texte I will be changed devient I have been changed through the interaction!. Pour obtenir ce simple résultat nous avons :

  1. Ligne 25 : ajouté un paragraphe avec attribut id="elementToChange" pour pouvoir l'identifier dans le script
  2. Ligne 32 : créé une référence symbolique à ce noeud à travers var theOutput = document.getElementById('elementToChange'). Encore une fois, le nom de cette variable est arbitraire et devrait suivre plutôt des règles de nomenclature sémantique comme nous avons suggéré plus haut.
  3. Ligne 36 : injecté dans la fonction déclenchée par le gestionnaire d'événement une instruction qui permet de modifier le contenu du noeud avec theOutput.innerHTML = 'I have been changed through the interaction!';

L'image suivante représente graphiquement ce processus.

Modification du contenu d'un noeud suite au déclenchement d'un événement
Important : si on veut modifier un élément de l'interface suite à un événement, il faudra l'identifier pour pouvoir y accéder dans le script, et ensuite insérer à l'intérieur du gestionnaire d'événement une instruction qui modifie l'élément, ainsi que cette instruction soit exécutée seulement lorsque l'événement s'avère.
Références croisées

Ajouter plusieurs manipulations au gestionnaire d'événement

Dans l'exemple précédent, notre gestionnaire d'événement se limite à exécuter une seule instruction lorsqu'il est déclenché. Ceci n'est certainement pas une contrainte, il est tout à fait possible, et d'ailleurs intéressant, d'exécuter plusieurs instructions à la fois. Voici le code, limité au contenu de la balise <script>...</script> pour l'exemple 01-08 :

29 //Create a symbolic reference (i.e. a variable) to the INTERACTIVE HTML element
30 var theButton = document.getElementById('interactiveIdentifier');
31 //Create a symbolic reference to the ELEMENT TO CHANGE after the interaction
32 var theOutput = document.getElementById('elementToChange');
33 //Add a listener that modifies the content and style of the paragraph, as well as the button itself
34 theButton.addEventListener('click', function () {
35      //You can have multiple instructions inside the event handler
36      theOutput.innerHTML = 'I have been changed through the interaction!';
37      //You can change the interactive element itself
38      theButton.innerHTML = 'I have been clicked!';
39      //You can change the style of an element
40      theOutput.style.backgroundColor = '#000';
41      theOutput.style.color = '#FFF';
42      theOutput.style.fontSize = '20px';
43 });

Comme vous pouvez le noter sur la page de l'exemple 01-08, lorsque vous cliquez sur le bouton il y a différents changements qui concernent à la fois le paragraphe de feedback, mais également la labellisation du bouton lui-même qui change de I am interactive now à I have been clicked.

À l'intérieur de la fonction associée au gestionnaire d'événements on peut en effet mettre autant d'instructions dont on a besoin et on peut faire référence à l'intérieur de cette fonction à tous les éléments qu'on peut identifier. Dans ce cas, nous utilisons les références symboliques aux éléments theButton et theOutput, mais rien n'empêche d'identifier les éléments directement à l'intérieur de la fonction. Il s'agit encore une fois d'une question d'organisation du code.

Comparé à l'exemple précédent, nous utilisons encore une fois .innerHTML = "..." pour modifier le contenu des noeuds référencé par les deux variables. De plus, pour theOutput nous avons exploité la possibilité d'utiliser .style.propriété pour modifier certaines caractéristiques de style du paragraphe comme la couleur du texte et du fond, ainsi que la taille de la police. Veuillez noter que les noms des propriétés n'est pas exactement celui qui est utilisée dans les CSS (fontSize au lieu de font-size, backgroundColor au lieu de background-color) pour respecter les règles syntaxique de JavaScript.

Un événement peut déclencher plusieurs changements au niveau de l'interface utilisateur. Pour ce faire, il suffit que tous les changements soient définis à l'intérieur de la fonction associée au gestionnaire d'événements.
Références croisées

Ajouter de la logique computationnelle au gestionnaire d'événement

Dans la fonction qui réagit au gestionnaire d'événement, nous pouvons injecter toutes sortes de logique computationnelle, par exemple pour réagir différemment en fonction de certaines variables. Dans l'exemple 01-09 nous ajoutons une simple instruction de contrôle qui définit le type de feedback à montrer :

  • S'il est plus tôt que midi, l'output est Good morning!
  • Autrement l'output sera Good afternoon!

Le code qui nous intéresse est limité à l'intérieur du <script>...</script> :

29 //Create a symbolic reference (i.e. a variable) to the INTERACTIVE HTML element
30 var theButton = document.getElementById('interactiveIdentifier');
31 //Create a symbolic reference to the ELEMENT TO CHANGE after the interaction
32 var theOutput = document.getElementById('elementToChange');
33 //Add a listener that perform some basic logic
34 theButton.addEventListener('click', function () {
35      //You can add some computational logic inside the event listener
36      //These instructions check the current time and modify the content of the paragraph depending if it is morning or afternoon
37      var now = new Date().getHours();
38      if (now < 12) {
39            theOutput.innerHTML = '<strong>Good morning!</strong>';
40      } else {
41             theOutput.innerHTML = '<strong>Good afternoon!</strong>';
42      }
43 });

Grâce à l'intégration de la structure de contrôle, nous avons augmenté la variabilité de notre application mais sans augmenter le nombre d'interactions possibles : l'utilisateur est toujours limité à la seule possibilité de cliquer, ou pas, sur le bouton. En fonction de l'heure à laquelle vous visitez la page avec l'exemple 00-09, vous allez obtenir un output différent qui s'affiche dans le paragraphe.

La fonction qui est associée au gestionnaire d'événement peut exécuter toute type de logique, de la plus simple à la plus complexe, et augmenter donc la variabilité de l'application avec le même type d'interaction.
Références croisées

Exemple d'application pédagogique

Dans les exemples précédents, nous avons abordé les principes de l'interaction avec l'explication de cas très simples. Dans tout ces cas, les utilisateurs avaient à disposition fondamentalement seulement un type de variation possible lorsqu'ils cliquaient le bouton, à l'exclusion du cas d'un utilisateur qui clique une première fois sur le bouton de l'exemple autour de 11:59 et attend jusqu'à midi pour cliquer la deuxième fois. Dans les autres cas, l'utilisateur ne va détecter aucune variation ultérieure sur l'interface utilisateur après le premier clique sur le bouton.

Dans le dernier exemple de cette section, nous allons complexifier légèrement la logique de la fonction associée au gestionnaire d'événement pour créer un canevas d'application avec finalité pédagogique. Chaque fois que l'utilisateur clique sur le bouton, l'interface utilisateur lui propose de dire entre 1 et 10 mots qui commencent avec une lettre au hasard de l’alphabet. L'interface ne propose pas la possibilité de saisir les mots (on verra comment traiter les inputs de l'utilisateur dans la section correspondante plus bas), mais néanmoins nous avons une petite application qui peut servir à tester/améliorer les capacités langagières d'une personne. Dans ce dernier cas, il est peut être utile de tester l'exemple avant de voir son code : page de l'exemple 01-10.

Voici le code complet de l'exemple 01-10, car nous avons ajouté quelques déclarations de style pour améliorer l'interface :

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 
 4 <head>
 5     <title>Interactive button 10/10</title>
 6     <meta charset="UTF-8">
 7     <meta name="viewport" content="width=device-width, initial-scale=1">
 8     <!-- We add some styling to the button and the output through CSS -->
 9     <style>
10         .betterButtonInterface {
11             background-color: #066;
12             color: #FFF;
13             font-size: 20px;
14             padding: 5px 10px;
15         }
16 
17         .message {
18             font-size: 50px;
19             letter-spacing: 5px;
20             font-family: Courier New, Courier, monospace;
21             padding: 10px 25px;
22             text-align: center;
23         }
24 
25         .message strong {
26             font-size: 90px;
27         }
28     </style>
29 </head>
30 
31 <body>
32     <h1>Interactive button 10/10</h1>
33     <p>This simple game aims at improving your vocabulary. You will be asked to say aloud a number of words beginning with a
34         given letter.</p>
35     <!-- The interactive element -->
36     <button id="interactiveIdentifier" class="betterButtonInterface">Play!</button>
37 
38     <!-- If we want to change some element in the DOM after the interaction, we need to identify it (as it was for the button) -->
39     <p id="elementToChange" class="message"></p>
40 
41     <!-- You need a script for it -->
42     <script>
43         //Create a symbolic reference (i.e. a variable) to the INTERACTIVE HTML element
44         var theButton = document.getElementById('interactiveIdentifier');
45         //Create a symbolic reference to the ELEMENT TO CHANGE after the interaction
46         var theOutput = document.getElementById('elementToChange');
47         //Define some functions that perform some logic
48 
49         //Generate a random number between 1 and 10
50         function generateRandomNumber() {
51             return Math.floor(Math.random() * 10) + 1;
52         }
53 
54         //Generate a random letter a-z
55         function generateRandomLetter() {
56             return String.fromCharCode(97 + Math.floor(Math.random() * 26));
57         }
58         //Add a listener that return an alphanumeric string
59         theButton.addEventListener('click', function () {
60             //You can add more complex logic calling functions inside the event listener
61 
62             theOutput.innerHTML = 'Say <strong>' + generateRandomNumber() +
63                 '</strong> word(s) beginning with <strong>' + generateRandomLetter() + '</strong>';
64 
65         });
66     </script>
67 
68 </body>
69 
70 </html>

Comparé aux exemples précédents, il n'y a aucun changement substantiel au niveau de l'interface utilisateur du départ. Nous avons toujours un bouton et un paragraphe de output comme éléments nécessaires à l'interactivité. Nous avons ajouté une simple, mais insuffisante, introduction à la tâche (i.e. depuis l'instruction on ne comprend pas qu'on peut obtenir des nouvelles consignes en cliquant encore sur le bouton). La partie qui nous intéresse est donc contenue à l'intérieur de la balise <script>...</script> :

43 //Create a symbolic reference (i.e. a variable) to the INTERACTIVE HTML element
44 var theButton = document.getElementById('interactiveIdentifier');
45 //Create a symbolic reference to the ELEMENT TO CHANGE after the interaction
46 var theOutput = document.getElementById('elementToChange');
47 //Define some functions that perform some logic
48 
49 //Generate a random number between 1 and 10
50 function generateRandomNumber() {
51    return Math.floor(Math.random() * 10) + 1;
52 }
53 
54 //Generate a random letter a-z
55 function generateRandomLetter() {
56     return String.fromCharCode(97 + Math.floor(Math.random() * 26));
57 }
58 //Add a listener that return an alphanumeric string
59 theButton.addEventListener('click', function () {
60     //You can add more complex logic calling functions inside the event listener
61 
62     theOutput.innerHTML = 'Say <strong>' + generateRandomNumber() +
63                 '</strong> word(s) beginning with <strong>' + generateRandomLetter() + '</strong>';
64 
65 });

Si on analyse ce code, on peut s'apercevoir que la structure est restée similaire aux exemples précédents. Nous identifions toujours le bouton et le paragraphe, et par la suite ajoutons un gestionnaire d'événements au bouton. En considération du fait que la logique de notre application s'est un peu complexifiée, nous avons déclaré deux fonctions en dehors du gestionnaire d'événement que nous allons par la suite appeler à son intérieur :

  1. Lignes 50-52 : function generateRandomNumber() { ... } qui génère un chiffre aléatoire entre 1 et 10
  2. Lignes 55-57 : function generateRandomLetter() { ... } qui génère une lettre entre a et z

La logique interne de ces fonctions dépasse l'objectif de cette page. Nous pouvons tout simplement en faire abstraction et faire confiance à ce qui est écrit dans les commentaires du code. Chaque fois qu'on appelle generateRandomNumber() nous aurons un nombre 1-10, et chaque fois qu'on appelle generateRandomLetter() une lettre a-z.

À ce point, nous pouvons intégrer les deux fonctions à l'intérieur de la fonction associée au gestionnaire d'événement pour déterminer le output du paragraphe dans lequel afficher la consigne avec le nombre de mots à dire qui commencent avec la lettre aléatoirement choisie :

60 //You can add more complex logic calling functions inside the event listener
61 
62 theOutput.innerHTML = 'Say <strong>' + generateRandomNumber() +
63                 '</strong> word(s) beginning with <strong>' + generateRandomLetter() + '</strong>';

Nous avons utilisé une simple concaténation à l'aide de l'opérateur + pour insérer d'abord le nombre et ensuite la lettre aléatoire dans la phrase qui sera affichée en tant que contenu du noeud/paragraphe theOutput.

Grâce aux deux fonctions qui génèrent un chiffre ou une lettre aléatoire, notre application maintenant dispose d'une grande variabilité, assurée par la probabilité de tomber sur l'une des 260 combinaisons possibles, tout en gardant une seule interaction sur l'interface utilisateur. Il y des bonnes chances, donc, que l'utilisateur se retrouve avec un état différent à chaque fois qu'il clique sur le bouton. Ce qui, en termes pédagogiques, représente à la fois un challenge et une motivation à utiliser plus souvent l'application car il est "impossible de finir le jeu".

Important: lorsque la logique interne de l'application se complexifie, il est bien de la décomposer en morceaux plus petits en utilisant plusieurs fonctions qui sont par la suite appelées à l'intérieur du gestionnaire d'événements. Si on exploite dans ces fonctions la capacité des ordinateurs à générer des éléments aléatoires, on peut facilement ajouter une grande variabilité même à une interaction simple comme le clique d'un bouton.
Références croisées

Petit exercice de consolidation

Pour appliquer les connaissances acquises dans cette section, vous pouvez essayer de modifier l'exemple 01-10 pour :

  • Mieux illustrer la description de la tâche pour améliorer l'expérience utilisateur (juste code HTML).
  • Modifier de Play! à Play again! la labellisation du bouton après la première fois que l'utilisateur a cliqué sur le bouton (modification du code, voir 01-08 si vous n'avez aucune idée de comment le faire).

Plusieurs boutons

Dans cette section, nous allons appliquer les concepts abordés lors de la section précédente à plusieurs boutons en même temps. L'un des avantages de la programmation est en effet la capacité des ordinateurs à répéter la même opération (ou des opérations assez similaires) rapidement, de manière efficace et pour un grand nombre de fois, ce qui n'est pas le cas des humains qui ont une tendance naturelle à s'ennuyer assez vite dans les tâches répétitives.

L'interface utilisateur va rester très similaires aux exemples de la section 1 : il y aura toujours une zone de output où afficher des changements suite aux interactions, mais au lieu d'un seule bouton, nous en aurons plusieurs.

Dans cette section et les suivantes, nous considérons certains aspects illustrés dans la première section comme acquis. En conséquence, nous allons réduire les explications aux aspects du code les plus importants. Si des aspects ne sont pas clairs, nous vous conseillons de revoir les exemples de la section 1.

Identifier plusieurs boutons sur l'interface utilisateur

Dans ce premier exemple, nous allons voir comment sélectionner plusieurs boutons qui sont présents sur l'interface utilisateur. Encore plus que dans le premier exemple, où on avait un seul bouton, il existe différentes manières pour générer plusieurs boutons. Pour garder cet exemple simple, nous allons encore une fois les coder "à la main" avec des noeuds HTML de type <button>...</button>. Voici le contenu du <body>...</body> de l'exemple 02-01 :

17 <h1>Multiple buttons 1/5</h1>
18 <!-- If you have multiple interactive elements, you can't use the id attribute, which is meant to be unique -->
19 <!-- You can use a class or an attribute to select multiple elements -->
20 <ul>
21     <li>
22         <button class="interactiveElement">First interactive button</button>
23     </li>
24     <li>
25         <button class="interactiveElement">Second interactive button</button>
26     </li>
27     <li>
28         <button class="interactiveElement">Third interactive button</button>
29     </li>
30     <li>
31         <button>A button, but not interactive</button>
32     </li>
33 </ul>
34 <!-- Define an output element -->
35 <p id="elementToChange">No button clicked yet!</p>
36 <!-- The instructions through the script -->
37 <script>
38     //Select all buttons with class="interactiveElement"
39     var theButtons = document.querySelectorAll('.interactiveElement');
40     //Log the content of the theButtons variable, which is a list of Nodes
41     console.log(theButtons);
42 </script>

Plutôt que de créer 3 références symboliques à chaque bouton individuellement avec trois fois la méthode document.getElementById("..."), nous avons sélectionné les boutons à l'aide de leur attribut class="interactiveElement en utilisant la méthode document.querySelectorAll('.interactiveElement'). Cette méthode accepte tous les sélecteurs CSS, et donc grâce au .interactiveElement en argument, tous les éléments avec cette classe seront sélectionnés et stockés dans la référence symbolique theButtons.

La sélection multiple s'applique à tous les éléments qui répondent au critères de sélection, dans ce cas class="interactiveElement"

Vous pouvez bien noter depuis le code que seulement les trois premiers boutons de la liste possèdent cet attribut, mais pas le quatrième. En conséquence, si vous ouvrez la console sur la page de l'exemple 02-01, vous allez obtenir ce résultat :

Lorsque l'identification des éléments concernent plusieurs noeuds, le résultat est une liste de noeuds

Contrairement aux exemple de la section 1, où la référence symbolique theButton représentait le HTML du noeud/button, theButtons représente une liste de noeuds. Comme vous pouvez le voir depuis le output de la console, cette liste contient en effet 3 noeuds et même si une liste de noeud n'est pas vraiment un array (c.f. Tutoriel JavaScript côté client), la numération des noeuds commence à 0. Si vous saisissez donc theButtons[0] dans votre console, vous allez obtenir seulement le premier bouton, et donc un output tout à fait similaire à l'exemple de la section 1 :

<button class="interactiveElement">First interactive button</button>
Important: pour sélectionner plusieurs éléments en même temps, on peut exploiter la méthode querySelectorAll(), en utilisant par exemple l'attribut class des éléments. Tous les éléments qui répondent aux critères de sélection sont insérés dans une liste de noeuds, qui n'est pas exactement un array, mais dont la numération commence à 0 et par conséquent les éléments de la liste peuvent être extraits avec la notation nomDeLaListe[0], nomDeLaListe[1], ...

Faire une itération entre les noeuds/boutons

Dans notre exemple, nous savons à l'avance que nous avons seulement trois boutons qui répondent au critère de sélection et donc on pourrait utiliser individuellement theButtons[0], theButtons[1], et theButtons[2] en tant que références symboliques aux noeuds/boutons respectifs. Très souvent, en revanche, nous ne pouvons pas savoir à l'avance combien d'éléments seront disponibles sur l'interface (surtout s'ils sont générés dynamiquement et/ou le nombre d'éléments varie en fonction de l'état de l'application). Ou encore ils sont trop nombreux pour les énumérer tous manuellement. À ce moment, on peut utiliser l'itération pour accéder de manière récursive à tous les éléments dans la liste des noeuds, indépendamment de sa longueur. Voici le code de l'exemple 01-02 qui applique ce principe en utilisant un cycle for :

38 //Select all buttons with class="interactiveElement"
39 var theButtons = document.querySelectorAll('.interactiveElement');
40 //You can iterate through the buttons with a loop, for exemple a for loop
41 for (let i = 0; i < theButtons.length; i++) {
42     //Print in the console the label of the iterated button
43     console.log(theButtons[i].innerHTML);
44 }

Nous exploitons la propriété .lenght pour savoir combien d'éléments sont contenus dans la liste des noeuds, et grâce au cycle for qui incrémente la valeur de i (rappel: utilisez let au lieu de var dans les cycles) à chaque itération, nous pouvons accéder ponctuellement à l'élément theButtons[i], c'est-à-dire :

  • theButtons[0] au premier passage
  • theButtons[1] au deuxième
  • ...

Dans cet exemple, à chaque passage du cycle nous affichons à la console le contenu .innerHTML de l'élément actuel dans le cycle d'itération. Par conséquent, en ayant trois éléments dans la liste dont le contenu est tout simplement le texte/labellisation du bouton, le output sera le suivant :

First interactive button
Second interactive button
Third interactive button
Important : pour accéder à tous les éléments d'une liste de noeuds, on peut utiliser l'itération du cycle for. À l'intérieur du cycle, nous pouvons accéder à l'élément spécifique grâce à son index progressif [0], [1], ... [n] où [n] est déterminée par la longueur de la liste (propriété .length)
Références croisées

Ajouter un gestionnaire d'événements à chaque bouton

Une fois que nous avons accès individuellement et de manière programmée à chaque noeud/bouton contenu dans notre liste, nous pouvons lui appliquer toute sorte de caractéristique, y compris un gestionnaire d'événement comme nous avons fait dans la section 1. Il suffira de le faire à l'intérieur du cycle for et faisant bien attention d'utiliser toujours la référence à son index dans la liste à travers la notation theButtons[i]. Voici le code de l'exemple 02-03 qui associe un gestionnaire d'événement au click sur chaque bouton :

38 //Select all buttons with class="interactiveElement"
39 var theButtons = document.querySelectorAll('.interactiveElement');
40 //You can iterate through the buttons with a loop, for exemple a for loop
41 for (let i = 0; i < theButtons.length; i++) {
42     //You can add an event listener during the iteration
43     theButtons[i].addEventListener('click', function () {
44         //Print the label of the clicked button
45         console.log(theButtons[i].innerHTML);
46     });
47 }

La partie qui nous intéresse est la suivante :

43 theButtons[i].addEventListener('click', function () {
44     //Print the label of the clicked button
45     console.log(theButtons[i].innerHTML);
46 });

Vous pouvez bien noter que ce code est tout à fait similaire au code de l'exemple 01-05 si ce n'est, justement, par le fait qu'on utilise theButtons[i] aux deux endroits (avant .addEventListener(...) et .innerHTML) où, avec un seul élément sélectionné, on utilisait theButton.

Vous pouvez ouvrir la console sur page de l'exemple 02-03 et voir que la labellisation du bouton cliqué s'affiche en message dans la console si vous cliquez sur l'un des boutons auquel on a associé le gestionnaire d'événement. Si on clique sur le quatrième, par contre, rien ne se passe car il n'est pas contenu dans la liste des noeuds sélectionnés.

Hint : pour bien comprendre l'importance d'utiliser let au lieu de var, vous pouvez essayer de changer à la ligne 02-03 Ligne 41. L'exemple ne marchera plus. L'explication de ce phénomène dépasse les objectifs de cet article, mais retenez juste d'utiliser let à l'intérieur des cycles, surtout si vous voulez appliquer des gestionnaires d'événements aux noeuds.

Une fois que nous avons accès, grâce à l'itération d'un cycle for, individuellement aux noeuds d'une liste, nous pouvons leur appliquer des gestionnaires d'événements tout comme nous avons fait dans la section 1. Il faudra juste bien penser à référencer l'élément à travers son index dans la liste.

Afficher un feedback lorsqu'on clique sur chaque bouton

Cet exemple ne fait que modifier la fonction associée au gestionnaire d'événement pour qu'un feedback visuel modifie l'interface utilisateur, ainsi que l'utilisateur puisse s'apercevoir du changement. Voici le code de l'exemple 02-04 :

38 //Select all buttons with class="interactiveElement"
39 var theButtons = document.querySelectorAll('.interactiveElement');
40 //Identify the element to change
41 var theOutput = document.querySelector('#elementToChange'); //equivalent to document.getElementById('elementToChange');
42 //You can iterate through the buttons with a loop, for exemple a for loop
43 for (let i = 0; i < theButtons.length; i++) {
44     //You can add an event listener during the iteration
45     theButtons[i].addEventListener('click', function () {
46         //Modify the content of the output paragraph
47         theOutput.innerHTML = 'You have clicked the ' + theButtons[i].innerHTML;
48     });
49 }

À ce stade, le code devrait être auto-explicatif. Nous signalons tout simplement l'utilisation à la ligne 02-04 Ligne 41 de querySelector('#elementToChange') qui est équivalent (mais préférable) à getElementById('elementToChange'). La page de l'exemple 02-04 modifie le contenu du paragraphe theOutput en fonction du bouton cliqué.

À l'intérieur du gestionnaire d'événement, on peut faire référence aux particularités d'un noeud par rapport aux autres noeud de la liste, toujours à travers la notation theButtons[i].

Exemple d'application pédagogique

Dans le dernier exemple de cette section, nous allons appliquer les concepts illustrés dans les exemples précédents pour créer un petit quiz à choix multiple, ou les différentes choix sont représentés par des boutons. Vous pouvez tester la page de l'exemple 02-05 avant de voir le code pour mieux comprendre la logique.

Nous affichons le code complet de la page pour faciliter le copier/coller dans le cas vous désirez la réutiliser vite-fait, sans télécharger tous les exemples, mais il n'y a que des changements mineurs au niveau de l'interface utilisateur et même dans le code la différence est limitée à la fonction associée au gestionnaire d'événement. Voici le code de l'exemple 02-05 :

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 
 4 <head>
 5     <title>Multiple buttons 5/5</title>
 6     <meta charset="UTF-8">
 7     <meta name="viewport" content="width=device-width, initial-scale=1">
 8     <!-- Add some style to improve the layout -->
 9     <style>
10         body,
11         button {
12             font-size: 20px;
13         }
14 
15         ul li {
16             margin-bottom: 25px;
17         }
18     </style>
19 </head>
20 
21 <body>
22     <h1>Multiple buttons 5/5</h1>
23     <!-- If you have multiple interactive elements, you can't use the id attribute, which is meant to be unique -->
24     <p>What is the capital of France?</p>
25     <!-- You can use a class or an attribute to select multiple elements -->
26     <ul>
27         <li>
28             <button class="interactiveElement">Rome</button>
29         </li>
30         <li>
31             <button class="interactiveElement">Berlin</button>
32         </li>
33         <li>
34             <button class="interactiveElement">Paris</button>
35         </li>
36     </ul>
37     <!-- Define an output element -->
38     <p id="elementToChange">No button clicked yet!</p>
39     <!-- The instructions through the script -->
40     <script>
41         //Select all buttons with class="interactiveElement"
42         var theButtons = document.querySelectorAll('.interactiveElement');
43         //Identify the element to change
44         var theOutput = document.querySelector('#elementToChange'); //equivalent to document.getElementById('elementToChange');
45         //You can iterate through the buttons with a loop, for exemple a for loop
46         for (let i = 0; i < theButtons.length; i++) {
47             //You can add an event listener during the iteration
48             theButtons[i].addEventListener('click', function () {
49                 //You can add some logic that changes the output given what button has been clicked
50                 if (theButtons[i].innerHTML == 'Paris') {
51                     theOutput.innerHTML = 'Yes, the capital of France is Paris!';
52                     theOutput.style.color = '#060';
53                 } else {
54                     theOutput.innerHTML = 'Nope, try again!';
55                     theOutput.style.color = '#F00';
56                 }
57             });
58         }
59     </script>
60 </body>
61 
62 </html>

Le code qui nous intéresse est limité au gestionnaire d'événement :

47 //You can add an event listener during the iteration
48 theButtons[i].addEventListener('click', function () {
49     //You can add some logic that changes the output given what button has been clicked
50     if (theButtons[i].innerHTML == 'Paris') {
51         theOutput.innerHTML = 'Yes, the capital of France is Paris!';
52         theOutput.style.color = '#060';
53     } else {
54         theOutput.innerHTML = 'Nope, try again!';
55         theOutput.style.color = '#F00';
56     }
57 });

Comme c'était le cas pour l'exemple 01-09, nous avons ajouté un structure de contrôle dans la fonction associée au gestionnaire d'événement et qui est déclenchée chaque fois que l'un des boutons avec le nom de la ville est cliqué. Contrairement à l'exemple de la section 1, cependant, la variable qui est testée est le label/contenu du bouton qui est cliqué, récupéré grâce à la notation theButtons[i].innerHTML. Chaque fois qu'un bouton est cliqué, donc, on évalue l'expression suivante :

  • theButtons[i].innerHTML == 'Paris'

Cette expression est true (i.e. "Paris" == "Paris") seulement si le bouton cliqué est effectivement celui avec le label/innerHTML Paris. Dans ce cas, un feedback confirme à l'utilisateur le bon choix en modifiant en même temps la couleur de l'output pour renforcer la réponse correcte. Dans les autres cas (i.e. "Rome" == "Paris" et "Berlin" == "Paris") l'expression est false et donc le output "Nope, try again!" sera affiché en rouge.

Important: en ajoutant une simple structure de contrôle à l'intérieur du gestionnaire d'événement, on peut assez facilement créer une application de type multiple-choice. Le gestionnaire d'événement répond différemment en fonction d'une caractéristique (dans ce cas le .innerHTML) de l'élément qui l'a déclenché.

Petit exercice de consolidation

Pour appliquer les connaissances acquises dans cette section, vous pouvez essayer de modifier l'exemple 02-05 :

  • Ajoutez deux boutons supplémentaires avec des réponses fausses (juste HTML)
  • Modifiez le code pour faire ainsi que le feedback en cas d'erreur affiche le nom de la ville choisi (e.g. passe de Nope, try again! à Nope, the correct answer is not XXX). De cette manière l'utilisateur peut avoir toujours un changement perceptible dans l'interface, même suite à deux choix incorrectes consécutives.

Input

Le point-and-click illustré dans les sections précédentes est l'une des interactions les plus fréquentes dans les interfaces utilisateurs, mais présuppose que toute l'information soit déjà disponible sur l'interface ou prévue à l'avance par le concepteur. Pour un échange plus articulé entre l'utilisateur et l'interface, surtout dans les cas où l'utilisateur doit fournir l'information, il est nécessaire d'utiliser des éléments de input.

Les utilisateur sont désormais assez habitués aux éléments de input traditionnels qu'on trouve dans les formulaires à remplir pour effectuer un ordre, accéder à une zone protégée d'un site, ajouter des contenus aux réseaux sociaux, etc. Il est donc possible d'exploiter ces habitudes est utiliser les éléments de input pour des finalités interactives/pédagogiques.

Dans cette section, nous allons surtout nous concentrer sur l'élément de input de type texte, qui est le plus répandu et le plus simple, mais il existe plusieurs types de input, dont certains ont été introduits assez récemment avec HTML5.

Aperçu de quelques types d'input

Dans ce premier exemple, nous allons tous simplement illustrer quelques types de input disponibles pour recueillir de l'information depuis l'utilisateur. Veuillez noter que nous nous limiterons aux aspects essentiels des éléments, sans montrer toutes les options de configuration ou stylisation possibles. Vous pouvez d'abord voir ces éléments sur la page de l'exemple 03-01.

Input de type texte

C'est le type de input le plus fréquemment utilisé et permet aux utilisateur d'écrire toute forme de texte qui est censé avoir une longueur assez réduite.

<input type="text" value="Hello World">

L'attribut value="..." est particulièrement important, car il détermine à la fois la valeur initial du champ, mais sera utilisé également par la suite pour récupérer la valeur (voir plus bas)

Input de type number

L'élément input peut être décliné pour différents types d'informations (chiffres, email, ...). Ici à l'exemple un champ qui s'attend à des chiffres :

<input type="number" value="97">
Input de type range

Une variante de l'input numérique est représenté par le range qui propose aux utilisateur un slider à traîner pour identifier une valeur entre deux pôles (minimal et maximal).

<input type="range" value="10" min="1" max="100" step="1">
Input de type radio

Ce type d'input est pensé pour proposer à l'utilisateur différentes options prédéterminées parmi lesquelles en choisir seulement une. Dans le code suivant les inputs ont été mis à l'intérieur d'une liste non ordonnée, mais cela n'est pas une obligation.

<ul>
    <li>
        <input type="radio" name="sameForAll" value="CH"> Switzerland
    </li>
    <li>
        <input type="radio" name="sameForAll" value="FR"> France
    </li>
    <li>
        <input type="radio" name="sameForAll" value="IT"> Italy
    </li>
</ul>

Important : pour que les différents choix appartiennent au même groupe (i.e., on peut en choisir seulement une), il faut que les éléments partagent l'attribut name="..."

Input de type checkbox

Contrairement aux radio, les checkboxes sont censés être utilisées pour sélectionner plusieurs choix en même temps. On utilise souvent ce type de input également de manière individuelle, par exemple pour activer/désactiver une option. Ici nous illustrons la version multiple.

<ul>
    <li>
        <input type="checkbox" name="againSameForAll" value="Bern"> Bern
    </li>
    <li>
        <input type="checkbox" name="againSameForAll" value="Rome"> Rome
    </li>
    <li>
        <input type="checkbox" name="againSameForAll" value="Paris"> Paris
    </li>
</ul>

Les mêmes principes valables pour les radios s'appliquent aux checkboxes. Nous signalons ici, mais cela concerne également les radios, qu'il faut bien distinguer entre la valeur associée aux input et la labellisation qu'on ajoute en dehors. Dans cet exemple, les deux correspondent (value="Bern" -> Bern, ...), mais parfois ce n'est pas le cas. Il faut bien se souvenir par la suite que c'est l'attribut value="..." qui est déterminant.

Select

Le select est un menu déroulant qui affiche plusieurs choix. Dans la version que nous proposons ici, seulement un seul choix peut être sélectionné à la fois.

<select>
    <option value="AF">Africa</option>
    <option value="AM">America</option>
    <option value="AS">Asia</option>
    <option value="EU">Europe</option>
    <option value="OC">Oceania</option>
</select>
Textarea

Lorsque la quantité de texte à insérer est conséquente, il faut utiliser plutôt un textarea. Ce type d'élément est un peu particulier car il ne possède pas l'attribut value="...". Pour déterminer une valeur initiale il faut écrire le texte à l'intérieur de la balise d'ouverture et de fermeture. Retenez néanmoins qu'on récupère le contenu du champ de la même manière que les autres.

<textarea rows="15" cols="30">A text box, text field or text entry box is a graphical control element intended to enable the user to input text information
    to be used by the program. Human Interface Guidelines recommend a single-line text box when only one line of input
    is required, and a multi-line text box only if more than one line of input may be required. (Wikipedia)</textarea>
Autres éléments

Il existe bien d'autres éléments de input, surtout des variations spécifiques de la balise <input .... Pour plus d'information :

Il existe plusieurs types d'éléments qui permet aux utilisateurs de fournir de l'information. Dans tous les cas, l'information est gérée par l'attribut value.

Identifier un élément de input et sa valeur

Même si les éléments de input jouent un rôle particulier par rapport à l'interactivité, au niveau du DOM ils sont des éléments tout à fait comme les autres. Cela implique que pour les identifier dans une perspective script/interactivité on peut utiliser exactement la même procédure qu'on a vu pour le bouton dans la section 1. Voici le code complet de l'exemple 03-02. Nous avons ajouté une petite variation de style car par default les éléments de input sont assez petits :

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 
 4 <head>
 5     <title>Inputs 2/4</title>
 6     <meta charset="UTF-8">
 7     <meta name="viewport" content="width=device-width, initial-scale=1">
 8     <!-- Add some style to the input for a better layout -->
 9     <style>
10         input {
11             font-size: 20px;
12             padding: 10px 20px;
13             width: 500px;
14         }
15     </style>
16 </head>
17 
18 <body>
19     <h1>Inputs 2/4</h1>
20     <!-- Outside a form, inputs can be identified as any other element, for instance using the id="myUniqueId" attribute -->
21     <input type="text" value="I am not interactive yet!" id="myInteractiveTextInput">
22     <!-- Identify it with JavaScript -->
23     <script>
24         //Use a document method to identify the element, e.g. document.querySelector or document.getElementById
25         var theInput = document.querySelector('#myInteractiveTextInput');
26         //You can access the value of the input as a normal attribue now
27         console.log(theInput.value);
28     </script>
29 </body>
30 
31 </html>

Le code qui nous intéresse se trouve comme d'habitude dans le <script>...</script> :

22 <!-- Identify it with JavaScript -->
23 <script>
24     //Use a document method to identify the element, e.g. document.querySelector or document.getElementById
25     var theInput = document.querySelector('#myInteractiveTextInput');
26     //You can access the value of the input as a normal attribue now
27     console.log(theInput.value);
28 </script>

Ce code reflète exactement l'exemple 01-03 si ce n'est qu'on utilise la méthode document.querySelector('#myInteractiveTextInput') pour associer l'élément de input à la référence symbolique var theInput.

La partie du code plus importante se trouve à l'intérieur du console.log() à la ligne 03-01 Ligne 27. Comme vous pouvez le voir dans la page de l'exemple 03-02, la console affiche exactement le contenu initial du champ de input I am not interactive yet!. Pour accéder au contenu, il suffit de traiter l'attribut value="..." comme tout autre attribut HTML :

27 theInput.value
Pour accéder au contenu d'un champ de input, il suffit de l'identifier dans la structure du DOM et récupérer le contenu à travers l'attribut value.
Références croisées

Ajouter un gestionnaire d'événements à un élément de input

Une fois que nous avons identifié l'élément de input dans le DOM et que nous savons comment récupérer sa valeur, on peut associer à l'élément un gestionnaire d'événement comme nous avons fait avec les boutons. Au lieu de l'événement click, en revanche, nous allons "écouter" des changements dans le champ à travers l'événement input. Par rapport à l'exemple précédent, nous avons ajouté un paragraphe de output qui a été légèrement stylisé, donc nous illustrons le code limité au contenu de la balise <body>...</body> de l'exemple 03-03.

26 <h1>Inputs 3/4</h1>
27 <!-- Outside a form, inputs can be identified as any other element, for instance using the id="myUniqueId" attribute -->
28 <input type="text" value="Now I am interactive!" id="myInteractiveTextInput">
29 <!-- Use a paragraph as output -->
30 <p id="output" class="message"></p>
31 <!-- Identify it with JavaScript -->
32 <script>
33     //Use a document method to identify the element, e.g. document.querySelector or document.getElementById
34     var theInput = document.querySelector('#myInteractiveTextInput');
35     //Identiy the output element
36     var theOutput = document.querySelector('#output');
37     //We output the current value in the output element when the page is loaded for consistency
38     theOutput.innerHTML = theInput.value;
39     //Add an event listener for input changes (i.e. every change will be reflected as is happens)
40     theInput.addEventListener('input', function () {
41         //Update the output with the input string
42         theOutput.innerHTML = theInput.value;
43     });
44 </script>

Comme vous pouvez le voir dans la page de l'exemple 03-03, il y a deux éléments d'intérêt dans ce code :

  1. Même si le paragraphe de output n'a pas de contenu dans le code HTML, une fois la page téléchargé le paragraphe reflet le contenu initial du champ de input. Ceci est possible grâce à la ligne de code 03-03 Ligne 38 qui récupère le contenu du champ et l'utiliser pour déterminer le .innerHTML du paragraphe :
    theOutput.innerHTML = theInput.value
    
  2. Nous utilisons ce même principe mais à l'intérieur d'un gestionnaire d'événement des lignes 03-03 Lignes 40-42 :
    39 //Add an event listener for input changes (i.e. every change will be reflected as is happens)
    40 theInput.addEventListener('input', function () {
    41     //Update the output with the input string
    42     theOutput.innerHTML = theInput.value;
    43 });
    
    Ce code "écoute" pour tout changement dans la valeur du champ de input et, lorsqu'il en détecte un, met à jour le contenu du paragraphe de output pour qu'il reflète ce changement.

Important : l'événement de type input n'est pas déterminé par le fait qu'on a utilisé un champ de type input. On utilise ce type d'événement même avec un champ de type textarea. Pour le champ de type select il est mieux d'utiliser l'événement change, qui peut être utilisé également avec les autres types de input, mais qui est déclenché seulement une fois que le champ n'est plus actif (i.e. l'utilisateur sort le focus de la souris du champ en cliquant ailleurs dans la page).

On peut associer un gestionnaire d'événement à un champ de input tout comme il est possible de le faire sur les autres éléments. Dans ce cas, nous avons utilisé l'événement de type input pour récupérer la valeur du champ après chaque changement et l'afficher dans un paragraphe de output.

Exemple d'application pédagogique

Exemple d'application qui permet de passer d'un nombre digital au format binaire. Grâce au input de type number, dans certains navigateur l'utilisateur peut utiliser deux petits boutons pour modifier la valeur.

Dans le dernier exemple de cette section, nous utilisons les connaissances acquises dans les étapes précédentes pour construire une petite application pédagogique qui permet aux utilisateurs de rentrer un chiffre en format décimal et d'obtenir l'équivalent en format binaire. Comme vous pouvez le voir depuis la [https://maltt-stic.github.io/stic-1-interaction-with-js/03-input/03-04-add-logic.html page de l'exemple 03-04, la transformation se fait à chaque fois que l'utilisateur modifie le champ de input.

Il y a deux particularités ultérieures à noter avant de regarder le code :

  1. Grâce au fait que nous utilisons un champ de input de type="number", au moins dans certains navigateurs (comme Google Chrome à l'image), dans le champ apparaissent deux petits boutons qui permettent d'incrémenter/décrémenter la valeur d'une unité à la fois, ce qui peut être utile si l'apprenant veut observer les changements progressifs dans la suite binaire, sans avoir à saisir rapidement les chiffres lui-même.
  2. Si l'utilisateur saisit (par erreur) un caractère non-numérique, un message d'erreur s'affiche dans le paragraphe de output. Ce message est généré par la logique de l'application, plus précisément à l'intérieur du gestionnaire d'événement. Important : certains navigateurs bloquent automatiquement la saisie des lettres dans le input de type number, mais laisse rentrer le caractère - pour les chiffres négatifs et les lettres e ou E pour les exponentiels. Utilisez ces caractères pour tester.

Voici le code complet de l'exemple 03-04 :

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 
 4 <head>
 5     <title>Inputs 4/4</title>
 6     <meta charset="UTF-8">
 7     <meta name="viewport" content="width=device-width, initial-scale=1">
 8     <!-- Add some style to the input and output for a better layout -->
 9     <style>
10         body {
11             text-align: center;
12         }
13 
14         input {
15             font-size: 20px;
16             padding: 20px 20px;
17             width: 500px;
18             text-align: center;
19         }
20 
21         .binaryCode {
22             font-size: 40px;
23             font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
24             color: blueviolet;
25             letter-spacing: 3px;
26         }
27     </style>
28 </head>
29 
30 <body>
31     <h1>Inputs 4/4</h1>
32     <p>Write any digital number in the text field below to see the equivalent in binary digits.</p>
33     <!-- Outside a form, inputs can be identified as any other element, for instance using the id="myUniqueId" attribute -->
34     <input type="number" value="1" id="myInteractiveTextInput">
35     <!-- Use a paragraph as output -->
36     <p id="output" class="binaryCode"></p>
37     <!-- Identify it with JavaScript -->
38     <script>
39         //Use a document method to identify the element, e.g. document.querySelector or document.getElementById
40         var theInput = document.querySelector('#myInteractiveTextInput');
41         //Identify the output element
42         var theOutput = document.querySelector('#output');
43         //We output the current value in the output element when the page is loaded for consistency
44         theOutput.innerHTML = theInput.value;
45         //Add an event listener for input changes (i.e. every change will be reflected as is happens)
46         theInput.addEventListener('input', function () {
47             //Perform some logic with the input value to output the binary code
48             //Value from text inputs are String by default, so first convert it in Number
49             var num = Number(theInput.value);
50             //Check if there are no letters or symbols in the field (this can be done in different ways)
51             if (theInput.value === String(num)) {
52                 theOutput.innerHTML = num.toString(2);
53             } else {
54                 theOutput.innerHTML = 'Please, provide a valid digital number';
55             }
56         });
57     </script>
58 </body>
59 
60 </html>

Le code reprend complètement l'exemple précédent, si ce n'est pour la partie à l'intérieur du gestionnaire que nous analysons plus en détail :

45 //Add an event listener for input changes (i.e. every change will be reflected as is happens)
46 theInput.addEventListener('input', function () {
47     //Perform some logic with the input value to output the binary code
48     //Value from text inputs are String by default, so first convert it in Number
49     var num = Number(theInput.value);
50     //Check if there are no letters or symbols in the field (this can be done in different ways)
51     if (theInput.value === String(num)) {
52         theOutput.innerHTML = num.toString(2);
53     } else {
54         theOutput.innerHTML = 'Please, provide a valid digital number';
55     }
56 });

Important : par default, la valeur d'un champ de input, indépendamment du type utilisé, est considéré comme du texte. Ceci signifie que lorsque vous saisissez le chiffre 3 dans le champ, JavaScript récupère la suite de caractères "3". Ceci implique, par exemple, que si vous faites une addition entre deux chiffres récupérés à travers deux champs de input, mettons "3" et "7", au lieu d'obtenir 10, vous obtenez "37".

À l'intérieur de la logique du gestionnaire d'événement nous avons ajouté des instructions (peut-être un peu tordues...) pour gérer ce phénomène :

  1. D'abord, à la ligne 03-04 Ligne 49, nous créons une variable qui va contenir la valeur du champ de texte transformé en Number :
    • Si l'utilisateur rentre 100, la valeur récupérée est "100" (String) et grâce à Number(theInput.value) la valeur de var num sera de 100 (Number).
    • Si l'utilisateur se trompe et rentre par exemple 123e, la valeur récupérée est "123e" et grâce à la transformation de Number(theInput.value) la valeur de var num sera NaN (Not a Number).
  2. Ensuite, dans la structure de contrôle, nous comparons la valeur du champ de texte (String) avec la ré-transformation de num en String. De cette manière :
    • Dans le cas de la valeur 100 sa transformation en String fera ainsi que la comparaison est "100" === "100" sera true et donc on peut afficher le chiffre binaire.
    • Dans le cas de la valeur '123e, la comparaison sera "123e" === "NaN" qui est false et donc le message d'erreur sera affiché.

Cet exemple un peu complexe (qui aurait pu être géré de manière différente à l’occurrence) montre qu'il faut toujours faire bien attention au type de données que nous attendons depuis les utilisateurs et apporter les transformations nécessaires si on s'attend à quelque chose de différent (ou plus précis) par rapport à du simple texte.

Dans cet exemple d'application pédagogique, nous avons exploité l'événement de type input pour transformer dynamiquement et en temps réel un chiffre décimal dans son correspondant binaire. Dans la démarche, nous avons dû faire attention au fait que la valeur d'un champ de input est traitée automatiquement en tant que texte, n'importe quel type de input nous avons spécifié. Il nous a fallu donc en tenir compte et apporter des transformations dans notre logique de l'application.
Références croisées

Petit exercice de consolidation

Pour consolider les connaissances acquises dans cette section, nous proposons deux exercices (un simple, l'autre plus complexe) en relation avec l'exemple 03-04.

Exercice simple

La méthode .toString() utilisée pour transformer les chiffres de digital à binaire peut faire également des transformations en octale (base 8) ou en hexadécimale (base 16). Surtout les hexadécimales sont intéressantes car elles sont utilisées souvent pour exprimer les couleurs, par exemple dans les CSS.

Modifiez l'application pour transformer le chiffre en hexadécimal.

Exercice plus "challenging" au niveau conceptuel et technique

JavaScript peut gérer des chiffres qui arrivent au maximum à 100000000000000000. Toute chiffre supérieur à celui-ci sera automatiquement réduite à cette limite supérieure à cause d'un mécanisme connu en informatique sous le nom de Integer overflow. En sachant que les utilisateurs ont la tendance à tester les limites des applications (surtout quand l'effort est minimal pour ajouter des inputs aux hasard), il y a des chances qu'ils rentrent des chiffres qui dépassent la limite. S'ils le font (vous pouvez le tester), l'application va afficher le message d'erreur Please, provide a valid digital number, même si, d'un point de vue formel, le chiffre rentré est tout à fait valable.

Essayez d'apporter donc des modifications à la logique de l'application (et si vous voulez aux consignes à l'utilisateur dans le HTML) pour limiter cette possibilité ou afficher un message d'erreur plus cohérent.

Hint : il s'agit d'un problème assez complexe car on ne peut pas tout simplement tester si le chiffre rentré est supérieur à 100000000000000000 car JavaScript ne connait pas des chiffres supérieurs ! Ce serait comme lui demander si infini est supérieur à infini ;)

Vous avez donc en gros deux choix :

  1. Diminuer le range d'inputs valables (e.g. limiter à 1'000'000'000), ainsi que JavaScript puisse encore faire des comparaisons. D'ailleurs, ceci serait cohérent également avec l'expérience utilisateur pour éviter que les chiffres binaires dépassent les marges de la page ;
  2. Utiliser des contraintes sur la longueur en termes de caractères de la valeur du champ de input plutôt que sur la valeur numérique (ce qui consolide la transition/transformation entre types de données différentes).

Exercices supplémentaires

Des exercices supplémentaires sont disponibles dans le repository GitHub :

Les exercices proposent la structure des fichiers suivante :

  • Examples : fichiers avec du code qui montre l'application des éléments fondamentaux de la programmation
  • Hands-on : ce dossier est mis à disposition pour que vous puissiez expérimenter les exemples de votre côté (e.g. essayer de reproduire ce que vous avez vu sans faire du copier/coller)
  • Tasks : ce dossier propose une série de challenges pour tester vos connaissances. Pour chaque tâche il y a l'ennoncé du problème (...-challenge.js) et la solution (..-solution.js)

Les exemples varient en difficulté. Pour résoudre certains exemples le contenu de cette page n'est pas suffisant, il faut une lecture plus approfondie du Tutoriel JavaScript côté client.

Conclusion

Dans cet article, nous avons d'abord introduit le concept d'interactivité. Une application interactive se caractérise par :

  • Une certaine variabilité : les actions de l'utilisateur doivent pouvoir modifier l'application ;
  • Des événements : les actions de l'utilisateur ne peuvent pas être complètement prévues à l'avance, il faut donc prévoir des événements possibles et faire réagir l'application par conséquence ;
  • Le contrôle de l'utilisateur : les événements sont déclenchés par les actions de l'utilisateur.

D'un point de vue technique, ces aspects se traduisent par la création de gestionnaires d'événements. Un gestionnaire d'événements proposent trois composantes :

  1. Un event listener
    Il s'agit d'un bout de code qui est associé à un élément spécifique de la page, par exemple un bouton, et qui "écoute" pour un type d'événement spécifique (e.g. le clique de la souris)
  2. Une règle de comportement
    À l'intérieur du listener, il faut spécifier quel est le comportement ou la reaction attendus suite à l'événement. La règle peut être plus ou moins complexe. Dans les cas les plus complexes, la règle peut être décomposées en plusieurs fonctions.
  3. Un feedback
    L'utilisateur doit percevoir que son action à effectivement déclenché la ou les règles de comportement associées à l'événement. Un feedback doit donc apparaître sur l'interface pour confirmer le changement. Encore une fois, les changements peuvent s'exprimer de manière plus ou moins complexes. Dans les cas les plus complexes, le feedback peut être décomposées en plusieurs fonctions.

À travers une série d'exemples, nous avons appliqué ce concept fondamental à différents éléments qui peuvent être contenus dans le DOM (i.e. dans la structure) d'une page HTML. Il est important à noter que le même principe peut être appliqué, par extension, à tout type d'élément contenu dans une page (voir par exemple HTML5 audio et video, Animation avec JavaScript ou SVG avec JavaScript).

Bibliographie

  • Peters, D. (2014). Interface Design for Learning. Design Strategies for Learning Experiences. New Riders.
  • Krug, S. (2006). Don’t Make Me Think (2nd ed.). Berkeley, CA: New Riders.
  • Saffer, D. (2014). Microinteractions. Designing with details. Sebastopol, CA: O’Reilly Media. Voir également le Site web

Ressources

Number Sorting Game

Number Sorting Game est une application/démo développée avec JavaScript qui permet de trier des nombres avec trois modalités interactives différentes :

  1. Saisir les chiffres avec le clavier
  2. Pointer et cliquer sur les chiffres dans l'ordre
  3. Ordonner les chiffres en faisant du drag&drop

Cette démo montre comme la même application peut être déclinée avec différents types d'interactivité, c'est-à-dire réagir à des types d'événements différents. Dans la première déclinaison, les événements/inputs sont déterminés par le clavier de l'utilisateur, tandis que dans la deuxième et troisième par la souris. De plus, dans la deuxième version, l'événement déclencheur est limité au clique, tandis que dans la troisième l'événement se complexifie avec le mécanisme du drag&drop.

Liens

  • From URL to interactive : une collection d'articles qui expliquent les éléments techniques à la base de l'interactivité dans une page web