Voici la version du Techies Lab:
En passant, le site LottieFiles offre des animations gratuites pour illustrer le coronavirus.
Crée un nouveau dossier pour ton projet avec les trois fichiers habituels:
Ouvre ton dossier dans ton éditeur de texte (Sublime Text, par exemple).
Crée l'HTML de base de ta page web. On va commencer avec un formulaire qui contient deux entrées: les rouleaux restants et le nombre de jours de confinement.
Le résultat final devrait avoir l'air de ceci:
Et ton code HTML devrait avoir l'air de ceci:
Lorsque les utilisateurs appuient sur le bouton "Calculons", cela doit déclencher un événement: le calcul du ratio.
Comment créer un événement en Javascript? Avec la fonction addEventListener(EVENT, CALLBACK);
qui prend deux arguments, EVENT et CALLBACK.
Cette fonction s'appelle sur un élément HTML qu'il faut d'abord obtenir (get
) et sauvegarder dans une variable:
const form = document.getElementById('form');
form.addEventListener(EVENT, CALLBACK);
Quel est l'événement déclencheur?
Tu trouveras une liste ici avec tous les événements. Lequel choisir? "scroll", "click", "mouseover"?
Regarde dans la section Form events, c'est à dire tous les événements reliés aux formulaires.
Il s'agit de l'événement 'submit'
Le callback d'une fonction c'est généralement... une autre fonction! C'est le code qui va être exécuté lorsque l'événement est déclenché.
function calculateRatio() {
console.log("je suis dans la fonction!!!");
}
const form = document.getElementById('form');
form.addEventListener('submit', calculateRatio);
Si tu ouvres ta console dans ton navigateur et appuies sur le bouton "Calculons", il ne se passe... rien! On ne voit pas les mots "je suis dans la fonction".
C'est un peu bizarre, mais pour régler ce problème, il faut rajouter une ligne dans notre fonction calculateRatio()
:
function calculateRatio() {
console.log("je suis dans la fonction!!!");
event.preventDefault();
}
const form = document.getElementById('form');
form.addEventListener('submit', calculateRatio);
Maintenant que notre fonction calculateRatio()
fonctionne (haha), au lieu de faire un console log sur la string "je suis dans la fonction"
, on va faire un console.log()
sur notre formulaire HTML.
Pourquoi?
Parce que dans notre formulaire se cachent les valeurs qu'on cherche pour calculer notre ratio!
Dans quelle variable de notre code JS avons-nous stocké l'élément HTML form? Comment pouvons-nous l'inspecter?
Regarde la variable form
...
function calculateRatio() {
console.log(form);
event.preventDefault();
}
const form = document.getElementById('form');
form.addEventListener('submit', calculateRatio);
Ceci nous donne accès à l'élément form
dans la console. Si tu cliques sur le triangle à côté de form
tu vas pouvoir voir les "sous-éléments" input
:
Comme on a vu à l'étape précédente, quand on clique sur l'élément form
dans la console, on a accès à ses sous-éléments, dont les éléments input. Chaque input
a un index, un peu comme dans un tableau (array en anglais). On accède à un élément d'un tableau en utilisant les accolades []
: form[0]
.
Dans la console de ton navigateur, essaie de trouver comment accéder à la valeur (value, hint, hint) du premier input
.
form[0].value
Tu peux maintenant utiliser ce code dans ta fonction calculateRatio()
et sauvegarder le nombre de rouleaux dans une belle variable! Vérifie que ta variable stocke la bonne donnée avec un petit... console.log()
!
function calculateRatio() {
const rolls = XXXXX ;
console.log(rolls);
event.preventDefault();
}
const form = document.getElementById('form');
form.addEventListener('submit', calculateRatio);
Trouve l'index de l'élément input
pour le nombre de jours de confinement dans l'élément form
.
Comme pour les rouleaux, sauvegarde le nombre de jours de confinement dans une variable const lockdownDays = XXXX;
lockdownDays
. En JavaScript, quand une variable est faite de plusieurs mots, le premier mot est en minuscules, tandis que la première lettre des mots suivants est en majuscule. Cette syntaxe s'appelle lowerCamelCase
... car elle rappelle les bosses d'un chameau.
D'autres syntaxes existent. En Ruby, par exemple, on utilise la syntaxe snake_case
. Notre variable s'écrirait alors lockdown_days
.
Vérifie que ta variable stocke la bonne donnée avec... console.log()
!
function calculateRatio() {
const rolls = XXXXX ;
console.log(rolls);
const lockdownDays = XXXXX ;
console.log(lockdownDays);
event.preventDefault();
}
const form = document.getElementById('form');
form.addEventListener('submit', calculateRatio);
Toujours dans la fonction calculateRatio()
, on peut maintenant calculer le fameux ratio.
Imaginons qu'un dure 5 jours. Pour calculer le nombre total de jours pour lesquels on aura du papier, il faut faire: rolls * 5
Encore une fois, utilisons une variable pour stocker ce nombre total de jours: const paperDays = rolls * 5;
Vérifie que ta variable paperDays
stocke la bonne donnée avec... Ok, ok, tu sais déjà quoi faire!
console.log()
ou le mettre ne commentaire.
Il ne reste plus qu'à calculer le ratio. Imaginons que j'ai 3 chez moi. Vu que chaque dure 5 jours, il me reste du papier pour 15 jours. Si le confinement dure 15 jours, c'est parfait j'ai tout juste assez de papier. Mon ratio est de 100%.
Mais imagine que le confinement dure 30 jours. Là, je n'ai du papier de toilette que pour la moitié de mon confinement. Mon ratio est de 50%.
Quelle est la formule du ratio?
La formule du ratio est la suivante: paperDays / lockdownDays * 100
Tu peux maintenant stocker ton ratio dans une variable et... oui, oui, console.log(ratio);
for the win!
function calculateRatio() {
const rolls = XXXXX ;
const days = XXXXX ;
const paperDays = rolls * 5;
// console.log(paperDays);
const ratio = XXXXX ;
console.log(ratio);
event.preventDefault();
}
const form = document.getElementById('form');
form.addEventListener('submit', calculateRatio);
Que se passe-t-il s'il te reste 3 et que tu es confiné 27 jours? Quel sera ton ratio?
Pas génial, tous ces chiffres après la virgule! On a besoin d'arrondir notre ratio. Pour ceci, JavaScript a une fonction qui s'appelle... round()
.
En regardant documentation pour la fonction round()
, arrives-tu à arrondir ton ratio?
Voici comment arrondir le ratio: Math.round(paperDays / lockdownDays * 100)
Il est temps d'afficher notre ratio sur notre page web (plutôt que dans la console).
Pour cela, il va falloir l'injecter dans notre HTML. Dans ton fichier HTML tu peux ajouter un élément div
. Donne-lui un id
pour que tu puisse facilement retrouver ta div
dans ton JavaScript.
Retourne maintenant dans ton JavaScript. On veut que le contenu de la div
soit notre ratio
. En d'autres termes, on veut que notre HTML ressemble à ceci:
Petit rappel de vocabulaire:
Pour spécifier le contenu d'un élément HTML, il y a une chouette fonction JavaScript qui s'appelle innerText
. Si tu cliques sur lien de innerText
, tu verras un exemple de comment utiliser cette fonction. Il y a deux étapes:
En JavaScript, il y a plusieurs fonctions pour séléctionner un ou plusieurs éléments HTML. Sais-tu lesquelles?
.getElementById()
, .querySelector()
, ou encore .querySelectorAll()
Comme notre div
a déjà un id
, on va utiliser la fonction .getElementById()
. Celle-ci s'utilise ainsi:
document.getElementById("XXXX")
Remplace les XXXX par le nom de ton id
, en gardant la même syntaxe que dans ton HTML. Dans mon cas, ce sera document.getElementById("output")
Si tu écris document.getElementById(output)
, tu vas voir le message d'erreur suivant dans ta console:
La différence pour nous, mortels, est minime entre output
et "output"
, mais pour JavaScript, ça fait toute la différence du monde!
Pour JavaScript, output
fait référence soit à une fonction, soit à une variable qui s'appelerait "output". Le problème, c'est qu'on n'a pas défini de variable ou de fonction "output". D'où le fait que JavaScript soit tout mélangé et nous affiche un beau message d'erreur en rouge.
Par contre, pour JavaScript, "output"
, c'est tout simplement une string et là, il n'y a pas de problème!
Il ne reste plus qu'à stocker notre élément HTML dans une variable et utiliser la fonction .innerText
:
function calculateRatio() {
// BLABLA PLEIN DE BEAU CODE
const outputDiv = document.getElementById("output");
outputDiv.innerText = XXXX;
event.preventDefault();
}
const form = document.getElementById('form');
form.addEventListener('submit', calculateRatio);
Et ça y est, notre ratio s'affiche!!!
Notre ratio fait un peu pitié. Il est perdu en-dessous du formulaire, on ne sait pas qu'il représente un pourcentage...
Première chose: ajouter le symbole %. Rajoute une string à ton ratio:
outputDiv.innerText = ratio + " %";
Et si on voulait que le ratio soit dans une balise h1
? Dans ce cas, la fonction innerText
n'est pas la plus appropriée. On a besoin d'une fonction qui permet d'insérer de l'HTML: innerHTML
On peut utiliser la fonction innerHTML
comme ceci:
outputDiv.innerHTML = "<h1>" + ratio + " %" + "</h1>";
Pourrait-on simplifier cette ligne de code? La "refactoriser"? Si je pose la question, c'est que la réponse est oui... Essaie!
outputDiv.innerHTML = "<h1>" + ratio + " %</h1>";
On pourrait même aller plus loin en utilisant les "littéraux de gabarits" (template literal en anglais). En gros, il s'agit d'injecter du code Javascript dans une string grâce à cette syntaxe: ${expression}
outputDiv.innerHTML = `<h1>${ratio} %</h1>`;
Note qu'on utilise alors les accents graves ` ` (backticks en anglais) et non les guillements " ".
À côté de notre ratio, on va ajouter un bel émoji! Celui-ci va dépendre du ratio. Si on est au-dessus de 100%, on est 😄, sinon c'est la... 💩
Et qui dit si, dit condition! Petit rappel sur la syntaxe d'une condition:
if (condition) {
// SOME CODE
} else {
// MORE CODE
}
Notre code aurait donc l'air de quelque chose comme ceci:
if (ratio XXXX 100) {
outputDiv.innerHTML = "<h1>" + ratio + " %" + "😄" + "</h1>";
} else {
XXXX
}
La version refactorisée de ce code?
if (ratio XXXX 100) {
outputDiv.innerHTML = `<h1>${ratio} % 😄</h1>`;
} else {
XXXX
}
Normalement, tu peux trouver les émojis de ton choix sur un site comme Emojipedia et simplement les copier-coller dans ton code JavaScript.
Si les émojis ne s'affichent pas correctement, tu dois alors trouver leur code (codepoints):
Il faut ensuite enlever la partie U+
et la remplacer dans ton JavaScript par :
outputDiv.innerHTML = "<h1>" + ratio + " %" + "💩" + "</h1>";
ou
outputDiv.innerHTML = `<h1>${ratio} % 💩</h1>`;
Maintenant que la base fonctionne, on peut s'amuser avec le style. Au lieu d'un formulaire quelconque, pourquoi ne pas utiliser un curseur sur une ligne (slider en anglais)? Comme ceci:
On aura toujours besoin de l'élément HTML input
mais cette fois-ci le type ne sera pas text
mais range
. Range veut dire écart.
Tu peux donc remplacer ton code HTML existant comme ceci:
À ton avis que veulent dire les propriétés min
et max
?
Elles veulent dire que le nombre de rouleau minimum est de zéro et le nombre maximum de 20. Tu sais quoi faire si tu veux permettre à tes visiteurs de calculer leur ratio avec un nombre de rouleaux plus élevé.
Finalement, tu peux te débarasser de l'input
de type submit
. En effet, on n'a plus besoin du bouton "Calculons".
Notre beau ratio a disparu 😭. C'est la faute du JavaScript! Regarde les dernières lignes de ton JS:
const form = document.getElementById('form');
form.addEventListener('submit', calculateRatio);
Notre fonction .addEventListener()
attendait (écoutait) un événement de type 'submit'
. Manque de pot, on vient d'enlever notre bouton "Calculons" (qui lui était un input
de type submit
). Qu'à cela ne tienne:on a de beaux curseurs, on va s'en servir!
On va maintenant écouter... nos curseurs! Et plus particulièrement, quand nos curseurs changent de position. Le temps est venu de retourner à notre documentation sur les événements.
S'il ne s'agit pas de 'submit'
, duquel s'agit-il?
Il s'agit de l'événement 'input'
Dans notre code JS, mettons en commentaire l'event listener sur notre variable form
:
const form = document.getElementById('form');
// form.addEventListener('submit', calculateRatio);
Créons une variable rollsInput
pour stocker l'élément HTML <input type="range">
:
const form = document.getElementById('form');
// form.addEventListener('submit', calculateRatio);
const rollsInput = document.getElementById('XXXX');
Et finalement, ajoutons notre event listener:
const form = document.getElementById('form');
// form.addEventListener('submit', calculateRatio);
const rollsInput = document.getElementById('XXXX');
rollsInput.addEventListener('XXXX', calculateRatio);
Tu peux faire la même chose pour l'input
des jours. Résultat des courses, le ratio s'affiche à nouveau:
Ce qui serait chouette, c'est que nos visiteurs puissent savoir exactement combien de rouleaux et de jours ils ont sélectionné avec les curseurs et que ces nombres se mettent à jour dès qu'on bouge le curseur:
La première chose à faire, c'est ajouter un élément HTML dans lequel on pourra injecter le nombre, grâce au JavaScript. Le plus facile, c'est d'utiliser un élément <span>
dans notre élément <p>
:
<p>Rouleaux restants: <span id="rolls-output"></span></p>
À ton avis, pourquoi a-t-on ajouté l'attribut id="rolls-output"
à notre élément <span>
?
Pour pouvoir sélectionner plus facilement l'élément dans notre JavaScript grâce à la fonction .getElementById()
À l'intérieur de notre fonction calculateRatio
, on peut à présent aller sélectionner l'élément <span id="rolls-output">
et y injecter le nombre de rouleux. D'ailleurs... dans quelle variable est stockée le nombre de rouleaux?
function calculateRatio() {
const rolls = form[0].value;
const lockdownDays = form[1].value;
const rollsOutput = document.getElementById('XXXX');
rollsOutput.innerHTML = XXXX;
Fais la même chose pour le nombre de jours et le tour est joué!
C'est le temps de rendre tout ça BEAU!!! Voici quelques idées:
<div>
et la propriété CSS margin