:: Enseignements :: ESIPE :: E3INFO :: 2020-2021 :: Programmation Web avec JavaScript ::
[LOGO]

Examen Prog Web - Sujet 5 - Session 2


Le but de ce TP noté est d'écrire une version simplifié d'une librarie réactive de manipulation du DOM.

Le cours est disponible à cette adresse http://monge.univ-mlv.fr/~forax/progweb/.

Voilà le code de la page HTML, exam.html, que l'on veut afficher
<!DOCTYPE html>
<html>
 <head>
   <meta charset="utf8"/>
   <script src="exam.js" defer></script>
 </head>
 <body>
  <div id = "my_node">
  </div>
 </body>
</html>
ainsi que le fichier exam.js
// Ecrire le reste du code ici !

render({
  state: 0,
  view: state =>
    v("div", {}, [
      v("h1", { class: "red" }, state),
      v("button", { onclick: state => state - 1 }, "subtract"),
      v("button", { onclick: state => state + 1 }, "add")
    ]),
  node: document.getElementById("my_node")
});

Exercice 1 - virtual domination

Une application réactive est une application qui change sont affichage en fonction du changement de valeur d'un objet particulier qui correspond à l'état de l'application. Par exemple, une application simple qui affiche une valeur avec un bouton + et - pour incrémenter ou décrémenter la valeur auro pour état un simple entier tandis que des application plus compliquées utiliseront des listes ou des objets comme état.
Une application réactive est composée de 3 valeurs différentes, l'état dont nous venons de parler, la vue qui permet à partir de l'état de générer un arbre DOM qui sera affiché (une fonction donc) et enfin un objet DOM de la page HTML qui va être remplacer par l'arbre DOM généré par la vue.
Donc de façon rudimentaire, l'application réactive qui incrémente et décrémente un entier peut se décrire par l'object JavaScript suivant :
    {
      state: 0,
      view: state => ... ,
      node: document.getElementById("my_node")
    }
   

Reste à savoir comment créer l'arbre DOM correspondant à l'état (les ... dans l'exemple, ci-dessus), on se propose pour cela d'utiliser ce que l'on appel un virtual DOM qui est un arbre comme l'arbre DOM mais géré en JavaScript (contrairement à un arbre DOM qui est géré en C et visible en JavaScript).
Voici un exemple de virtual DOM
    v("div", {}, [
      v("h1", { class: "red" }, state),
      v("button", { onclick: state => state - 1 }, "subtract"),
      v("button", { onclick: state => state + 1 }, "add")
    ])
   
La fonction v prend 3 paramètres, un nom d'élement (ici, div, h1 ou button), un ensemble de propriété qui sont les propriétés de l'élément (par exemple la class de l'élement h1 ou la propriété onclick) et enfin une valeur qui peut être soit un élément, soit un tableau d'élements soit une valeur qui va être transformé en string pour être affiché.
Pour notre implantation, la fonction v va renvoyer une instance de la classe Element ayant les attributs name (le nom de l'élement), properties un objet contenant les propriétés de l'élements et textOrChildren qui contient soit un élément, un tableau d'élements ou une valeur.
De plus, la classe Element va possèder une méthode toDOM qui permet à partir d'une élement du virtual-dom de transformer celui-ci en élement réel du DOM créer en utilisant les méthode habituelles document.createElement, document.createTextElement et element.appendChild.
On peut noter que la fonction prise en paramètre par onclick n'est pas la fonction classique prise par la propriété onclick sur l'arbre DOM, en effet, c'est fonction est ajouter sur le virtual dom pas usr le DOM généré. La fonction classique onclick enregistrer lors de la génération de l'arbre DOM par la méthode toDOM va appeler la fonction du virtual dom avec en paramétre l'état de l'application, puis stocker le résultat de l'appel dans le champs state et enfin appeler la fonction render pour changer l'affichage graphique.
Cette astuce permet d'être sur que lorsque l'on clique sur un bouton, l'état de l'application est mis à jour et que l'affichage graphique est raffraichi.

Si on met les différentes parties ensemble, on obtient le code suivant :
render({
  state: 0,
  view: state =>
    v("div", {}, [
      v("h1", { class: "red" }, state),
      v("button", { onclick: state => state - 1 }, "subtract"),
      v("button", { onclick: state => state + 1 }, "add")
    ]),
  node: document.getElementById("my_node")
});
   
Lors de l'affichage de la page, la fonction render prend l'objet correspondant à l'application, récupère la valeur de l'état, appel la fonction view pour créer l'arbre d'élements (le virtual dom, appel la méthode toDOM sur l'arbre d'élement pour créer l'arbre DOM correspondant puis remplace l'objet node par le noeud racine de l'arbre DOM créé (le remplacement se fait en demandant le parentNode de node puis en appelant la méthode replaceChild() sur le parent).

Le code JavaScript doit utiliser la version JavaScript 2015.

  1. Ecrire la classe Element et son constructeur. Ecrire la fonction v qui renvoie une nouvelle instance de la classe Element à chaque appel.
  2. Ecrire dans la classe Element la méthode toDOM et vérifier avec un exemple sans gestion des évènements que l'arbre DOM généré est correct.
    Note: Array.isArray permet de savoir si un objet est un tableau et value instanceof Element permet de savoir si la variable value est un Element.
  3. Ecrire la fonction render et vérifier que l'affichage de la page HTML affiche bien l'arbre DOM générer.
  4. Ajouter la gestion des évènements de tel sorte à ce que l'exemple ou l'on incrémente et décremente une valeur ci-dessus fonctionne.
    Note: value instanceof Function permet de savoir si la variable value est une fonction.