:: Enseignements :: ESIPE :: E3INFO :: 2024-2025 :: Programmation Web avec JavaScript ::
[LOGO]

AJAX, JSON, Fetch, mise à jour du DOM


Le but de cet exercice est de fabriquer une application simple qui affiche un agenda contenant des évènements définis par une date (when), une occupation (what) et un lieu (where).
Comme pour le TP précédent, on sépare ce que l'on appelle le modèle (model), les données de l'application et la vue (view), l'affichage de ces données.
Comme pour les TPs précédents, on vous demande de créer le rapport du TP8 dans un fichier compte-rendu-tp8.html.

L'application doit pouvoir stocker l'agenda, pour cela nous utiliserons une application backend écrite en Java JExpress.java. Cette application contient à la fois un serveur de fichiers et aussi une API REST qui permet d'obtenir tous les évènements, d'ajouter un évènement, de supprimer un évènement et de modifier un évènement.
Pour exécuter le serveur sur la console, vous utiliserez la commande suivante
    java --enable-preview JExpress.java
   

Normalement, une fois que le serveur est lancé, vous n'avez plus besoin de l'arrêter.
Le serveur, est un serveur de test, qui pour permettre de débugger votre application va attendre 2 secondes avant de traiter les requêtes à l'API pour simuler un serveur utilisé par plein de clients différents.
Par défaut, le serveur sert tous les fichiers qui sont dans le répertoire dans lequel il est lancé. Donc pour servir le fichier agenda.html, les fichiers JExpress.java et agenda.html doivent être dans le même répertoire.
Pour visualiser votre application, le fichier agenda.html est disponible à l'adresse
    http://localhost:8080/agenda.html
   

Attention (Achtung ! Achtung!): comme l'on a besoin de faire des requêtes AJAX sur les endpoints du serveur, votre fichier HTML doit être distribué par le même serveur. Un navigateur ne vous permettra pas de faire des requêtes AJAX si le fichier HTML est chargé en local (avec un file://) sinon vous avez trouvé un bug de sécurité !

