Sujet 7

  1. Bienvenue au 7e sujet
  2. Révisions
    1. Gestionnaire d'événements
    2. Gestionnaire d'événements 2
    3. Fonction anonyme
    4. Quel élément ?
    5. Ordre
    6. Création d'un élément
    7. Création 2
    8. Création 3
  3. Bubbling
    1. Fichiers HTML et CSS
    2. Clique sur « Toc ! »
    3. Correction
    4. Click sur « Tac »
    5. Correction
    6. addEventListener
    7. Gestionnaire d'événements
    8. Click sur le paragraphe
    9. Bubbling
    10. Bubbling p
    11. Bubbling : présentation
    12. Bubbling: exemple
    13. Bubbling: exemple 2
    14. Bubbling:
    15. Bubling : remontée à html
  4. Bubbling: this, Event.target
    1. this / event.target: span / body
    2. Click sur p
    3. Click sur a
    4. Click sur a
    5. Morpion bubbling
    6. Simplifier
    7. this et event.target
    8. Changer this
    9. Correction
    10. Vérifier l'élément
    11. Panier bubbling
    12. Correction panier
  5. Bubbling et HTML généré
    1. Moment d'execution
    2. Click ul
    3. Correction
    4. Élément cliqué
    5. remove()
    6. Vérifier élément
    7. Correction
  6. Tableau joueurs
    1. ajouter_joueur
    2. Correction
    3. Click sur la croix
    4. Correction
    5. Supprimer la ligne
    6. Conclusion: HTML généré et bubbling

1. Bienvenue au 7e sujet

1.1 Bienvenue au 7e sujet

Pour votre progression, c'est très important de finir le sujet précédent avant de commencer celui-ci.

Vous devez travailler connectés (lien « Connexion » en haut à droite de la page). Sinon, vous rencontrerez des problèmes d'avancement et vous risquez d'être comptés absent. En étant connectés vous retrouverez l'endroit où vous en étiez à la séance suivante.


2. Révisions

2.1 Révisions

Commençons par une rapide révision des notions des sujets précédents.


Révisions

2.2 Gestionnaire d'événements

<p>bonjour</p>
let a=document.querySelector('p');
XYZ
function coucou(){
   console.log('coucou');
}

Que faut-il écrire à la place de XYZ pour que la fonction coucou soit appelée lorsque l'utilisateur clique sur « bonjour » ?
(vous devez utiliser a)

Révisions

2.3 Gestionnaire d'événements 2

Dans l'expression suivante:

a.addEventListener('click',coucou);


Révisions

2.4 Fonction anonyme

Réécrivez en une seule ligne le code suivant, en utilisant une fonction anonyme

a.addEventListener('click',coucou);
function coucou(){
   console.log('coucou');
}
Faites bien attention aux accolades et parenthèses.

Révisions

2.5 Quel élément ?

<span id="a1">Chien</span><span  id="a2">Chat</span><span  id="a3">Souris</span>
document.getElementById('a1').addEventListener('click',abcd);
document.getElementById('a2').addEventListener('click',abcd);
document.getElementById('a3').addEventListener('click',abcd);
function abcd(){
   console.log(XYZ);
}

Que faut-il écrire à la place de XYZ pour afficher l'animal cliqué ?


Révisions

2.6 Ordre

    ...
<h1>bonjour</h1>
<script>
console.log('A');
let v=document.querySelector('h1');
console.log('B');
v.addEventListener('click',ma_fonction);
console.log('C');
function ma_fonction()
{
console.log('D');
}
console.log('E');
</script>
...
Quel est l'ordre  ?

Révisions

2.7 Création d'un élément

<body>
    <p>Vanille</p>
    <p>Framboise</p>
</body>

On voudrait ajouter un paragraphe au document précédent pour obtenir ceci:

<body>
    <p>Vanille</p>
    <p>Framboise</p>
<p>Chocolat</p>
</body>

La création d'un élément puis son insertion se fait en plusieurs étapes:

let p=document.ABC('p');
p.CDE='Chocolat';
document.body.FGH(p);
Que faut-il écrire à la place de ABC ?

Révisions

2.8 Création 2

<body>
    <p>Vanille</p>
    <p>Framboise</p>
</body>

On voudrait ajouter un paragraphe au document précédent pour obtenir ceci:

<body>
    <p>Vanille</p>
    <p>Framboise</p>
