L'objectif de ce TD est de se familiariser avec le langage javascript. On en profitera pour manipuler un format d'image XML : le SVG.
Pour commencer:
- Les slides du cours sont ici : Javascript, JSclient, XML&JSON et AJAX
- Consulter les tutos Javascript, JSclient, DOM, XML&JSON, Validation XML et AJAX
- Ayez à portée de main la documentation de JavaScript sur Mozilla Developper Network
Pour rendre votre travail
Sur le site Edunao.
Pour réaliser les exercices
Il vous faut au minimum une console javascript. Tous les navigateurs en proposent une avec les outils de développement.
Avec Firefox, puisque c'est notre outil par défaut, pour ouvrir la console javascript: Control-Shift-K, ou dans le menu: "outils de développement web" puis "console".
Sinon, avec Repl.it, la zone noire en bas à droite est la console javascript de la page. Pour les besoins du TD c'est le plus simple, cela permet de garder une trace de ce qui est fait.
- Clonez par exemple le repl suivant: https://repl.it/@CSappliWeb2022/Javascript#fact.js
1 - Prise en main de Javascript
1.1 - Javascript, un langage de programmation
- Écrivez un programme qui calcule la factorielle d'un entier positif n demandé à l'utilisateur. Affichez le résultat dans la console du navigateur.
console.log("blah blah blah")
imprime la chaine de caractère dans la console (n'oubliez pas de l'ouvrir !)prompt("Une question")
lance un pop-up permettant à l'utilisateur de rentrer une chaine de caractère- Le résultat est une chaine de caractère...
- Vous pouvez utiliser
parseInt("1234")
pour interpréter une chaine de caractères en un entier.
- Si ce n'est pas deja fait, encapsulez le programme de la partie précédente en une fonction
fact
qui calcule et retourne la factorielle d'un entier positif n (donc en utilisant le mot-clefunction
, comme suit).
- Écrire une fonction
applique
qui prend en argument un tableautab
et une fonctionf
, et qui a le comportement suivant:
Votre fonction pourrait ressembler à cela:
- Utilisez les fonctions
fact
etapplique
pour faire la factorielle de tous les éléments d'un tableau:
- Utilisez
applique
à une fonction non-nommée:
Essayez le code et assurez-vous de comprendre ce qui se passe.
1.2 - JavaScript dans une page web
Nous allons maintenant utiliser JavaScript pour interragir avec la page web. Nous allons donc changer de fichier javascript.
1.2.1 - Premiers pas
- Dans la page HTML (
index.html
), changer la source de la balise de script pourscript.js
- Ajoutez un titre et un paragraphe à la page HTML. Par exemple, mettez dans le <body>:
- Ajouter dans le fichier de script
script.js
un appelconsole.log("le code javascript s'exécute");
et assurez vous que lorsque la page se charge cela apparait dans la console.
1.2.2 - Interception d'un événement
Dans votre page web "index.html", déclenchez l'affichage de la phrase "Le paragraphe a été cliqué" dans la console web lorsque l'utilisateur clique sur le paragraphe.
- Utilisez l'attribut
onclick
qui capture l'évènementclick
... - Ensuite, essayez de le faire en javascript pur.
- Allez voir la slide du cours
1.2.3 - Accès au document
Afficher dans la console web l'objet document
de la page web "index.html". Pour que ce soit intéressant, ouvrez bien la page index.html de votre repl dans une fenêtre dédiée, et ouvrez la console javascript de firefox.
Attention
On ne peut manipuler le contenu d'une page que lorsque cette page est
entièrement chargée, ce qui n'est pas le cas lorsque le JavaScript
commence à s'exécuter si la balise script est en début de page.
En revanche la fonction désignée par
onload
est justement appelée lorsque le chargement de la page
est terminé... Ou il faut bien mettre la balise de script à la fin.
1.3 - Utiliser DOM avec JavaScript
Clonez maintenant le repl https://repl.it/@CSappliWeb2022/Javascript2#index.html
1.3.1 - Accès au contenu du document
Afficher dans la console web la valeur de l'élément <title> de la page web "index.html".
- Vous pouvez aller le chercher "à la main" en parcourant l'arbre
- Ou directement avec
getElementsByTagName
(sachant que cette fonction renvoie une collection)
1.3.2 - Rechercher des éléments dans la page
Ecrire un programme JavaScript qui affiche dans la console web les attributs href
des balises <a>
présentes.
getElementsByTagName
est encore votre ami.
1.3.3 - Modifions la page !
A. Dans votre programme, changer le style des liens: mettez-les en gras, ou en couleur...
- Utilisez par exemple
setAttribute
pour définir l'attributstyle
des éléments qui vous intéressent. - N'oubliez pas les points-virgules à la fin. Par exemple, voila un style potentiel:
- Utilisez par exemple
B. Modifiez le contenu des balise <a>
: ajouter une image (par exemple - Copiez l'adresse du lien pour l'utiliser) en fin de texte.
- Pour chaque élément
a
:- créez d'abord un nouvel élément tout neuf de type
img
- mettez-lui le bon attribut
src
avec la fonctionsetAttribute
- ajoutez-le à la fin des fils de la balise
a
avecappendChild
- créez d'abord un nouvel élément tout neuf de type
- Attention: créez bien un nouvel élément
img
pour chaque balisea
! Si vous ne comprenez pas pourquoi, demandez-moi.
- Pour chaque élément
2 - Montrer et cacher des éléments.
Dans cet exercice, nous allons compléter l'application météo commencée mardi. L'objectif à terme est d'avoir les valeurs que vous avez entrées à la main directement envoyées par le serveur.
Si vous pensez que votre page n'ira pas pour l'exercice
vous trouverez en bas de cette page un exemple de fichier HTML. Vous pouvez bien sûr l'incorporer à votre page le cas échéant.
À faire
Dans un premier temps, et c'est l'objectif de cet exercice, nous allons simplement les faire modifier par des fonctions javascript en local.
- Tout d'abord, les valeurs (températures, pression, etc) que vous avec entrées à la main ne sont peut-être pas facilement accessible avec javascript. Nous allons commencer par éditer le fichier html pour cela.
- Encadrez chacune des valeurs qui devraient être dynamiques par une balise
<span>
. Donnez à ces balises la classecontenu
- Encadrez les unités par une autre balise
<span>
. Donnez à ces balises la classeunite
- Les valeurs peuvent être affichées, ou pas (c'est l'objectif de la page de configuration). Pour chaque balise qui contient la donnée et sa description, donnez la classe
contenant
et un identifiant unique. - Par exemple, si vous aviez cela:
- Encadrez chacune des valeurs qui devraient être dynamiques par une balise
On souhaite avoir cela:
- Ajoutez dans l'entête de votre fichier html une balise
<script>
qui pointe sur un fichier javascript (avec l'extension.js
) dans le même répertoire. - Le reste de l'exercice se fait en éditant ce fichier javascript.
- Écrivez une fonction
cacheTout()
qui cache toutes les balises de la classecontenant
(utilisez un style CSS par exemple). - Écrivez une fonction
montre()
qui prend en argument une liste destring
et qui affiche les balises qui ont les identifiants en question. - Testez vos fonctions dans la console de votre navigateur.
- Par exemple, si vous faites
cela doit tout enlever. Puis (dans le cas de l'exemple qui précède) si vous faisiez cela devrait réafficher uniquement la température et le vent.
3 - Modifier l'arbre de la page à la volée.
Nous allons maintenant parametrer les unités. On se restreint ici à la température et au vent pour simplifier, mais dans un deuxième temps vous pouvez faire plus !
- Dans votre fichier javascript, créez une table d'association comme dans l'exemple suivant:
Cette table va contenir les choix possibles pour les unités. Évidemment, je donne une table pour l'exemple du dessus. Faites pour votre cas de figure.
- Ajoutez une autre table, qui contient les indices des unités choisies. Par exemple:
Donc on veut des températures en Celsius et un vent en mètres/seconde.
- Finalement, il faut une dernière table qui contient les valeurs courantes des mesures. On prend la convention que la valeur est dans l'unité indiquée par l'indice 0 (donc ici: Celsius et km/h).
- On veut maintenant une fonction
afficher()
qui prend ces différents éléments et qui change les valeurs de la page en conséquence.- On accède au champ d'une table d'association avec la le point "
.
", par exemple dans l'exemplevaleurCourantes.vent
vaut -42. - Pour passer de Celsius en Fahrenheit, la formule est TF = TC x 9/5 + 32
- Pour passer de Celsius en Kelvin, la formule est TK = TC + 273,15
- Pour passer de km/h en m/s... Voyons, vous devriez savoir faire.
- Il faut donc changer les textes (avec
element.innerHTML = "nouveau texte"
) des balises<span>
, charactérisées par le nom de leur classe. Par exemple, pour changer le texte "km/h", il faut accéder à la balise<span>
dans la classe "unite" qui est fille (element.children
) de la balise avec l'identifiant "vent". - En principe, si dans la console vous modifiez les valeurs, par exemple:
- On accède au champ d'une table d'association avec la le point "
cela doit changer les unités et les valeurs en conséquence.
4 - AJAX
Dans la l'exercice précédant, vous avez stocké les les valeurs des
données affichées par votre application météo dans la variable
javascript valeursCourantes
locale à la page. Les unités à
utiliser pour l'affichage étaient stockées dans la variable
unitesChoisies
. La page était ensuite modifiée à l'aide d'une
fonction afficher()
qui utilisait cette variable.
Nous allons voir comment récupérer ces valeurs depuis des sources externes.
4.1 - Accès à des données JSON statiques avec JavaScript
- On fournit la donnée JSON suivante, à mettre dans un fichier
pref.json
et qui contient les préférences qui sont sensées correspondre au fichierconfig.html
, que nous traiterons plus tard. Il s'agit donc des valeurs à placer dans la variable globaleunitesChoisies
, et de l'état d'affichage des différents champs.
L'objectif est de récupérer ce fichier à l'aide de la fonction fetch
, de changer les valeurs de la variable globale unitesChoisies
et d'afficher ou de cacher ce qu'il faut.
- Si
state
(oustatus
) vaut 0, on veut cacher le champ en question, le montrer sinon. - Le champ
unite
donne la valeur a mettre dansunitesChoisies
À faire
- Écrivez une fonction
litConfig()
qui lit le fichier json avecfetch()
, récupère les données, mets à jour la variable globaleunitesChoisies
et affiche/cache les champs ad-hoc. - Testez votre fonction dans la console:
- Modifiez le fichier JSON avec un éditeur de texte
- Lancez votre fonction
- Affichez la variable et vérifiez que cela s'est mis à jour
4.2 - De la météo en direct.
Dans cet exercice, nous allons récupérer les informations depuis internet, en utilisant un service météo.
Dans ce repl, vous trouverez le coeur d'une interface web pour une application d'affichage de la météo utilisant les service de http://openweathermap.org. Nous allons essentiellement nous inspirer de ce repl pour compléter notre application météo. Vous pouvez évidemment simplement importer dans votre application météo les morceaux intéressants.
L'objectif est de réaliser une variant de la fonction litConfig()
pour récupérer
les données en faisant un appel à openweathermap, comme dans l'exemple.
À faire
- Allez sur la page http://openweathermap.org/appid et obtenez votre propre ID.
- Changez l'ID pour la votre dans le repl exemple. Assurez-vous que cela marche toujours. Note: l'ID peut mettre un certain temps avant d'être utilisable. Dans l'interval, vous pouvez utiliser celui de l'exemple.
- Changez la langue utilisée pour les réponses: par exemple, en français. La doc du service est là.
- Le serveur donne beaucoup d'informations: Pouvez-vous trouver la température, la pression, le vent, l'humidité, la couverture nuageuse ?
- Un champ "icon" pointe sur une icone résumant le temps : Voir la doc ici.
- Dans votre application météo, réalisez une fonction
litDonnees()
pour effectuer un appel AJAX avecfetch()
à openweathermap. Quid des unités des valeurs numériques ? - Finalement, dans le cas où vous souhaitez afficher les heures de lever et coucher du soleil, vous pouvez trouver ces informations ici par exemple: https://sunrisesunset.io/api/. Les coordonnées GPS de la ville se trouvent dans la réponse à la requête à openweathermap.
4.3 - Utilisons les deux informations à la fois
L'idée maintenant est d'avoir les deux fichiers en même temps. Problème : on veut s'assurer que la variable unitesChoisies
a bien été mise à jour avant d'envisager d'appeler la fonction affichage()
. Mettre cote à cote les deux appels à fetch
ne résoudra pas le problème: chacun des appels est asynchrone. C'est le propre de la programmation événementielle: Il faut donc forcer la séquencialité des choses.
Une manière de faire est d'utiliser la compositionalité de la méthode .then()
des promesses.
À faire
Réalisez une fonction litConfigDonnee()
fait en séquence
- la lecture de la configuration
- la lecture des données
- l'affichage
Il s'agit simplement de chainer les fonctions à l'aide de .then()
.
Attention
La méthode .then()
prend nécéssairement une fonction en argument... Par exemple, si on définit
qui attend le temps demandé avant de faire le contenu du .then()
qui suivrait, les deux choses suivantes n'ont pas le même comportement:
et
5 - Optionnel - Affichage de la météo sur une carte
Notre application météo comporte une image. Nous allons remplacer cette image par une carte où nous placeront à la bonne place l'icone donnée par openweathermap. À cette fin, nous allons utiliser un service de fond de carte. Google propose un tel service, mais je vous propose plutôt d'utiliser ici OpenLayers (nous nous servirons de la version 2, particulièrement simple à utiliser).
- Trouver dans les informations données par le serveur openweathermap la longitude et la latitude de la ville.
- Nous allons maintenant faire appel à OpenLayers pour afficher l'icone à la latitude et longitude donnée. Un exemple d'utilisation de MapQuest (utilisant la version 2) se trouve sur ce repl. Inspirez-vous en pour ajouter une carte à votre appli météo centrée sur la ville avec l'icone résumant le temps.
Conclusion
Nous avons donc (presque) une application complète: il ne manque plus qu'à mettre en fonctionnement la page de configuration. Ce sera l'objectif du TD de jeudi, avec la mise en oeuvre d'un micro-service web.
Appendix - Exemple de page à utiliser
Si vous n'êtes pas sûr de la page principale de votre application météo, ou si vous pensez qu'elle ne correspond pas à l'exercice, en voici une particulièrement simple (sans CSS) mais qui devrait faire l'affaire. Évidemment, les liens ne marcheront pas...