L'API REST est définie comme ceci:
  • Obtenir tous les évènements: GET /api/event
    Cet appel renvoi l'ensemble des évènements (id, when, what, where) au format JSON
    Vous pouvez tester en copiant dans votre navigateur http://localhost:8080/api/event.
  • Ajouter un évènement: POST /api/event
    Cet appel prend un paramètre un évènement au format JSON (sans id !) et l'ajoute à la liste des évènements maintenue par le serveur. Cet appel renvoi 200 suivi de l'évènement au format JSON (avec l'id qui a été attribué).
  • Supprimer un évènement: DELETE /api/event/id
    Avec id, la valeur de l'id de l'évènement que l'on veut supprimer. Cet appel renvoi un code 200 si cela s'est bien passé ou 404 sinon.
  • Mettre à jour un évènement: PUT /api/event/id
    Cet appel prend en paramètre un évènement au format JSON (avec l'id), trouve l'élément ayant le même id dans la liste et le met à jour. Cet appel renvoi 200 si l'élément a été mis à jour ou 404 s'il n'existe pas d'élément ayant l'id indiqué.

Note: c'est un serveur de test, il ne vérifie pas du tout les données que vous allez envoyer. À vous de faire un peu attention ! Vous pouvez aussi regarder dans l'onglet "NetWork" des WebTool pour voir si ce que vous envoyez et correcte et si la réponse du serveur est bien celle que vous attendez.
Note2: on peut remarquer que c'est le serveur qui créé les id et pas votre application Web !

Exercice 1 - Agenda

Le but de cet exercice est d'écrire une petite application Web qui permet de gérer un agenda. On veut pouvoir, lister les évènements, ajouter un évènement (when, what, where), supprimer un évènement, mettre à jour un évènement.
Pour cet exercice, nous travaillerons dans le fichier agenda.html.
Et voici une image qui donne un aperçu de l'interface graphique que l'on veut: agenda.png

  1. Dans un premier temps, on va s'intéresser au code déjà existant dans le fichier agenda.html.
    A quoi servent les classes Agenda et Event ?
    A quoi servent les fonctions render et replaceView ?

    Dans render, la partie qui détaille une carte est spécifiée en utilisant une chaine de caractère, quelles sont à votre avis les avantages et inconvénients de cette technique par rapport à utiliser les méthodes document.createElement()/node.appendChild() ?
    A quoi sert la ligne e.preventDefault(); ?

  2. On veut maintenant afficher les évènements qui sont stockés dans le serveur plutôt que ceux qui sont en dur dans le code. Supprimer la version en dur dans le code et utiliser un fetch pour obtenir les évènements auprès du serveur.
    Sachant que l'on veut utiliser async/await, comment doit être déclarée la fonction enregistrée dans le onload ?
    Comme on veut découper en fonction pour rendre le code pus clair, écrire une fonction asynchrone getEvents qui permet d'obtenir les évènements du serveur.
    Puis modifier la fonction onload pour utiliser la fonction asynchrone que vous venez d'écrire.
    Note: n'oubliez pas de faire le rafraichissement graphique une fois que les données ont été chargé.
    Pourquoi doit-on copier les objets obtenus en parsant le JSON envoyé par le serveur dans des objets Event plutôt qu'utiliser directement ces objets ?

  3. On souhaite maintenant pouvoir supprimer un évènement en utilisant le bouton "Delete". L'idée est d'envoyer au serveur une requête demandant la suppression de l'évènement suivie d'une requête re-demandant la liste des évènements.
    Écrire la fonction asynchrone deleteEvent puis modifié la fonction flèche correspondant au click sur le bouton "Delete".

  4. Comme le serveur est assez long à répondre, ce n'est pas très satisfaisant pour l'utilisateur, en effet, on a l'impression que le delete ne marche pas vu qu'il faut attendre.
    L'astuce que l'on utilise habituellement consiste à mettre à jour la vue (en supprimant l'évènement) même si le serveur n'a pas encore répondu, comme cela l'utilisateur à bien la confirmation visuelle de son action (de la demande de suppression).
    Dans le but d'implanter la suppression juste au niveau de la vue, quelle méthode doit-on ajouter à la classe Agenda ? Implanter cette méthode.
    Modifier la fonction flèche correspondant au click du "Delete" pour supprimer l'élément au niveau de la vue. Bien sûr, on laisse les appels au serveur, car il faut aussi supprimer l'évènement du serveur et indiquer à l'utilisateur que la donnée a bien été supprimée (ou pas, s'il y a un problème).
    Rappel: en JavaScript, on utilise la méthode splice pour supprimer un élément d'un tableau.

  5. On souhaite maintenant ajouter l'implantation du bouton "Edit" qui permet de mettre à jour un évènement (changer le when, what, where).
    Sachant que l'on ne peut éditer qu'un seul évènement à la fois, comment doit-on changer le modèle ?
    Sachant que l'on va utiliser le code suivant pour éditer un évènement, modifier le code pour que lorsque l'on clique sur "Edit", la vue edition soit affichée.
             const editForm = document.createElement("form");
             editForm.className = "card-edit-form";
             editForm.innerHTML = `
               <input type="datetime-local" name="when" value="${event.when}" required>
               <input type="text" name="what" value="${event.what}" required>
               <input type="text" name="where" value="${event.where}" required>
               <div>
                   <button type="button" class="cancel">Cancel</button>
                   <button type="submit" class="save">Save</button>
               </div>
             `;
         


  6. On souhaite implanter les deux boutons "Cancel" et "Save" de la vue d'édition. "Cancel" abandonne la vue édition. "Save" met à jour l'évènement sur le serveur et au niveau de l'interface graphique (sans attendre).
    Ajouter l'implantation du bouton "Cancel".
    Puis ajouter l'implantation du bouton "Save".

  7. Enfin, notre interface a un petit problème, on veut éviter que l'on puisse éditer ou supprimer un évènement si celui-ci a été mis à jour et que la confirmation du serveur n'est pas encore arrivé. Par contre, on doit pouvoir éditer n'importe quel autre évènement.
    Comment doit-on modifier le modèle ?
    Comment doit-on modifier la vue ?
    Rappel: désactiver un bouton set fait en ajoutant l'attribut "disabled", button.setAttribute("disabled", true);.