Les événements du DOM

Technologie web 2

Johan Girod

Qu'est-ce qu'un événement ?

Un événement est un signal déclenché par le navigateur, qui peut être écouté dans du code Javascript afin d'executer une action.

Qu'est-ce qu'un événement ?

Un événement est un signal déclenché par le navigateur, qui peut être écouté dans du code Javascript afin d'executer une action.

			
			

Qu'est-ce qu'un événement ?

Un événement est un signal déclenché par le navigateur, qui peut être écouté dans du code Javascript afin d'executer une action.

			
			

`.addEventListener(type, callback)`

  • Est une méthode présente sur tous les éléments du DOM
  • type : le type d'événement à écouter (click, mouseover, keydown, etc.)
  • callback : la fonction appelée lorsque l'événement est détecté

`.addEventListener(type, callback)`


			
		

Les évènements « bouillonnent » dans le DOM

La plupart des évènements se propagent d'éléments en éléments, depuis la cible jusqu'à la racine du document


						
;

Les évènements « bouillonnent » dans le DOM

La plupart des évènements se propagent d'éléments en éléments, depuis la cible jusqu'à la racine du document


						
;

				
							
						
			
			

Les évènements « bouillonnent » dans le DOM

La plupart des évènements se propagent d'éléments en éléments, depuis la cible jusqu'à la racine du document


						
;

				
			
							
						
			

Les évènements « bouillonnent » dans le DOM

La plupart des évènements se propagent d'éléments en éléments, depuis la cible jusqu'à la racine du document


						
;

				
			
			
							
						

Accéder à l'élément cible

On peut toujours accéder à l'élément cible de l'évènement avec la propriété event.target


			
		

Les différents types d'évènements

Les évènements de souris

  • click : un clic simple
  • dblclick : un double clic
  • mouseenter : le curseur de la souris entre dans la zone de l'élément
  • mouseover : le curseur de la souris est dans la zone de l'élément
  • mouseleave : le curseur de la souris sort de la zone de l'élément

On peut récuperer la position de la souris avec les propriétés `event.clientX` et `event.clientY` `MouseEvent`

Les évènements de clavier

  • keydown : une touche du clavier est enfoncée
  • keyup : une touche du clavier est relachée

On peut récuperer la touche pressée avec la propriété event.key (voir la documentation de KeyboardEvent)

Les évènements de focus

Lorsque l'utilisateur interagit avec un élément, ce dernier devient "actif" et reçoit le focus


  • focus : l'élément reçoit le focus
  • blur : l'élément perd le focus

Formulaire et évènements

Rappel : les formulaires en HTML


			
		

<input> et <textarea>

  • input : évènement lancé quand l'utilisateur tape du texte dans l'élément
  • change : lancé quand l'utilisateur a fini de taper
  • On peut récuperer la valeur saisie avec la propriété event.target.value


			
	

Voir la documentation MDN

<input type="checkbox">

  • change : évènement lancé quand l'utilisateur coche ou décoche la case
  • On peut récuperer l'état de la case avec la propriété event.target.checked
  • 
    			
    		
Votre choix :

<input type="radio">

  • change : évènement lancé quand l'utilisateur change d'option
  • On peut récuperer l'option choisie avec la propriété event.target.checked
  • On peut récuperer le nom du groupe de radio avec la propriété event.target.name

Voir la documentation sur MDN

<select>

  • change : évènement lancé quand l'utilisateur change d'option
  • On peut récuperer l'option choisie avec la propriété event.target.value

			
		

Voir la documentation sur MDN

À vous de jouer !

johangirod.com/cours

TP 4 UrbeXplorer

Dans ce TP, nous allons réaliser une application web pour trouver des lieux abandonnés à explorer. Le but est de pouvoir filtrer les lieux par type, d’ajouter une recherche, et de mettre en place des tris par difficulté d’accès et par avis des utilisateurs, à partir d’une page html existante.

