# Javascript WF3 ## Partie 1 ### Informations À télécharger : Windows : [Laragon](https://laragon.org/) MacOS : [MAMP](https://www.mamp.info/fr/mamp/mac/) norme JS = ECMAScript _Afin de chercher des données coté serveur sans avoir à recharger la page on utilisera **AJAX**_ La console est un espace de debogage pour le dev ### Fonctions `console.log` est une ==fonction → fait une action== Les fonctions sont suivies de parentheses. **A l'intérieur des parentheses on a les ==paramètres/arguments== de la fonction** `document.write('')` = écris du texte dans le code source `window.alert('')` = envoie une pop up `console.log('')` = écris dans la console `window.prompt('')` = boîte de dialogue qui nous invite à saisir du texte ### Types de données Types de données en JS 6 types primitifs : **string, number, boolean, null, undefined, symbol** le type **object** ### Variables #### L'instruction `let` * **déclarer** les variables age et nom ```javascript let age, name; ``` * **affecter** une valeur à la variable age ```javascript age = 28; ``` _(si pas d'affectation, la variable contient undefined)_ **Declaration + affectation de la variable age en une ligne :** ```javascript let age = 28; ``` #### Les constantes `const` Contrairement aux constantes `const` ==les variables peuvent être modifiées==. Si on réaffecte une constante, javascript fera une erreur. On y rangera alors des valeurs qui ne sont pas censées être changées pour éviter de les modifier par erreur. #### La variable `var` (obsolète) Autre maniere de déclarer une variable `var`. Elle fonctionne toujours mais n'est plus utilisée. #### Déclarer une chaine de caractère (string) Pour déclarer une variable qui contient une chaine de caractere (string) il faut ajouter `''` ou `""` Exemple : ```javascript let price = 10.5; // Number ``` ```javascript const productName = 'Nom du produit'; // String ``` ```javascript let price = '10.5'; // String ``` ### Calculs On peux faire des calculs complexes en JS ```javascript let price = 10.5 + 10 * (50 - 4); // price = 470.5 ``` ### Concaténation On peux concaténer une variable de différente manière ```javascript document.write('<p>Tu as ' + age + ' ans !'); ``` ```javascript document.write("<p>Tu as " + age + " ans !"); ``` ```javascript document.write(`<p>Tu as ${age} ans !`); ``` **Attention : Si le contenu à l'intérieur des `''` contient ce même charactère on y ajoutera un antislash ou alors on utilisera `""` à la place** ```javascript document.write('L\'age entré n\'est pas valide.') ``` ```javascript document.write("L'age entré n'est pas valide.") ``` ### Conditions ==la valeur retournée est true ou false== 2 structures conditionnelles * if...else * switch #### Opérateur de comparaison `<, >, <=, >=, ==, !=, ===` « et » ``&&`` « ou » ``||`` Switch peut être utilisé s'il y a beaucoup de if...else consécutifs. ### Les Boucles Plusieurs types de boucles : * `for` : faire un nombre connu de répétitions * `while`: nombre inconnu de répétitions (entre 0 et l'infini) * `do...while` (variante de while) : nombre inconnu (au moins 1 tour de boucle) * `for...of` : permet de parcourir des structures itérables (tableaux, chaînes de caractères, ect) * `for...in` (permet de parcourir les propriétés d'un objet) #### Boucles `for` ```javascript= for (let i = 1 ; i <= 10 ; i++){ console.log(i + 'kilomètre(s) à pieds, ça use ça use...'); } ``` #### Boucles `while` On repète tant que la condition est vraie ```javascript= let number = Number(prompt('Donnez un nombre entre 1 et 100')); while(number < 1 && number > 100){ //tant que number est inférieur à 1 et supérieur à 100 ... } ``` Elle peut avoir un comportement similaire à la boucle `for` ```javascript= let compteur = 0; while(compteur < 5){ console.log('Tour de boucle while n°' + compteur); compteur++; // compteur = compteur + 1; ou bien compteur += 1; } ``` #### Boucles `do...while` Si la condition du `while` est fausse des le départ il y aura **0 tour de boucle**. Si on souhaite au moins faire un tour de boucle on préfèrera `do..while` ```javascript= let password; do{ password = prompt('Donne un mot de passe de plus de 8 caractères'); } while(password.length < 8); ``` ##### Exemple : Shifumi **Étape 1** : On demande à l'utilisateur d'entrer pierre, papier ou ciseau. S'il entre autre chose, on lui redemande. ```javascript= let player ; do{ // on demande ce qu'il joue player = prompt('Qu\'est-ce que tu joue ? (pierre, feuille ou ciseaux)'); player = player.toLowerCase(); // tout mettre en minuscule } while(player != 'pierre' && player != 'feuille' && player != 'ciseaux'); //tant que sa réponse n'est pas correcte document.write(`<p>Vous avez joué ${player} !</p>`); ``` **Étape 2** : On tire un nombre aléatoire afin de déterminer le choix de l'ordinateur. ```javascript= const rand = Math.random(); //renvoit un nbre flottant (nbre décimal) entre 0 et 1 let computer; // variable qui va contenir le choix de l'ordinateur //si nbre aléatoire entre 0 et 0.33 (premier intervalle) if(rand < 0.33){ computer = 'pierre'; } //sinon si on est entre 0.33 et 0.66 (deuxieme intervalle) else if(rand < 0.66){ computer = 'feuille'; } // Sinon rand est plus grand que 0.66 (troisieme intervalle) else{ computer = 'ciseaux'; } document.write(`<p>L'ordinateur à joué ${computer} !</p>`); ``` **Étape 3** : On compare les réponse de l'utilisateur et de l'ordinateur pour savoir qui a gagné. ```javascript= if(player == computer){ // si nos choix sont identiques document.write(`<p>Égalité !</p>`); } else if(player == 'pierre' && computer == 'feuille') || (player == 'feuille' && computer == 'ciseaux') || (player == 'ciseaux' && computer == 'pierre') ){ // je perds dans 3 cas document.write(`<p>Vous avez perdu !</p>`); } else{ // sinon j'ai gagné document.write(`<p>Vous avez gagné !</p>`); } ``` ### Récapitulatif `document.write('')` `window.alert('')` `window.prompt('')` `console.log('')` `let` `const` `var` `parseInt()` `Number()` `.length` `.toLowerCase()` `if()` `else if()` `else()` `for()` `do()` `while()` `Math.random()` --- ## Partie 2 ### Les objets _En JavaScript tout ce que l'on manipule est un objet_ Les objets permettent de ==regrouper plusieurs informations ensemble== dans une seule variable. * ==Propriétés== : informations/caractéristiques d'un objet * ==Méthodes== : fonctions qui permettent de faire des actions sur l'objet. * ==Classe== : Catégorie de l'objet. _(exemple : une voiture est un objet de type véhicule)_ On a déja utilisé des objets précedement : ```javascript document.write('Du texte sur la page'); ``` _action `write()` sur l'objet `document`_ Ou encore : ```javascript console.log('Du texte dans la console'); ``` _Appel de la méthode `log()` sur l'objet `console`_ #### Créer un objet On commence par créer une constante ou une variable et on y range un objet de la classe voulue. On crée un objet en ajoutant le mot clé `new` #### La classe `Date` Dans la constante `today` on stock un objet de la classe `Date`. ```javascript= const today = new Date(); document.write(today.toLocaleDateString()); ``` renvoie une chaine de caractères correspondant à la date JJ/MM/AAAA Si rien dans les parentheses `Date()` il renvoie la date d'aujourd'hui. ```javascript const birthday = new Date('1982-03-09'); // AAAA-MM-JJ ``` #### La classe `Object` Représente un objet générique. ##### Création d'un objet de la classe `Object` ```javascript= const student = new Object(); // on créé un objet vide student.firstname = 'Alfred'; // ajout d'une propriété firstname dans l'objet student et j'y range la valeur Alfred student.lastname = 'Dupont'; student.age = 17; student.birthday = new Date('2003-07-01'); // ajout d'une propriété birthday dans l'objet student et j'y range un objet de la classe Date document.write(student.birthday.getFullYear()); //affiche l'année de naissance de student ``` Syntaxe alternative pour créer un objet de la classe `Object` : ```javascript= const student = { firstname: 'Alfred', lastname: 'Dupont', age: 17, birthday: new Date('2003-07-01') }; document.write(student.birthday.getFullYear()); //affiche l'année de naissance de student ``` ##### Modifier des propriétés à mon objet une fois qu'il a été créé ```javascript student.age = 18; //age passe de 17 à 18 ``` #### Exemple ##### Exemple : Affichons une liste d'élements contenus dans un objet ```javascript= // création d'un objet voiture const voiture = new Object(); // ajout ou modification des propriétés de mon objet voiture voiture.modele = 'Punto'; voiture.puissance = '70cv'; voiture.miseEnCirculation = new Date('2010-05-06'); // création d'un objet de classe Date stocké dans voiture.miseEnCirculation voiture.options = ['abs', 'sièges chauffants', 'climatisation']; // création d'un tableau de 3 éléments stocké dans voiture.options // affichage sur la page des données contenues dans l'objet voiture document.write('<article>'); document.write('<h2>' + voiture.marque + ' ' + voiture.modele + '</h2>'); document.write('<ul>'); document.write('<li>Couleur : ' + voiture.couleur + '</li>'); document.write('<li>Puissance : ' + voiture.puissance + '</li>'); document.write('<li>Date de mise en circulation : ' + voiture.miseEnCirculation.toLocaleDateString() + '</li>'); document.write('<li>Options : '); document.write('<ul>'); for(let i = 0 ; i < voiture.options.length ; i++){ document.write('<li>' + voiture.options[i] + '</li>'); } document.write('</ul>'); document.write('</li>'); document.write('</ul>'); document.write('</article>'); ``` ### Les tableaux `Array()` Un tableau est un objet de la classe `Array` Ils permettent de stocker une liste d'élements (==valeurs==) de même nature. Chaque élément contenu dans un tableau est repéré par un numéro : l'==indice== **L'indice du premier élément d'un tableau est 0 !** indices | 0 | 1 | 2 --------|---|---|--- **valeurs** | 'astragale' | 'calendula' | 'consoude' #### Création d'un tableau vide ```javascript const tab = new Array(); ``` #### Insérer des élement dans un tableau Avec la méthode `push()` : ```javascript= const notes = new Array(); // tableau vide notes.push(17, 12, 15); // on ajoute 3 éléments au tableau ``` *Syntaxe alternative :* ```javascript= const notes = []; // tableau vide notes.push(17, 12, 15); ``` Ou alors sans créer un tableau vide: ```javascript const notes = new Array(17, 12, 15); ``` *Syntaxe alternative :* ```javascript const notes = [17, 12, 15]; ``` **`notes` contient alors :** indices | 0 | 1 | 2 --------|---|---|--- **valeurs** | 17 | 12 | 15 #### Récupérer un élément d'un tableau Pour récuperer un élement précis d'un tableau on utilise son indice. ```javascript console.log(notes[0]); // on récupere la première valeur du tableau et on l'affiche dans la console ``` #### Modifier un élément d'un tableau ```javascript notes[2] = 12; // le troisième élément du tableau (indice 2) passe de 15 à 12 ``` #### Récupérer plusieurs éléments d'un tableau Pour ==parcourir un tableau== on peux faire une boucle `for` dans le cas où on connais le nombre d'indices du tableau ```javascript= for(let indice = 0 ; indice < 4 ; indice++){ console.log('La valeur associée à l\'indice ' + indice + ' est ' notes[indice]); } ``` On peux également récupérer la longueur d'un tableau (le nombre de cases) à l'aide de la fonction `.length` ```javascript console.log(notes.length); // on affiche dans la console le nombre d'éléments dans le tableau (3) ``` #### Exemple ##### Exemple : Affichons le contenu d'un tableau sous forme de liste ```javascript= const personnes = ['Pierre', 'Sophie', 'Léa', 'François']; // notre tableau contenant une liste de noms document.write('<ul>'); for(let i = 0 ; i < personnes.length ; i++){ document.write('<li>' + personnes[i] + '</li>'); } document.write('<ul>'); ``` ### Les fonctions * Elle peux avoir besoin de paramètres (==arguments==) * Elle va produire un résultat ou pas *Jusqu'a présent on a utilisé des fonctions crées par Javascript (les ==fonctions natives==)mais on peux également en créer (==fonctions utilisateurs==) !* On peut également ajouter des ==API== ou ==librairies== afin d'enrichir le langage de fonctions supplémentaires. #### Définir une fonction ```javascript= function add(number1, number2){ const result = Number(number1) + Number(number2); return result; } ``` #### Appel de la fonction ```javascript= const somme = add(388,412); document.write(somme); ``` #### Exemples ##### Exemple n°1 : Créons une fonction `arraySum()` qui fait la somme des nombres d'un tableau ```javascript= function arraySum(array){ let total = 0; for (let i = 0 ; i < array.length ; i++){ total += Number(array[i]); } return total; } const sum = arraySum([8, 10, 12]); // console.log(sum); // affiche la somme : 30 ``` **Les variables déclarées dans une fonction n'existe qu'à l'intérieur de la fonction.** Tout bloc de code dans des accolades fonctionne de la même manière ! Pour faire sortir le résultat d'une fonction on a besoin d'utiliser `return`. Une fois l'instruction `return` effectuée, **la fonction est terminée** ! ##### Exemple n°2 : Créons une fonction `arrayAverage()` qui calcule la moyenne des nombres d'un tableau On peux utiliser une fonction à l'intérieur d'une autre fonction. Pour cet exemple, nous allons réutiliser la précédente fonction `arraySum()`. ```javascript= function arrayAverage(array){ let sum = arraySum(array); let average = sum / array.length; return average; } console.log(arrayAverage([8, 10, 12])); // affiche la moyenne : 10 ``` ##### Exemple n°3 : Créons une fonction `sayHello()` qui dit bonjour à quelqu'un à partir d'un prénom ```javascript= function sayHello(name = 'world'){ return Bonjour ${name}; // return 'Bonjour ' + name; } ``` On peut donner un ==paramètre par défaut== dans le cas ou aucun paramètre n'a été indiqué et ainsi éviter que la fonction renvoie `undefined`. Dans notre exemple, on a indiqué 'world' comment étant le paramètre par défaut. Si aucun nom n'a été communiqué en paramètre, la fonction va retourner `Hello world`. ##### Exemple n°4 : Créons une fonction `ucFirst()` qui met en majuscule la première lettre d'un mot et toute les autres lettres en minuscule ```javascript= function uFirst(string){ const firstChar = string.charAt(0).toUpperCase(); // récupere le premier charactère (indice 0) à l'aide de la méthode .charAt() puis on le met en majuscule avec .toUpperCase() const otherChars = string.slice(1, string.length).toLowerCase(); // récupere le reste des charactères : en paramètres de .slice(), l'indice de début (1) et l'indice de fin exclus (string.length) puis on le met en minuscule avec .toLowerCase() const result = firstChar + otherChars; // concaténation du premier caractère en majuscule et du reste des caractères en minuscle return result; } document.write(uFirst('tEXT')); //affiche 'Text' ``` ##### Exemple n°5 : Créons une fonction `getRandomInt()` qui tire un nombre entier aléatoire entre 2 bornes ```javascript= function getRandomInt(min,max){ Math.ceil(min); // retourne le plus petit entier supérieur ou égal à min Math.floor(max); // retourne le plus grand entier qui est inférieur ou égal à max random = Math.floor(Math.random() * (max - min + 1) + min); return random; } document.write(getRandomInt(3,6)); // affiche un nombre compris entre 3 et 6 ``` ### Récapitulatif `new` `Date()` `Object()` `Array()` `.toLocaleDateString()` `.getFullYear()` `.charAt()` `.slice()` `.toUpperCase()` `.toLowerCase()` `.push()` `Math.ceil()` `Math.floor()` `return` --- ## Partie 3 ### Javascript pour le web Javascript est exécuté par les navigateurs web pour rendre les interfaces des sites plus **dynamiques** On va pouvoir modifier la structure HTML d'un document : * Ajout de balises * Modification de balises existantes * Manipulation des attributs * ect.. Pour que le HTML et le JavaScript communiquement entre eux, il nous faut un intermédiaire : **==l'API DOM==** **A**pplication **P**rogramming **I**nterface ### Le DOM **D**ocument **O**bject **M**odel *C'est la traduction du code **HTML** d'un document en **JavaScript**. Chaque balise HTML va trouver sa traduction dans un objet d'une certaine classe.* Exemple : la balise paragraphe `<p>` sera représentée dans le **DOM** par un objet de classe `HTMLParagraphElement`. Toutes les classes du DOM ont comme classe mère la classe `HTMLElement` **==Elément==** : objet représentant une balise HTML Un élément possède des ==propriétés== et des ==méthodes==, comme tous les objets, qui dépendent de la classe à laquelle il appartient. #### L'arbre DOM Le navigateur va traduire l'arbre HTML en JavaScript et créer l'arbre DOM. Cette opération peut prendre un certain temps : c'est le ==chargement du DOM==. ##### Agir sur le DOM Pour modifier un document HTML en JavaScript, on va le faire par l'intermédiaire du DOM. On procédera toujours en deux temps * Sélectionner le ou les élément(s) qui nous intéressent * Ajout sur cet ou ces élément(s) * récupérer la valeur d'un attribut * modifier la valeur d'un attribut * agir sur les classes * agir sur les propriétés CSS de l'élément * .. ### Sélectionner un élément par son `id` avec `getElementById()` La méthode `getElementById()` sélectionne 1 élément à partir d'un **id** ```htmlmixed <p id="my-example-para">Lorem ipsum</p> ``` ```javascript= const paragraph = document.getElementById('my-example-para'); // on séléectionne l'élement avec pour id my-example-para et on le met dans une constante paragraph console.log(paragraph.constructor.name); // affiche dans la console la classe de notre élément paragraph paragraph.textContent = 'Nouveau texte'; // On change ici le contenu de l'élément paragraph.innerHTML = '<em>Nouveau texte</em>'; // On ajoute à notre élément une balise em ``` `.textContent` contient le **texte brut** et n'interprète rien. S'il contient des balises HTML, elles seront affichées et non interprétées. Si on souhaite faire en sorte que les balises HTML soient interpretées on préfèrera `.innerHTML`. ### Sélection d'un élément avec `querySelector()` En paramètre de la fonction `querySelector()` un sélecteur CSS (id, class, attribut, tag ect..) ```htmlmixed= <header> <h1>Titre</h1> </header> <main> <p class="accroche"> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </main> ``` ```javascript const accroche = document.querySelector('.accroche'); // on stock dans la constante accroche l'élement HTML avec pour class CSS .accroche ``` #### La propriété `.style` `.style` contient toutes les propriétés css de l'élément. Les propriétés CSS composées d'un seul mot restent les mêmes en JS (`color` → `.color`). Cependant les propriétés CSS habituellement séparées par un tiret seront collées (`font-size` → `.fontSize`). ```javascript= const accroche = document.querySelector('.accroche'); accroche.style.color = 'blue' // on change la couleur du paragraphe accroche.style.fontSize = '3em' // on change la couleur du paragraphe ``` ### Sélectionner plusieurs éléments avec `querySelectorAll()` Contrairement à la fonction `querySelector()`, celle-ci récupère tous les élements mentionnés en paramètre et retourne un tableau d'éléments. On va donc faire une boucle `for` pour parcourir ce tableau et agir individuellement sur chaque élément. ```htmlmixed= <header> <h1>Titre</h1> </header> <main> <p class="accroche"> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </main> ``` ```javascript= const paragraphs = document.querySelectorAll('p'); // cherche tous les éléments correspondant au tag p for(let i = 0 ; i < paragraphs.length ; i++){ console.log(paragraphs[i]); // on affiche dans la console chaque <p> } ``` ### Modifier des classes avec `.add()` `.remove()` et `toggle()` ```css= .important{ font-family: Verdana, sans-serif; text-align: justify; color: red; } ``` On réalise une boucle `for` pour ajouter la classe `.important`à chaque élements de `paragraphs` ```javascript= const paragraphs = document.querySelectorAll('p'); // cherche tous les éléments correspondant au tag p for(let i = 0 ; i < paragraphs.length ; i++){ paragraphs[i].classList.add('important'); // on ajoute la class .important à nos éléments contenus dans paragraphs } ``` Syntaxe alternative : ```javascript= const paragraphs = document.querySelectorAll('p'); // cherche tous les éléments correspondant au tag p for(const para of paragraphs){ // pour chaque paragraphe que j'appelle 'para' du tableau de paragraphes 'paragraphs' para.classList.add('important'); // on ajoute la class .important à nos éléments contenus dans paragraphs } ``` On récupère toutes les classes d'un élément avec `.classList` et on y ajoute une classe avec `.add()`. On peux supprimer une classe avec `.remove()`. `.toggle()` fonctionne comme un interrupteur on/off. Si l'élement possède la classe, JS va l'enlever. Si elle n'existe pas, il va l'ajouter. `.contains()` vérifie si l'élement contient la classe spécifiée. [Liste des méthodes pour .classList](https://developer.mozilla.org/fr/docs/Web/API/Element/classList) #### Exemple : Faire disparaître tous les paragraphes qui n'ont pas la classe `.accroche` ```htmlmixed= <main> <h1>Titre</h1> <p class="accroche"> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </main> ``` ```css= .hidden{display:none} ``` En utilisant `if...else` ```javascript= const paragraphs = document.querySelectorAll('p'); // cherche tous les éléments correspondant au tag p // on va parcourir notre tableau paragraphs qui contient tous les éléments p for(let i = 0 ; i < paragraphs.length ; i++){ if(paragraphs[i].classList.contains('accroche') == false ){ paragraphs[i].classList.add('hidden'); // on ajoute la class hidden à nos éléments contenus dans paragraphs } } ``` Ou alors en utilisant un sélecteur CSS ```javascript= const paragraphs = document.querySelectorAll('p:not(.accroche)'); // cherche tous les éléments correspondant au tag p sauf ceux avec la classe accroche (sélécteur CSS) // on va parcourir notre tableau paragraphs qui contient tous les éléments p for(let i = 0 ; i < paragraphs.length ; i++){ paragraphs[i].classList.add('hidden'); } ``` ### Agir sur les attributs #### Récupérer la valeur d'un attribut ```javascript const link = document.getElementById('my-link'); const href = link.getAttribute('href'); ``` #### Modifier la valeur d'un attribut ```javascript const link = document.getElementById('my-link'); link.setAttribute('href', 'www.monsite.fr'); ``` ### Créer et insérer des éléments #### Création d'un élément ```javascript const link = document.createElement('a') // en paramètre on indique quel type d'élément on veux créer ``` #### Modifier l'élément créé ```javascript link.setAttribute('href', 'www.monsite.com'); link.textContent = 'Mon Site'; ``` #### On insère l'élément dans le document à partir d'un autre élément À la fin d'un élément parent : `parent.appendChild(child);` Au début d'un élément parent : `parent.prepend(child);` Après un élément de même niveau : `sibling.after(element);` Avant un élément de même niveau : `sibling.before(element);` #### Exemple : Ajout d'un lien dans le header ```javascript= const link = document.createElement('a'); // <a></a> link.setAttribute('href', 'www.monsite.fr'); // <a href="www.monsite.fr"></a> link.textContent = 'Mon Site'; // <a href="www.monsite.fr">Mon Site</a> const header = document.querySelector('header'); // on récupère l'élément <header> dans une constante header header.appendChild(link) // insertion du lien à la fin du parent <header> ``` ### Les Évenements Un évenement est une ==action d'un internaute== (clic, double clic ect..) Pour observer, pour espionner un élement, on va installer un ==gestionnaire d'événement== : `.addEventListener()`. En premier paramètre on y met l'évenement (ex : 'click') et en deuxieme paramètre l'action (une fonction crée au préalable) [Voir la liste des évenements ici](https://developer.mozilla.org/en-US/docs/Web/Events) #### Exemples ##### Exemple 1 : Créons un bouton qui permet d'afficher ou de masquer un élément lors d'un double clic ```htmlmixed= <main> <button id="my-button">Click me !</button> <p class="hidden my-text"> <!-- le paragraphe est caché par défaut --> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </main> ``` ```css= .hidden{display: none;} ``` ```javascript= const button = document.getElementById('my-button'); // notre bouton const text = document.querySelector('.my-text'); // notre texte button.addEventListener('dblclick', onDoubleClickButton); // lors de l'évenement 'dblclick' sur button : faire la fonction onDoubleClickButton function onDoubleClickButton(){ text.classList.toggle('hidden'); // toggle la classe hidden dans l'élément text } ``` ##### Exemple 2 : Créons un bouton qui permet de cacher une image avec un attribut précis ```htmlmixed= <img src="image-1.jpg"> <button>Cliquez ici pour cacher image-1.jpg</button> ``` ```css= .hidden{display: none;} ``` ```javascript= const button = document.getElementById('hide-image-button'); // récupère l'élement #hide-image-button et je le stock dans button button.addEventListener('click', onClickButton); // lorsque que 'click' sur #hide-image-button je réalise l'action onClickButton // on défini se que fait onClickButton function onClickButton(){ const img = document.querySelector('img[src="image-1.jpg"]'); // récupère un élément img avec pour attribut src="image-1.jpg" img.classList.add('hidden'); // j'ajoute à cet élément la classe .hidden } ``` ### Récapitulatif `.getElementById()` `.querySelector()` `.querySelectorAll()` `.constructor.name` `.classList` `.add()` `.remove()` `.toggle()` `.contains()` `.getAttribute()` `.setAttribute()` `.createElement()` `.textContent` `.innerHTML` `.style` `.appendChild()` `.prepend()` `.after()` `.before()` `.addEventListener()` --- ## Partie 4 ### Le mot clé `this` Dans un gestionnaire d'événement on peut accéder à l'**élement déclencheur** grâce au mot clé `this`. ```htmlmixed= <p id="total">Il vous reste <em>?</em> photo(s) à sélectionner</p> <ul class="photo-list"> <li><img src="images/image1.jpg"></li> <li><img src="images/image2.jpg"></li> <li><img src="images/image3.jpg"></li> <li><img src="images/image4.jpg"></li> <li><img src="images/image5.jpg"></li> </ul> ``` ```css= .photo-list li.selected{border: 3px solid forestgreen;} ``` ```javascript= const images = document.querySelectorAll('.photo-list li'); // on stock tous nos <li> dans une constante 'images' (tableau) for(const img of images){ // pour chaque éléments (que l'on nomme 'img') du tableau 'images` img.addEventListener('click', onClickPhoto); // lorsque je 'click' sur mon img je réalise la fonction nommé 'onClickPhoto' } // le mot clé this représente l'élément <li> sur lequel on a cliqué function onClickPhoto(){ this.classList.toggle('selected'); } ``` ### L'objet `event` Une solution alternative à `this` : l'objet `event`. Un gestionnaire d’événement peut récupérer un **objet en paramètre qui représente l’événement** et qui contient des informations dessus. Il permet par exemple également de récupérer l’élément déclencheur, surveillé. La propriété `.currentTarget` nous indique l'élément déclencheur. ```javascript= const images = document.querySelectorAll('.photo-list li'); for(const img of images){ img.addEventListener('click', onClickPhoto); } function onClickPhoto(event.currentTarget){ event.currentTarget.classList.toggle('selected'); } ``` En d'autres termes, `event.currentTarget` contient exactement la même chose que le mot-clé `this`. ### Exemple : Selectionnez un maximum de 3 photos #### En utilisant `if...else` ```javascript= const images = document.querySelectorAll('.photo-list li'); // stock tous les <li> const totalEm = document.querySelector('#total em'); // stock le <em> let total = 3; // nombre de photo restantes à sélectionner (3 par défaut) totalEm.textContent = total; // afficher ce nombre à l'intérieur des <em> for(const img of images){ // pour chaque éléments 'img' contenus dans le tableau 'images' img.addEventListener('click', onClickPhoto); // lorsque je clic sur ce img : faire l'action onClickPhoto // explication de la fonction onClickPhoto function onClickPhoto(){ if(img.classList.contains('selected')){ // si img contient déjà selected img.classList.remove('selected'); // je retire la bordure total++; // total = total + 1; totalEm.textContent = total; } else{ // si img ne contient pas selected if(total <= 3 && total > 0){ // si le nombre de photo restante se situe entre 0 et 3 img.classList.add('selected'); // j'ajoute la bordure total--; // total = total - 1; totalEm.textContent = total; } else{ // sinon message d'erreur window.alert('Vous avez déjà selectionné 3 photos !'); } } } } ``` ### Les fonctions anonymes Une fonction est un objet de la classe `Function`. D'habitude, on mettais en paramètre de notre `.addEventListener` une variable `onClickPhoto` qui contient notre fonction. Mais ont peux donner directement la fonction en paramètre d'`addEventListener`. Elle n'aura donc plus de nom : c'est une ==fonction anonyme== #### Fonction non anonyme En paramètre d'`addEventListener` : notre événement `'click'` et une variable `'onClickPhoto'` qui **contient** notre fonction que l'on défini après. ```javascript= img.addEventListener('click', onClickPhoto); // on défini notre objet function que l'on nomme onClickPhoto function onClickPhoto(){ this.classList.toggle('selected'); } ``` On a donc appelé notre fonction `onClickPhoto` ! #### Fonction anonyme En paramètre d'`addEventListener` : notre événement `'click'` et la fonction. On défini immédiatement dans les paramètre de `.addEventListener` notre fonction. ```javascript= img.addEventListener('click', function(){ this.classList.toggle('selected'); }); ``` La fonction est directement en paramètre, elle n'a pas de nom : c'est une ==fonction anonyme==. ### JavaScript et les formulaires #### Exemple : Dans un formulaire, ajouter une bordure et un texte d'erreur si le champ n'a pas été rempli ```htmlmixed= <main class="project container"> <form class="signup-form"> <div> <label for="email">Email</label> <input type="text" name="email" id="email"> </div> <div> <label for="password">Mot de passe</label> <input type="password" name="password" id="password"> </div> <div> <label for="password-confirm">Mot de passe (confirmation)</label> <input type="password" name="password-confirm" id="password-confirm"> </div> <div> <input class="btn" type="submit" value="Envoyer"> </div> </form> </main> ``` ```css= .error-message { margin-top: 0; font-style: italic; font-size: 0.9em; color: red; } ``` ##### Étape 1 : Message d'erreur pour le champ email ```javascript= const form = document.querySelector('form.signup-form'); // on récupère les éléments du formulaire dans la constante form form.addEventListener('submit', onSubmitForm); // à chaque fois que l'on fait l'évènement 'submit', la fonction onSubmitForm se réalise // Définition de la fonction onSubmitForm function onSubmitForm(event){ // event = l'élèment déclencheur // afin d'eviter que la page se recharge lorsque l'on clique sur le bouton Envoyer (empecher le comportement par défaut du navigateur) event.preventDefault(); // on supprime les précédents messages d'erreurs pour eviter qu'ils apparaissent plusieurs fois à chaque fois que l'on clique sur Envoyer const errors = document.querySelectorAll('.error-message'); for(const error of errors){ // on parcours le tableau errors et on supprime tous les messages error.remove(); } // Champ email const emailField = document.getElementById('email'); // je sélectionne le champ email let email = emailField.value; // récupere la valeur du champ emailField email = email.trim(); // la fonction .trim() permet de retirer les espaces en début et fin de chaine afin qu'un mail composé uniquement d'espaces soit ocnsidéré comme vide if(email.length == 0){ // si le champ email est vide → création du message d'erreur emailField.style.borderColor = 'red'; // on change la couleur de la bordure pour la mettre en rouge const errorPara = document.createElement('p'); // création d'une balise <p> errorPara.textContent = 'Veuillez entrer une adresse mail.'; // ajout du texte a l'intérieur du <p> errorPara.classList.add('error-message'); // ajout de la classe .error-message à notre <p> emailField.after(errorPara); // on place notre p après notre champ email } else{ // sinon c'est que l'email est bien rempli emailField.style.borderColor = 'forestgreen'; } } ``` ##### Étape 2 : Message d’erreur pour le champ mot de passe ```javascript= const form = document.querySelector('form.signup-form'); // on récupère les éléments du formulaire dans la constante form form.addEventListener('submit', onSubmitForm); // à chaque fois que l'on fait l'évènement 'submit', la fonction onSubmitForm se réalise // Définition de la fonction onSubmitForm function onSubmitForm(event){ // event = l'élèment déclencheur event.preventDefault(); // on supprime les précédents messages d'erreurs pour eviter qu'ils apparaissent plusieurs fois à chaque fois que l'on clique sur Envoyer const errors = document.querySelectorAll('.error-message'); for(const error of errors){ // on parcours le tableau errors et on supprime tous les messages error.remove(); } // Champ email const emailField = document.getElementById('email'); let email = emailField.value; email = email.trim(); if(email.length == 0){ // si le champ email est vide → création du message d'erreur emailField.style.borderColor = 'red'; const errorPara = document.createElement('p'); errorPara.textContent = 'Veuillez entrer une adresse mail.'; errorPara.classList.add('error-message'); emailField.after(errorPara); } else{ // sinon c'est que l'email est bien rempli emailField.style.borderColor = 'forestgreen'; } // Champ mot de passe const passwordField = document.getElementById('password'); let password = passwordField.value; password = password.trim(); if(password.length < 8 || password.length > 12){ // si le mot de passe inférieur a 8 ou supérieur à 12 → création du message d'erreur passwordField.style.borderColor = 'red'; const errorPara = document.createElement('p'); errorPara.textContent = 'Veuillez entrer un mot de passe entre 8 et 12 caractères.'; errorPara.classList.add('error-message'); passwordField.after(errorPara); } else{ // sinon c'est que le mot de passe est bien rempli passwordField.style.borderColor = 'forestgreen'; } // Champ confirmation const confirmField = document.getElementById('password-confirm'); let confirm = confirmField.value; confirm = confirm.trim(); if(password != confirm){// si le mot de passe est différent de la confirmation → création du message d'erreur confirmField.style.borderColor = 'red'; const errorPara = document.createElement('p'); errorPara.textContent = 'Votre mot de passe n\'est pas le même'; errorPara.classList.add('error-message'); confirmField.after(errorPara); } else{ // sinon c'est que le mot de passe et la confirmation sont identiques confirmField.style.borderColor = 'forestgreen'; } } ``` ##### Étape 3 : Création de la fonction `.addErrorMessage()` et `.validateField` Pour chaque champs on a répété la même action de création d'un message d'erreur. Pour racourcir le code et éviter de se répéter on peux créer une fonction `.addErrorMessage()` qui affiche un message d'erreur et une fonction `.validateField` qui affiche une bordure verte. ```javascript= function addErrorMessage(field, text){ field.style.borderColor = 'red'; // on change la couleur de la bordure pour la mettre en rouge const errorPara = document.createElement('p'); // création d'une balise <p> errorPara.textContent = text; // ajout du texte a l'intérieur du <p> errorPara.classList.add('error-message'); // ajout de la classe .error-message à notre <p> field.after(errorPara); // on place notre p après notre champ email } function validateField(field){ field.style.borderColor = 'forestgreen'; } ``` On obtient ainsi un code plus court : ```javascript= const form = document.querySelector('form.signup-form'); form.addEventListener('submit', onSubmitForm); // Définition de la fonction onSubmitForm function onSubmitForm(event){ event.preventDefault(); // On supprime les précédents messages d'erreurs pour eviter qu'ils apparaissent plusieurs fois à chaque fois que l'on clique sur Envoyer const errors = document.querySelectorAll('.error-message'); for(const error of errors){ error.remove(); } // Pour éviter de repeter les mêmes actions pour chaque champ. On va créer une fonction qui va permettre la création d'un paragraphe d'erreur et une fonction qui met la bordure en vert si tout est bon function addErrorMessage(field, text){ field.style.borderColor = 'red'; const errorPara = document.createElement('p'); errorPara.textContent = text; errorPara.classList.add('error-message'); field.after(errorPara); } function validateField(field){ field.style.borderColor = 'forestgreen'; } // Champ email const emailField = document.getElementById('email'); let email = emailField.value; email = email.trim(); if(email.length == 0){ // si le champ email est vide → création du message d'erreur addErrorMessage(emailField, 'Veuillez entrer une adresse mail.'); } else{ // sinon c'est que l'email est bien rempli validateField(emailField); } // Champ mot de passe const passwordField = document.getElementById('password'); let password = passwordField.value; password = password.trim(); if(password.length < 8 || password.length > 12){ // si le mot de passe inférieur a 8 ou supérieur à 12 → création du message d'erreur addErrorMessage(passwordField, 'Veuillez entrer un mot de passe entre 8 et 12 caractères.'); } else{ // sinon c'est que le mot de passe est bien rempli validateField(passwordField); } // Champ confirmation const confirmField = document.getElementById('password-confirm'); let confirm = confirmField.value; confirm = confirm.trim(); if(password != confirm){// si le mot de passe est différent de la confirmation → création du message d'erreur addErrorMessage(confirmField, 'Votre mot de passe n\'est pas le même'); } else{ // sinon c'est que le mot de passe et la confirmation sont identiques validateField(confirmField); } } ``` ### Récapitulatif `this` `event` `.currentTarget` `.value` `.preventDefault()` `.remove()` --- ###### tags: `javascript`