<p>Chocolat</p>
</body>

La création d'un élément puis son insertion se fait en plusieurs étapes:

let p=document.createElement('p');
p.CDE='Chocolat';
document.body.FGH(p);
Que faut-il écrire à la place de CDE ?

Révisions

2.9 Création 3

<body>
    <p>Vanille</p>
    <p>Framboise</p>
</body>

On voudrait ajouter un paragraphe au document précédent pour obtenir ceci:

<body>
    <p>Vanille</p>
    <p>Framboise</p>
<p>Chocolat</p>
</body>

La création d'un élément puis son insertion se fait en plusieurs étapes:

let p=document.createElement('p');
p.textContent='Chocolat';
document.body.FGH(p);
Que faut-il écrire à la place de FGH ?

3. Bubbling

3.1 Bubbling

Dans les pages suivants on va découvrir  le « bubbling » ... comment les événements remontent par étapes.


Bubbling

3.2 Fichiers HTML et CSS

Créez les deux fichiers suivants et vérifiez que vous avez bien cet affichage:
bubbling.html
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Bubbling</title>
<link href="bubbling.css" type="text/css" rel="stylesheet"/>
</head>
<body>
<p>
<a>Toc !</a>
<span>Tac !</span>
</p>
<script>
</script>
</body>
</html>

bubbling.css

body:after
{
content: "body";
position: absolute;
right: .3em;
top: 0em;
}

p
{
position: relative;
width: 20em;
margin: 2em;
padding: 2em;
background-color: #ff8080;
}

p:after
{
content: "p";
position: absolute;
right: .3em;
top: 0em;
}

a
{
margin: 2em;
padding: 1em;
background-color: #aecf00;
position: relative;
display: inline-block;
}

a:after
{
content: "a";
position: absolute;
right: .3em;
top: 0em;
}

span
{
display: inline-block;
margin: 2em;
padding: 1em;
background-color: #7777ff;
position: relative;
}

span:after
{
content: "span";
position: absolute;
right: .3em;
top: 0em;
}

Bubbling

3.3 Clique sur « Toc ! »

Quand l'utilisateur clique sur le « Toc ! », faites en sorte qu'une fonction (non anonyme) « click_sur_a » soit appelée. Cette fonction affichera « click_sur_a » dans la console. Vérifiez que ça s'affiche correctement dans la console.

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Bubbling

3.4 Correction


			let toc=document.querySelector('a');
toc.addEventListener('click',click_sur_a);
function click_sur_a()
{
console.log('click_sur_a');
}


Bubbling

3.5 Click sur « Tac »

Faisons la même chose pour le span:

Quand l'utilisateur clique sur le « Tac ! », faites en sorte qu'une fonction (non anonyme) « click_sur_span » soit appelée. Cette fonction affichera « click_sur_span » dans la console. Vérifiez que ça s'affiche correctement dans la console.


Bubbling

3.6 Correction


			let toc=document.querySelector('a');
toc.addEventListener('click',click_sur_a);
function click_sur_a()
{
console.log('click_sur_a');
}

let tac=document.querySelector('span');
tac.addEventListener('click',click_sur_span);
function click_sur_span()
{
console.log('click_sur_span');
}


Bubbling

3.7 addEventListener

Que fait la fonction addEventListener dans le code suivant ?

tac.addEventListener('click',click_sur_span);

Bubbling

3.8 Gestionnaire d'événements

tac.addEventListener('click',click_sur_span);

Un gestionnaire d'événements est une fonction qui a vocation à être appelée lorsqu'un événement survient.
 Le gestionnaire d’événements est la fonction click_sur_span
Elle est enregistrée sur le span « Tac ! ».
Si l'utilisateur clique sur le span, le navigateur verra que click_sur_span est enregistré sur ce span et l’appellera.

Sur Firefox, faites « clique droit -> Inspecter » sur le span.
Vous devrez voir «event » a coté du span. Si vous cliquez sur cet « event» vous verez que c'est la fonction click_sur_span.
Même chose sur le <a> « Tac » pour click_sur_a.
Vous voyez bien que ces fonctions sont bien enregistrées sur ces éléments.



Bubbling

3.9 Click sur le paragraphe

Maintenant faisons la même chose pour le paragraphe:

			let toc=document.querySelector('a');
toc.addEventListener('click',click_sur_a);
function click_sur_a()
{
console.log('click_sur_a');
}