Mise en place

  1. Cloner le projet en utilisant la commande suivante
git clone https://sources.univ-jfc.fr/techno-web-2/tp-4.git

Vous utiliserez les identifiants de votre compte universitaire pour vous connecter.

Important : Cette étape est obligatoire pour ce TP. En effet, vous sauvegarderez votre travail sur le dépôt gitlab de l’université. Vous pourrez ainsi récupérer votre travail à la prochaine séance. Si vous ne parvenez pas à cloner le projet, demandez de l’aide à votre enseignant.

  1. Ouvrez le dossier tp-4 dans votre éditeur de code (VSCode par exemple).
cd tp-4
code .

Ce projet contient un fichier index.html et un fichier script.js. Le fichier script.js est vide. C’est dans ce fichier que vous allez écrire votre code JavaScript.

Vous pouvez ouvrir le fichier index.html dans votre navigateur pour voir le rendu de la page. Elle contient une liste de lieux abandonnés à explorer, avec des images, des descriptions, des avis, etc.

  1. En fin de TP, pensez à sauvegarder votre travail sur le dépôt gitlab de l’université. Pour cela, ouvrez un terminal dans le dossier tp-4 et tapez les commandes suivantes, en remplaçant prenom et nom par votre prénom et nom :
git config --global user.name "Votre nom"
git config --global user.email "votremail@univ-jfc.fr"
git checkout -b prenom.nom
git add :/
git commit -m "TP 4 - seance 1"
git push -u
  1. Pour récupérer votre travail à la prochaine séance, vous pourrez utiliser la commande suivante :
git clone https://sources.univ-jfc.fr/techno-web-2/tp-4.git
cd tp-4
git checkout prenom.nom

Exercice 1 : Ajouter et enlever la modale d’avertissement

Au tout début du fichier index.html, vous trouverez le code de la modale d’avertissement. Une modale est une fenêtre qui s’affiche par dessus le reste de la page. Ici, elle est implémentée en utilisant l’élément HTML <dialog>, qui est celui à utiliser pour implémenter une modale.

  1. Faire en sorte que la modale s’affiche au chargement de la page :

    • Créer une fonction displayModal dans le fichier script.js.
    • Dans cette fonction, récupérez l’élément HTML <dialog> dans une variable modal.
    • Utilisez la méthode modal.showModal() pour afficher la modale.
    • Appelez displayModal.
  2. Faire en sorte que la modale se ferme quand on clique sur le bouton “J’ai compris”

    • Dans la même fonction, récupérez le noeud DOM du bouton “J’ai compris” dans une variable button.
    • Ajoutez un écouteur d’événement “click” sur le bouton (avec la méthode addEventListener).
    • Dans la fonction de rappel de l’écouteur d’événement, appelez la méthode modal.close() pour fermer la modale.
  3. Tester que tout fonctionne correctement : la modale doit s’afficher au chargement de la page, et se fermer quand on clique sur le bouton “J’ai compris”.

Astuce : pour éviter d’avoir à refermer la modale à chaque fois que vous rechargez la page pour les exercices suivants, vous pouvez commenter l’appel à la fonction displayModal.

Corrigé

Exercice 2 : faire défiler les images au hover

Dans le fichier index.html, vous pourrez voir que chaque lieu est représenté par un élément <article>. Chaque article contient un titre, ainsi que plusieurs images. Seule l’image avec la classe displayed est visible. L’objectif de cet exercice est de faire défiler les images au survol de la souris.

Première étape : créer la fonction de défilement

