LIFAP5 - TP2 : Fonctions sur les tableaux, tests, formulaires

Comme pour le TP1, un projet de départ vous est fourni (archive zip). Il comprend un fichier LIFAP5-TP2.html qui charge le fichier LIFAP5-TP2.js. Le fichier LIFAP5-TP2.js comprend tout l’outillage de base pour la gestion des événements de LIFAP5-TP2.html. Extraire le contenu de l’archive zip, puis ouvrez LIFAP5-TP2.html dans firefox et éditez LIFAP5-TP2.js avec votre éditeur préféré pour répondre aux exercices suivants. Un peu plus tard dans le TP, on utilisera également 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

  1. 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));
  1. 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) {
    tab.push(() => i);
  }
  let t = tab.map((f) => f());
  return t;
}

function f2() {
  let tab = [];
  for (var i = 0; i < 3; ++i) {
    const j = i;
    tab.push(() => j);
  }
  let t = tab.map((f) => f());
  return t;
}
  1. Réécrire la fonction f2() précédente en utilisant une IIFE au lieu d’une déclaration const 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 vous est fourni et permet de lancer Mocha dans le navigateur en utilisant les tests définis dans LIFAP5-TP2-test.js.

Le fichier LIFAP5-TP2-test.js contient des tests pour la fonction garde_entiers_pairs définie dans LIFAP5-TP2.js. 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:

  1. Regarder le contenu de la constante donnees_exemple définie dans LIFAP5-TP2.js et essayer de comprendre comment sont représentées les nouvelles.
  2. 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éthode sort des tableaux précédée d’une copie effectuée grâce à Array.from.
  3. Tester votre fonction en ajoutant des tests dans LIFAP5-TP2-test.js (et en les lançant via LIFAP5-TP2-test.html).
  4. 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>.
  5. 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 utiliser join au besoin.
  6. 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:

  1. Compléter la fonction filtre_mois_annee dans le fichier LIFAP5-TP2.js qui filtre la liste des nouvelles selon le mois et l’année passés en arguments.
  2. Tester cette fonction via Mocha en ajoutant le nécessaire dans LIFAP5-TP2-test.js.
  3. Compléter la fonction maj_liste_nouvelles qui:
    • Récupère le mois dans l’input dont l’id est input-mois et l’année dans l’input dont l’id est input-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 est elt-nouvelles
  4. Compléter la fonction init_3_2 en associant la fonction liste_nouvelles_html au bouton dont l’id est btn-upt-liste.
  5. Tester en essayant différentes valeurs dans la page LIFAP5-TP2.html.

Aide

  • On peut utiliser les méthodes substr et/ou split pour découper les dates en années et en mois.
  • Pour récupérer un élément html selon sont id, on peut utiliser document.getElementById().
  • Pour récupérer ou changer la valeur d’un élément input on peut utiliser le champ value.
  • Pour changer le contenu d’un élément (par exemple mettre à jour le contenu d’un div) on peut faire une affectation sur son champ innerHTML.
  • 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 dans onclick (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 du select.
  • Si l’attribut selected d’un élément option vaut true, c’est cette valeur qui sera présélectionnée dans le menu déroulant.
  • Le champ value d’un élément select contient la valeur de l’option sélectionnée.
  • Le champ onchange d’un élément select peut être utilisé pour enregister un callback qui sera appelé lors d’un choix dans le menu (c’est le pendant du onclick des boutons).
  • Des Set (méthodes) peuvent être utilisés pour éviter les doublons.