let tac=document.querySelector('span');
tac.addEventListener('click',click_sur_span);
function click_sur_span()
{
console.log('click_sur_span');
}

let para=document.querySelector('p');
para.addEventListener('click',click_sur_p);
function click_sur_p()
{
console.log('click_sur_p');
}

Mettez à jour votre code et vérifiez que tout fonctionne.
Que s'affiche-t-il dans la console quand vous cliquez sur le <a> « Toc ! » ?

Bubbling

3.10 Bubbling

C'est bizarre ! Vous avez cliqué sur <a> et le navigateur vous dit que vous avez aussi cliqué sur <p> !

Essayons autre chose.
Enlevez tout le JS sauf celui qui concerne le paragraphe. Il ne doit rester que:

			let para=document.querySelector('p');
para.addEventListener('click',click_sur_p);
function click_sur_p()
{
console.log('click_sur_p');
}

Vérifiez que ca marche quand vous cliquez sur <p>

Bubbling

3.11 Bubbling p

Quelles affirmations sont vraies ?

Bubbling

3.12 ¤ Bubbling : présentation

Cette remontée s’appelle le « bubbling ». C'est très utile.

Bubbling

3.13 Bubbling: exemple

Dans le code suivant on a installé des gestionnaires d'événements sur tous les éléments:

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Bubbling</title>
<link href="bubbling.css" type="text/css" rel="stylesheet"/>
</head>
<body>
<p>
<a>Toc !</a>
<span>Tac !</span>
</p>
<script>
let toc=document.querySelector('a');
toc.addEventListener('click',click_sur_a);
function click_sur_a()
{
console.log('click_sur_a');
}

let tac=document.querySelector('span');
tac.addEventListener('click',click_sur_span);
function click_sur_span()
{
console.log('click_sur_span');
}

let para=document.querySelector('p');
para.addEventListener('click',click_sur_p);
function click_sur_p()
{
console.log('click_sur_p');
}

let b=document.querySelector('body');
b.addEventListener('click',click_sur_body);
function click_sur_body()
{
console.log('click_sur_body');
}

let h=document.querySelector('html');
b.addEventListener('click',click_sur_html);
function click_sur_html()
{
console.log('click_sur_html');
}
</script>
</body>
</html>

Qu'affiche la console si on clique sur « Tac ! » ?
(Essayez de répondre d'abord, avant d'exécuter le code.)



Bubbling

3.14 Bubbling: exemple 2

On suppose qu'on a le même code que la question précédente.


Qu'affiche la console si on clique sur <p> ?