Nous allons créer une fonction qui change l’image affichée à chaque fois qu’elle est appellée. Pour cela, elle déplacera la classe displayed sur l’image suivante.

  1. Créer une fonction loopImage dans le fichier script.js. Cette fonction prendra en paramètre article, l’élément DOM <article> sur lequel elle doit opérer.
  2. Dans cette fonction, récupérez l’image actuellement affichée dans l’élément article (on pourra utiliser article.querySelector) dans une variable currentImage.
  3. Supprimez la classe displayed de l’image actuelle.
  4. Récupérez l’image suivante dans une variable nextImage (on pourra utiliser la propriété nextElementSibling par exemple).
  5. Si nextElementSibling est null, cela signifie que l’image actuelle est la dernière. Dans ce cas, faire en sorte que la variable nextImage contienne la première image de l’élément article.
  6. Ajoutez la classe displayed à l’image suivante.

Testez que cette fonction fonctionne en appelant par exemple loopImage(document.querySelector('article')) dans la console de votre navigateur.

Corrigé

Deuxième étape : faire défiler les images

  1. Faire en sorte que les images du premier lieu défilent automatiquement chaque seconde. Pour cela, appelez-la fonction loopImage toute les secondes avec setInterval

  2. Généraliser le défilement automatique à tous les lieux.

Troisième étape : les images défilent seulement au survol de la souris

Nous allons maintenant faire en sorte que les images ne défilent que lorsque la souris est sur le lieu. Pour cela, nous allons utiliser les événements mouseenter et mouseleave.

mouseenter est déclenché quand la souris entre dans un élément, et mouseleave quand elle en sort.

  1. Débuter le défilement au survol. Ajoutez un écouteur d’événement sur chaque élément <article>, et déplacez l’appel à setInterval dans la fonction de rappel de cet écouteur,

  2. Arrêter le défilement quand la souris quitte le lieu. Il vous faudra annuler le setInterval débuté précédement. Comment ? En utilisant la fonction clearInterval, avec comme paramètre l’identifiant de l’intervalle retourné par setInterval.

    // exemple
    const intervalId = setInterval(() => {
    	console.log('Hello');
    }, 1000);
    
    clearInterval(intervalId); // arrête l'intervalle
  3. Pour plus de réactivité, vous pouvez faire en sorte que la fonction loopImage soit appelée immédiatement au survol de la souris, puis toute les secondes.

Tester que tout fonctionne correctement : les images doivent défiler au survol de la souris, et s’arrêter quand la souris quitte le lieu.

Corrigé

Exercice 3 : Filtrer par catégorie de lieu

Chaque lieu contient des données structurées dans des attributs data-. Par exemple, data-category contient le type de lieu, data-difficulty contient la difficulté d’accès, etc.

Les attributs `data-<*>` en HTML

Les attributs commençant par data- sont des attributs personnalisés qui permettent de stocker des données supplémentaires dans un élément HTML. Ils sont très utiles pour stocker des données structurées dans une page web.

On peut accéder à ces données directement en utilisant la propriété dataset de l’élément.

Par exemple, element.dataset.category permet de récupérer la valeur de l’attribut data-category de l’élément element.

L’objectif de cet exercice est de faire en sorte que l’utilisateur puisse filtrer les lieux par type.

Le bouton de filtre est déjà présent dans le fichier index.html. Il est représenté par un élément <select> qui a comme id category.

  1. Créer une fonction filterByCategory dans le fichier script.js. Cette fonction prendra le type de lieu à filtrer en paramètre. Elle devra cacher les lieux qui ne correspondent pas et afficher ceux qui correspondent.

    • filterByCategory("industriel") doit cacher les lieux qui ne sont pas de type “industriel” et afficher ceux qui le sont.
    • filterByCategory("all") doit afficher tous les lieux.

    Pour cacher un élément, vous pouvez utiliser la méthode style.display = "none". Pour le réafficher, on utilisera style.display = "".

  2. Tester cette fonction en appelant filterByCategory('militaire') dans la console de votre navigateur.

  3. Ajouter un écouteur d’événement “change” sur l’élément <select>. Dans la fonction de rappel de cet écouteur, appelez la fonction filterByCategory avec la valeur de l’élément <select> en paramètre.

  4. Tester que tout fonctionne correctement : les lieux doivent se filtrer en fonction du type sélectionné.

