LIFAP5 - TP2 : Fonctions sur les tableaux, tests, formulaires
Comme pour le TP1, un projet de départ vous est fourni. Il comprend un fichier LIFAP5-TP2.html
qui charge LIFAP5-TP2.js
. Le fichier LIFAP5-TP2.js
comprend tout l’outillage de base pour la gestion des événements de LIFAP5-TP2.html
. Copiez les deux fichiers sur votre compte, puis ouvrez LIFAP5-TP2.html
dans firefox et éditez LIFAP5-TP2.js
avec votre éditeur préféré pour répondre aux exercices suivants. Il vous faudra également copier sur votre compte les fichiers LIFAP5-TP2-test.html
et LIFAP5-TP2-test.js
.
Utilisez la console (F12) de firefox pour mettre au point vos programmes.
Exercice 0: Portées en javascript
- Que fait le programme suivant ? Essayer de prédire sa valeur puis vérifier dans la console Javascript de Firefox.
function f(n) {
return (n2) => n + n2;
}let f3 = f(3);
console.log(f3(4));
console.log(f(2)(10));
let f5 = f(5);
let tab = [1, 2, 3];
console.log(tab.map(f5));
- Expliquer la différence entre les deux fonctions suivantes. Essayer de prédire le résultat puis vérifier dans la console Javascript de Firefox.
function f1() {
let tab = [];
for (var i = 0; i < 3; ++i) {
.push(() => i);
tab
}let t = tab.map((f) => f());
return t;
}
function f2() {
let tab = [];
for (var i = 0; i < 3; ++i) {
const j = i;
.push(() => j);
tab
}let t = tab.map((f) => f());
return t;
}
- Réécrire la fonction
f2()
précédente en utilisant une IIFE au lieu d’une déclarationconst j
.
Exercice 1: Transformations de tableaux
Pour chacune des variables définies dans le programme suivant, essayer de prédire sa valeur puis vérifier dans la console Javascript de Firefox.
let tab = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let t1 = tab.filter((n) => n > 3);
let t2 = tab.map((n) => n + 10);
let v1 = tab.some((n) => n !== 3 && n % 3 === 0);
let v2 = tab.some((n) => n !== 5 && n % 5 === 0);
let t3 = tab.filter((n) => n % 2 === 0).map((n) => 2 * n);
let t4 = tab.map((n) => 2 * n).filter((n) => n % 2 === 0);
let v3 = tab.reduce((acc, n) => acc + (n % 2 === 0 ? n * n : 0), 0);
let v4 = tab
.filter((n) => n % 2 === 0)
.map((n) => n * n)
.reduce((acc, n2) => acc + n2, 0);
let v5 = tab.filter((n) => n <= 4).reduce((acc, n) => acc * n, 1);
let v6 = tab
.filter((n) => n % 3 === 0)
.map((n) => ({ v: n, c: 1 }))
.reduce((acc, o) => ({ s: acc.s + o.v, c: acc.c + o.c }), { s: 0, c: 0 });
let v7 = ((o) => o.s / o.c)(v6);
Exercice 2: tests unitaires avec Mocha et Chai
La bibliothèque Mocha couplée avec Chai permet de tester du code Javascript. Elle permet en particulier d’automatiser l’exécution de tests et d’afficher les tests qui ont réussi / échoué.
Dans le cadre de ce TP, on utilisera le style assert
(doc ici) de Chai.
Le fichier LIFAP5-TP2-test.html
(à télécharger) vous est fourni et permet de lancer Mocha dans le navigateur en utilisant les tests définis dans LIFAP5-TP2-test.js
(à télécharger également).
Le fichier LIFAP5-TP2-test.js
contient des tests pour la fonction garde_entiers_pairs
définie dans LIFAP5-TP2.js
(à télécharger). Exécuter les tests en ouvrant simplement LIFAP5-TP2-test.html
dans Firefox.
On constate que certains tests échouent. Recoder la fonction garde_entiers_pairs
dans LIFAP5-TP2.js
en utilisant la méthode filter
des tableaux à la place de la boucle et vérifier que votre implémentation passe tous les tests avec succès. Corriger au besoin.
Exercice 3: Affichage de nouvelles
Cet exercice va consister à mettre en place un affichage pour des nouvelles stockées dans une structure JSON. On devra définir les traitements sur la collection donnees_exemple
puis associer ces traitements aux boutons de l’interface HTML pour les déclencher.
3.1 Structure de la liste de nouvelles et extraction des titres
Dans cet exercice, on s’interdira d’utiliser let
et var
: on n’utilisera que const
.
On souhaite dans un premier temps afficher la liste des nouvelles classées par ordre de date décroissante. Pour y parvenir, il est proposer de suivre les étapes suivantes:
- Regarder le contenu de la constante
donnees_exemple
définie dansLIFAP5-TP2.js
et essayer de comprendre comment sont représentées les nouvelles. - Compléter la fonction
trie_articles_date
qui prend un tableau de nouvelles et renvoie un nouveau tableau trié par date décroissante. On pourra pour cela utiliser la méthodesort
des tableaux précédée d’une copie effectuée grâce àArray.from
. - Tester votre fonction en ajoutant des tests dans
LIFAP5-TP2-test.js
(et en les lançant viaLIFAP5-TP2-test.html
). - Compléter la fonction
formate_titre
qui prend une nouvelle et renvoie une chaîne de caractères contenant le titre de la nouvelle entouré d’une balise<li>
. - Compléter la fonction
liste_nouvelles_html
qui utilisera les méthodes des tableaux et les fonctions définies précédemment pour générer une chaîne de caractères contenant le code HTML permettant d’afficher la liste des titres de nouvelles classées par ordre de date décroissante. On pourra utiliserjoin
au besoin. - Vérifier que l’affichage se fait maintenant correctement dans
LIFAP5-TP2.html
en l’ouvrant avec Firefox
3.2 Boutons et événements
On souhaite pouvoir filtrer les nouvelles selon un mois et une année. Pour cela, on effectue les étapes suivantes:
- Compléter la fonction
filtre_mois_annee
dans le fichierLIFAP5-TP2.js
qui filtre la liste des nouvelles selon le mois et l’année passés en arguments. - Tester cette fonction via Mocha en ajoutant le nécessaire dans
LIFAP5-TP2-test.js
. - Compléter la fonction
maj_liste_nouvelles
qui:- Récupère le mois dans l’
input
dont l’id
estinput-mois
et l’année dans l’input
dont l’id
estinput-annee
. - produit une liste de nouvelles filtrées à partir de
donnees_exemple
grâce àfiltre_mois_annee
- génère le code html correspondant à cette liste via
liste_nouvelles_html
- change le contenu de l’élément de l’
id
estelt-nouvelles
- Récupère le mois dans l’
- Compléter la fonction
init_3_2
en associant la fonctionliste_nouvelles_html
au bouton dont l’id
estbtn-upt-liste
. - Tester en essayant différentes valeurs dans la page
LIFAP5-TP2.html
.
Aide
- On peut utiliser les méthodes
substr
et/ousplit
pour découper les dates en années et en mois. - Pour récupérer un élément html selon sont
id
, on peut utiliserdocument.getElementById()
. - Pour récupérer ou changer la valeur d’un élément
input
on peut utiliser le champvalue
. - Pour changer le contenu d’un élément (par exemple mettre à jour le contenu d’un
div
) on peut faire une affectation sur son champinnerHTML
. - Pour associer une fonction (callback) à un clic, on peut faire une affectation sur le champ
onclick
. Attention c’est la fonction et pas le résultat de son appel qu’il faut ranger dansonclick
(sinon l’appel se fait au moment de l’affectation et pas au moment du click).
3.3 Formulaire dynamique
On souhaite maintenant rendre plus interactif le changement de mois et d’année. Pour cela, on veut remplacer le formulaire par deux menus déroulants (élément select
):
- Le premier correspond à l’année et est initialisé avec la liste des années présentes dans la liste des nouvelles.
- Le second correspond au mois de l’année choisie (en se limitants aux mois pour lesquels on dispose d’un moins une nouvelle).
- Lorsque l’on change le mois, la liste des nouvelles est mise à jour de façon à n’afficher que les nouvelles du mois et de l’année concernée
- Lorsque l’on change l’année, il faut mettre à jour le menu des mois et changer la liste des nouvelles comme pour un changement de mois.
- Par défaut c’est la première année et le premier mois disponible qui sont sélectionnés et la liste des nouvelles doit être filtrée en fonction.
Aide
- Il sera utile de générer tout d’abord les tableaux des années ou des mois avant générer la liste des
option
duselect
. - Si l’attribut
selected
d’un élémentoption
vauttrue
, c’est cette valeur qui sera présélectionnée dans le menu déroulant. - Le champ
value
d’un élémentselect
contient la valeur de l’option sélectionnée. - Le champ
onchange
d’un élémentselect
peut être utilisé pour enregister un callback qui sera appelé lors d’un choix dans le menu (c’est le pendant duonclick
des boutons). - Des
Set
(méthodes) peuvent être utilisés pour éviter les doublons.