(Essayez de répondre d'abord, sans exécuter le code.)

Bubbling

3.15 Bubbling:

Sur quels éléments peut-on cliquer pour provoquer l'affichage dans la console de click_sur_html ?


Bubbling

3.16 Bubling : remontée à html

En effet... tous les événements remontent jusqu'à <html> puis à document.
C'est pratique. Par exemple, si on veut réagir à tous les clicks, où qu'ils soient sur la page, il suffit d'installer un gestionnaire d'événements sur document (ou <html>). C'est qu'on à fait pour le pingouin au Sujet-1:

pingouin.html

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Pingouin</title>
<style>
.splat
{
/* Ceci permet de placer les splats avec top et left */
position: absolute;
/* La position de départ: en bas, au centre */
top: 500px;
left: 100px;
/* Agrandir 4 fois l'image */
transform: scale(4);
/* Définir les propriétés CSS à animer. Toutes en 1 seconde */
transition: top 1s,left 1s,transform 1s;
}
</style>
</head>
<body>
<img src="https://moodle.iutv.univ-paris13.fr/img/bjs/tux.png" alt="tux"/>
<script>
document.addEventListener('mousedown',ajouter_splat);
function ajouter_splat(event)
{
// Petit détail: éviter la sélection
event.preventDefault();
let i=document.createElement('img');
i.src='https://moodle.iutv.univ-paris13.fr/img/bjs/splat.png';
i.className='splat';
document.body.append(i);
// Forcer le navigateur à prendre en compte la situation actuelle (position, scale).
// Ceci permettra au navigateur de s'apercevoir d'un changement futur des propriétés CSS.
window.getComputedStyle(i).top;
// Changer les propriétés CSS qui transitionnent.
// Le navigateur s'aperçoit du changement et déclenche la transition.
i.style.top =(event.pageY-16)+'px';
i.style.left=(event.pageX-16)+'px';
i.style.transform='scale(1)';
}
</script>
</body>
</html>

Si on veut réagir à une touche appuyée n'importe où sur la page, on peut faire pareil. C'est ce qu'on a fait au sujet3, au jeu, pour déplacer le pingouin avec le clavier:

jeu.js

...
document.addEventListener('keydown',function(event){
console.log('Touche enfoncée:',event.key);
let rect=tux.getBoundingClientRect();
console.log(rect);
let d=100;
let left=rect.left;
let top=rect.top;
if(event.key==='ArrowRight'){left+=d;}
if(event.key==='ArrowLeft' ){left-=d;}
if(event.key==='ArrowDown' ){top+=d;}
if(event.key==='ArrowUp' ){top-=d;}
left=Math.max(10,left);
top =Math.max(10,top);
left=Math.min(510-rect.width ,left);
top =Math.min(510-rect.height,top);
tux.style.left=left+"px";
tux.style.top=top+"px";
});
...

4. Bubbling: this, Event.target

4.1 ¤ Bubbling: this, Event.target

Quand on utilise le bubbling, il faut distinguer

Bubbling: this, Event.target

4.2 this / event.target: span / body

    <body>
        <p>
            <a>Toc !</a>
            <span>Tac !</span>
        </p>
    </body>

            document.body.addEventListener('click',function() {
              console.log(this);
              console.log(event.target);
            });

L'utilisateur clique sur le span. Dans la fonction anonyme, quelles affirmations sont vraies ?

Bubbling: this, Event.target

4.3 Click sur p

    <body>
        <p>
            <a>Toc !</a>
            <span>Tac !</span>
        </p>
    </body>

            document.body.addEventListener('click',function() {
              console.log(this);
              console.log(event.target);
            });

L'utilisateur clique sur p. Dans la fonction anonyme, a quel élément correspond "this"  ?
(donnez juste son nom)


Bubbling: this, Event.target

4.4 Click sur a

    <body>
        <p>
            <a>Toc !</a>
            <span>Tac !</span>
        </p>
    </body>

            document.querySelector('a').addEventListener('click',function() {
              console.log(this);
              console.log(event.target);
            });

L'utilisateur clique sur a. Dans la fonction anonyme, a quel élément correspond "this"  ?
(donnez juste son nom)
(le code changé est indiqué en gras)


Bubbling: this, Event.target

4.5 Click sur a

    <body>
        <p>
            <a>Toc !</a>
            <span>Tac !</span>
        </p>
    </body>

            document.querySelector('p').addEventListener('click',function() {
              console.log(this);
              console.log(event.target);
            });

L'utilisateur clique sur a. Dans la fonction anonyme, à quel élément correspond "event.target"  ?
(donnez juste son nom)
(le code changé est indiqué en gras)


Bubbling: this, Event.target

4.6 Morpion bubbling

Dans les pages suivantes on va reprendre le morpion et le simplifier en utilisant le bubbling.

Créez le fichier morpion-bubbling.html suivant. Pour l'instant c'est le même code que l'ancien. On va le modifier ensemble, dans les pages suivantes.

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Morpion</title>
<style>
table
{
border-collapse: collapse;
}

td
{
border: 1px solid black;
width: 40px;
height: 40px;
font-size: 30px;
text-align: center;
cursor: pointer;
}

td:hover
{
background-color: #ffc;
}
</style>
</head>
<body>
<table>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
</table>
<script>
let tds=document.querySelectorAll('td');
for(let i=0;i<tds.length;i++)
{
tds[i].addEventListener('click',click_td);
}
let joueur='X';
function click_td(event)
{
console.log('Click');
if(this.textContent!=''){return;}
this.textContent=joueur;
if(joueur==='X'){joueur='O';}else{joueur='X';}
}
</script>
</body>
</html>

Bubbling: this, Event.target

4.7 Simplifier

Dans l'ancienne version, on a utilisé une boucle pour installer le gestionnaire d'événements click_td sur chacun des <td>:

			let tds=document.querySelectorAll('td');
for(let i=0;i<tds.length;i++)
{
tds[i].addEventListener('click',click_td);
}
On peut faire plus simple avec le bubbling!

Remplacez ce code, avec un code qui installe click_td uniquement sur la table. Vérifiez que « Click » s'affiche toujours sur la console quand on clique sur un <td>

Bubbling: this, Event.target

4.8 this et event.target

Avec le changement qu'on à fait, que valent, dans click_td, les variables suivantes:


Bubbling: this, Event.target

4.9 Changer this

Notre code actuel est le suivant:

			let tab=document.querySelector('table');
tab.addEventListener('click',click_td);
let joueur='X';
function click_td(event)
{
console.log('Click');
if(this.textContent!=''){return;}
this.textContent=joueur;
if(joueur==='X'){joueur='O';}else{joueur='X';}
}

Le "this" est celui de l'ancien programme (où c'était un <td>).
Avec notre changement,