Corrigé

Exercice 4 : implémenter le tri

Le bouton de tri est déjà présent dans le fichier index.html. Il est représenté par un groupe de boutons radio qui ont pour name : sort.

  1. Retrouvez l’endroit où ils sont définis. Quel élément est utilisé ? Comment sont-ils liés entre eux ?

    Corrigé
  2. Créer une fonction sortBy dans le fichier script.js. Cette fonction prendra le type de tri à effectuer en paramètre (on ne prend pas en compte l’ordre croissant ou décroissant pour commencer)

    // Exemple d'appel
    sortBy('difficulty'); // tri par difficulté d'accès

    A noter : un élément du DOM ne peut pas se retrouver à deux endroits en même temps. Pour le déplacer, il suffit juste de l’insérer à un autre endroit (il sera automatiquement retiré de son emplacement précédent).

  3. Tester cette fonction en appelant sortBy dans la console de votre navigateur. **A noter : il y a une erreur dans le code HTML : la riziere n’a pas la bonne valeur pour le data-diffulty

  4. Ajouter un écouteur d’événement “change” pour les boutons de selection du tri.

  5. Dans la fonction de rappel de cet écouteur, récupérez la nature du tri a effectuer (difficulté ou avis)

    Pour cela, vous pouvez utiliser le selecteur input[name="sort"]:checked.

    Ce dernier récupère le premier élément <input> de type “radio” qui a comme attribut name la valeur “sort” et qui est sélectionné.

  6. Tester que tout fonctionne correctement : les lieux doivent se trier en fonction du type sélectionné.

    Corrigé
  7. Faire en sorte que les boutons pour sélectionner l’ordre croissant ou décroissant fonctionnent.

Corrigé

Exercice 5 : Ajouter une recherche

Pour la recherche, nous allons ajouter un élément <input> de type “text” qui a comme id search.

L’objectif est de faire en sorte que l’utilisateur puisse taper un mot dans cet élément, et que les lieux qui ne contiennent pas ce mot dans leur titre soient cachés.

Créer une fonction search dans le fichier script.js. Cette fonction prendra le mot à rechercher en paramètre, et cachera les lieux qui ne contiennent pas ce mot dans leur titre.

Cette fonction doit être appelée à chaque fois que l’utilisateur tape une lettre dans l’élément <input>. Pour cela, ajoutez un écouteur d’événement “input” sur cet élément.

Corrigé

Exercice 6 : Ajouter la distance entre l’utilisateur et le lieu et ajouter un tri par distance

  1. Créer une fonction qui récupère la position de l’utilisateur en utilisant la méthode navigator.geolocation.getCurrentPosition. Cette méthode prend en paramètre une fonction de callback qui sera appelée avec la position de l’utilisateur en paramètre.
  2. Modifier les lieux pour ajouter la distance entre l’utilisateur et le lieu. Pour cela, vous pouvez utiliser la méthode haversine (ci-dessous) qui prend en paramètre deux coordonnées géographiques et retourne la distance en kilomètres. Les coordonnées de chaque lieu sont stockées dans le dataset de l’élément <article>.
function haversine([lat1, lon1], [lat2, lon2]) {
	toRad = function (n) {
		return (n * Math.PI) / 180;
	};
	const R = 6371; // km
	const x1 = lat2 - lat1;
	const dLat = toRad(x1);
	const x2 = lon2 - lon1;
	const dLon = toRad(x2);
	const a =
		Math.sin(dLat / 2) * Math.sin(dLat / 2) +
		Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
	const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
	const d = R * c;
	return d;
}
  1. Ajouter une option de tri par distance dans le groupe de boutons radio. Quand cette option est sélectionnée, les lieux doivent être triés par distance croissante par rapport à la position de l’utilisateur.
Corrigé