---
# System prepended metadata

title: Javascript WF3
tags: [javascript]

---

# 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`