Modifiez le code pour qu'il fonctionne.

Bubbling: this, Event.target

4.10 Correction

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Morpion</title>
<style>
table
{
border-collapse: collapse;
}

td
{
border: 1px solid black;
width: 40px;
height: 40px;
font-size: 30px;
text-align: center;
cursor: pointer;
}

td:hover
{
background-color: #ffc;
}
</style>
</head>
<body>
<table>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
</table>
<script>
let tab=document.querySelector('table');
tab.addEventListener('click',click_td);
let joueur='X';
function click_td(event)
{
console.log('Click');
if(event.target.textContent!=''){return;}
event.target.textContent=joueur;
if(joueur==='X'){joueur='O';}else{joueur='X';}
}
</script>
</body>
</html>


Bubbling: this, Event.target

4.11 Vérifier l'élément

Dans notre code, on a installé click_td sur <table> et on suppose que event.target est toujours un <td>.
Or <table> a d'autres descendants (des <tr> et <tbody> ajouté automatiquement).
Donc pour être certain qu'on agit uniquement sur les <td>, il faut le vérifier:
la propriété nodeName nous donne le nom de la balise (en majuscules).

			let tab=document.querySelector('table');
tab.addEventListener('click',click_td);
let joueur='X';
function click_td(event)
{
console.log('Click');
if(event.target.nodeName!=='TD'){return;}
if(event.target.textContent!=''){return;}
event.target.textContent=joueur;
if(joueur==='X'){joueur='O';}else{joueur='X';}
}


Bubbling: this, Event.target

4.12 Panier bubbling

Au Sujet-3 on avait crée un panier.  On veut le simplifier en utilisant le bubbling.
Utilisez les mêmes idées que l'on a vu précédemment:

Voici le code initial, que vous devez transformer vous mêmes:
panier-bubbling.html

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Jeu</title>
<style type=>
#parfums span
{
padding: .5em;
margin: 1em;
border: 1px solid blue;
}
#parfums span:hover
{
background-color: #ffa;
}
</style>
</head>
<body>
<p id="parfums"><span>Fraise</span><span>Chocolat</span><span>Vanille</span><span>Framboise</span></p>
<h4>Panier:</h4>
<ul id="panier">
</ul>
<script>
let parfums=document.querySelectorAll('#parfums span');
for(let i=0;i<parfums.length;i++)
{
parfums[i].addEventListener('click',function(event){
console.log('Click');
let ligne=document.createElement('li');
ligne.textContent=this.textContent;
let panier=document.getElementById('panier');
panier.append(ligne);
});
}
</script>
</body>
</html>

Changez le code, avec les mêmes idées qu'on a utilisé pour le morpion.

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:


Bubbling: this, Event.target

4.13 Correction panier


			let p=document.getElementById('parfums');
p.addEventListener('click',function(event){
console.log('Click');
if(event.target.nodeName!=='SPAN'){return;}
let ligne=document.createElement('li');
ligne.textContent=event.target.textContent;
let panier=document.getElementById('panier');
panier.append(ligne);
});

5. Bubbling et HTML généré

5.1 Bubbling et HTML généré

Quand l'utilisateur clique sur un parfum déjà dans le panier (partie du bas), on voudrait le supprimer.
Réfléchissez pour essayer de trouver tout seul une solution...
On va le faire, ensemble, dans les pages suivantes.

Rappel:

panier-bubbling.html

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Jeu</title>
<style type=>
#parfums span
{
padding: .5em;
margin: 1em;
border: 1px solid blue;
}
#parfums span:hover
{
background-color: #ffa;
}
</style>
</head>
<body>
<p id="parfums"><span>Fraise</span><span>Chocolat</span><span>Vanille</span><span>Framboise</span></p>
<h4>Panier:</h4>
<ul id="panier">
</ul>
<script>
let p=document.getElementById('parfums');
p.addEventListener('click',function(event){
console.log('Click');
if(event.target.nodeName!=='SPAN'){return;}
let ligne=document.createElement('li');
ligne.textContent=event.target.textContent;
let panier=document.getElementById('panier');
panier.append(ligne);
});
</script>
</body>
</html>



Bubbling et HTML généré

5.2 Moment d'execution

Au démarrage, notre page est comme ceci:
		<p id="parfums"><span>Fraise</span><span>Chocolat</span><span>Vanille</span><span>Framboise</span></p> 
<h4>Panier:</h4>
<ul id="panier">
</ul>
Pour l'instant, les <li> de panier <ul> n'existent pas.
Pourtant, on voudrait pouvoir faire des addEventListener sur ces <li> pour ajouter une fonction qui nous permettra des les supprimer quand l'utilisateur cliquera dessus.

Notre code, pour l'instant, est le suivant:
		<script>
let p=document.getElementById('parfums');
p.addEventListener('click',function(event){
console.log('Click');
if(event.target.nodeName!=='SPAN'){return;}
let ligne=document.createElement('li');
ligne.textContent=event.target.textContent;
let panier=document.getElementById('panier');
panier.append(ligne);
});
XYZ
</script>
A quel moment est-ce que le code XYZ est exécuté ?


Bubbling et HTML généré

5.3 Click ul


		<p id="parfums"><span>Fraise</span><span>Chocolat</span><span>Vanille</span><span>Framboise</span></p> 
<h4>Panier:</h4>
<ul id="panier">
</ul>
<script>
let p=document.getElementById('parfums');
p.addEventListener('click',function(event){
console.log('Click');
if(event.target.nodeName!=='SPAN'){return;}
let ligne=document.createElement('li');
ligne.textContent=event.target.textContent;
let panier=document.getElementById('panier');
panier.append(ligne);
XYZ
});
</script>
XYZ est exécuté au démarrage de la page lorsqu'il les <li> n'existent pas encore.
On ne peut donc pas faire addEventListener sur les <li>... mais on peut faire addEventListener sur le <ul> dans lequel les <li> seront ajoutés.

Faites-le et affichez « Click ul » dans la console chaque fois que l'utilisateur clique dans le <ul>

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Bubbling et HTML généré

5.4 Correction

			let panier=document.getElementById('panier');
let p=document.getElementById('parfums');
p.addEventListener('click',function(event){
console.log('Click');
if(event.target.nodeName!=='SPAN'){return;}
let ligne=document.createElement('li');
ligne.textContent=event.target.textContent;
panier.append(ligne);
});
panier.addEventListener('click',function(event){
console.log('Click ul');
});


Bubbling et HTML généré

5.5 Élément cliqué

Vérifiez que si vous ajoutez des parfums dans le panier, puis que vous cliquez dessus, que « Click ul  » est bien affiché dans la console.

			panier.addEventListener('click',function(event){
console.log('Click ul');
ICI
});
Pour supprimer un élément, on peut utiliser la fonction remove(). Elle s'applique sur un élément. Voir la documentation.

Que faut-il écrire « ICI » pour supprimer l'élément <li> du panier quand l'utilisateur clique dessus ?
Indice: trouvez d’abord comment on récupère l'élément <li> cliqué...
(vérifiez dans votre navigateur avant de répondre)

Bubbling et HTML généré

5.6 remove()

Mettez à jour votre code:

            panier.addEventListener('click',function(event){
console.log('Click ul');
event.target.remove()
});

Ajoutez des parfums et vérifiez que ça marche. Que se passe-il si vous cliquez à gauche des points dans le panier ?

Bubbling et HTML généré

5.7 Vérifier élément

Si vous cliquez à gauche des points, votre click se trouve dans le <ul> et non pas le <li>... vous supprimez donc le <ul> tout entier !!

Inspirer vous de ce qui a été fait précédemment pour vérifier que le click est bien dans un <li>

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Bubbling et HTML généré

5.8 Correction


<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Jeu</title>
<style type=>
#parfums span
{
padding: .5em;
margin: 1em;
border: 1px solid blue;
}
#parfums span:hover
{
background-color: #ffa;
}
</style>
</head>
<body>
<p id="parfums"><span>Fraise</span><span>Chocolat</span><span>Vanille</span><span>Framboise</span></p>
<h4>Panier:</h4>
<ul id="panier">
</ul>
<script>
let panier=document.getElementById('panier');
let p=document.getElementById('parfums');
p.addEventListener('click',function(event){
console.log('Click');
if(event.target.nodeName!=='SPAN'){return;}
let ligne=document.createElement('li');
ligne.textContent=event.target.textContent;
panier.append(ligne);
});
panier.addEventListener('click',function(event){
console.log('Click ul');
if(event.target.nodeName!=='LI'){return;}
event.target.remove();
});
</script>
</body>
</html>

6. Tableau joueurs

6.1 Tableau joueurs

On va reprendre le tableau de joueurs du sujet-5. Des petites croix ont été ajoutées à chaque ligne.

Créez les fichiers suivants (ou reprenez les vôtres en mettant à jour le tableau HTML)

joueurs.html

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>joueurs</title>
<link type="text/css" rel="stylesheet" href="joueurs.css"/>
</head>
<body>
<!--------------------->
<h2>Joueurs :</h2>
<p id="ajouter">
<label>nom: <input id="ajout-nom" type="text"/></label>
<label>score: <input id="ajout-score" type="text"/></label>
<input id="bouton-ajouter" type="button" value="ajouter"/>
</p>
<table id="joueurs">
<tr><td class="effacer"><img src="https://moodle.iutv.univ-paris13.fr/img/js/effacer.png"/></td><td class="nom">Leïla</td><td class="score">121</td></tr>
<tr><td class="effacer"><img src="https://moodle.iutv.univ-paris13.fr/img/js/effacer.png"/></td><td class="nom">Driss</td><td class="score">153</td></tr>
<tr><td class="effacer"><img src="https://moodle.iutv.univ-paris13.fr/img/js/effacer.png"/></td><td class="nom">Lian</td><td class="score">210</td></tr>
<tr><td class="effacer"><img src="https://moodle.iutv.univ-paris13.fr/img/js/effacer.png"/></td><td class="nom">Joe</td><td class="score">32</td></tr>
<tr><td class="effacer"><img src="https://moodle.iutv.univ-paris13.fr/img/js/effacer.png"/></td><td class="nom">Naïma</td><td class="score">261</td></tr>
<tr><td class="effacer"><img src="https://moodle.iutv.univ-paris13.fr/img/js/effacer.png"/></td><td class="nom">Karim</td><td class="score">183</td></tr>
<tr><td class="effacer"><img src="https://moodle.iutv.univ-paris13.fr/img/js/effacer.png"/></td><td class="nom">Anon.</td><td class="score">0</td></tr>
</table>
<p>
total : <span id="total" >960</span><br/>
médiane : <span id="mediane">153</span>
</p>

<!--------------------->
<script src="joueurs.js"></script>
</body>
</html>

joueurs.css

body
{
font-family: sans;
}

h2
{
font-size: 16px;
}

#joueurs
{
box-shadow: 2px 2px 4px rgba(0,0,0,.2);
border-radius: 2px;
border-collapse: collapse;
margin-left: 40px;
}

#joueurs td
{
padding: 3px 10px;
}
#joueurs tr
{
background-color: #f0f0ff;
}

#joueurs tr:nth-child(2n)
{
background-color: #efe;
}

#ajouter input[type='text']
{
width: 80px;
}

#ajout-nom
{
margin-right: 10px;
}

joueurs.js

let bouton=document.getElementById('bouton-ajouter');
bouton.addEventListener('click',function(){
console.log('Click');
let joueur={
nom: document.getElementById('ajout-nom').value,
score: document.getElementById('ajout-score').value
};
ajouter_joueur(joueur);
document.getElementById('ajout-nom').value='';
document.getElementById('ajout-score').value='';
document.getElementById('total').textContent=calculer_total();
});

function calculer_total()
{
let total=0;
let tds=document.querySelectorAll('.score');
for(let i=0;i<tds.length;i++){
let score=parseInt(tds[i].textContent);
total+=score;
}
return total;
}

function ajouter_joueur(joueur)
{
console.log('ajouter_joueur',joueur);
let ligne=document.createElement('tr');
let nom =document.createElement('td');
let score=document.createElement('td');
nom.textContent=joueur.nom;
score.textContent=joueur.score;
nom.className='nom';
score.className='score';
ligne.append(nom);
ligne.append(score);
document.getElementById('joueurs').append(ligne);
}

Tableau joueurs

6.2 ajouter_joueur

Pour l'instant ajouter_joueur n'ajoute pas une ligne avec la petite croix.
En vous inspirant du code existant , complétez ajouter_joueur pour qu'il y ait bien une petite croix.
Indices:


Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Tableau joueurs

6.3 Correction


function ajouter_joueur(joueur)
{
console.log('ajouter_joueur',joueur);
let ligne =document.createElement('tr');
let effacer=document.createElement('td');
let nom =document.createElement('td');
let score =document.createElement('td');
let croix=document.createElement('img');
croix.src='https://moodle.iutv.univ-paris13.fr/img/js/effacer.png';
effacer.append(croix);
nom.textContent=joueur.nom;
score.textContent=joueur.score;
effacer.className='effacer';
nom.className='nom';
score.className='score';
ligne.append(effacer);
ligne.append(nom);
ligne.append(score);
document.getElementById('joueurs').append(ligne);
}



Tableau joueurs

6.4 Click sur la croix

On voudrait réagir lorsque l'utilisateur clique sur une croix.

Le HTML des joueurs ajoutés (ligne dans le tableau) n'existe pas au démarrage de la page... on ne peut donc pas faire des addEventListener sur les croix au démarrage.

On va donc utiliser le bubbling. Faites en sorte d'afficher « Click croix » dans la console, uniquement quand l'utilisateur clique sur une croix (et pas ailleurs).

Indices:

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Tableau joueurs

6.5 Correction


let bouton=document.getElementById('bouton-ajouter');
bouton.addEventListener('click',function(){
console.log('Click');
let joueur={
nom: document.getElementById('ajout-nom').value,
score: document.getElementById('ajout-score').value
};
ajouter_joueur(joueur);
document.getElementById('ajout-nom').value='';
document.getElementById('ajout-score').value='';
document.getElementById('total').textContent=calculer_total();
});
let joueurs=document.getElementById('joueurs');
joueurs.addEventListener('click',function(event){
console.log('Click sur table');
if(event.target.nodeName!=='IMG'){return;}
console.log('Click sur croix');
});


function calculer_total()
{
let total=0;
let tds=document.querySelectorAll('.score');
for(let i=0;i<tds.length;i++){
let score=parseInt(tds[i].textContent);
total+=score;
}
return total;
}

function ajouter_joueur(joueur)
{
console.log('ajouter_joueur',joueur);
let ligne =document.createElement('tr');
let effacer=document.createElement('td');
let nom =document.createElement('td');
let score =document.createElement('td');
let croix=document.createElement('img');
croix.src='https://moodle.iutv.univ-paris13.fr/img/js/effacer.png';
effacer.append(croix);
nom.textContent=joueur.nom;
score.textContent=joueur.score;
effacer.className='effacer';
nom.className='nom';
score.className='score';
ligne.append(effacer);
ligne.append(nom);
ligne.append(score);
document.getElementById('joueurs').append(ligne);
}


Tableau joueurs

6.6 Supprimer la ligne

Dans le code suivant:

let joueurs=document.getElementById('joueurs');
joueurs.addEventListener('click',function(event){
console.log('Click sur table');
if(event.target.nodeName!=='IMG'){return;}
console.log('Click sur croix');
});

event.target sera l'image.
On veut supprimer la ligne <tr> quand l'utilisateur clique sur la croix.

Que faut-il taper pour supprimer la ligne tout entière ?

Indices:


Tableau joueurs

6.7 ¤ Conclusion: HTML généré et bubbling

Que ce soit pour le panier ou pour le tableau joueur, on a deux situations où:

Dans ces deux cas on ne peut pas utiliser addEventListener au démarrage de la page, car les éléments (panier: <li>, joueurs: <tr>) n'existent pas encore. On exploite alors le bubbling: on utilise addEventListener sur un parent qui existe au démarrage (panier: <ul>, joueurs: <table>).

On aura donc du code de ce type:

unParent.addEventListener('exemple', function(event){
    if( /* c'est n'est pas l'élément descendant souhaité */ ) { return; }
});

Cette approche est très courante. En particulier, c'est le cas des programmes AJAX (qu'on verra plus tard) qui génèrent beaucoup de HTML en cours d’exécution.