I. Introduction▲
I-A. Public visé▲
La connaissance des fondements de la technologie AJAX est indispensable à la bonne compréhension de cet article. À cet égard, je recommande aux novices de cette technologie de lire cet excellent tutoriel de François DUSSERT.
Pour aborder ce tutoriel, le lecteur doit maîtriser le JavaScript et plus particulièrement les fonctions de rappel (Callback).
Dans le cadre de cet article, JavaScript étant utilisé comme compagnon du HTML 5, une connaissance de ce langage à balises est évidemment nécessaire.
I-B. L'objectif de ce tutoriel▲
Dans ce tutoriel nous allons voir comment récupérer des données stockées au format JSON (JavaScript Object Notation) en simulant une requête asynchrone avec AJAX. Ce format est certainement, à ce jour, le format le plus utilisé pour échanger des données entre systèmes dans le monde du web. Afin de permettre au lecteur de tester cette technologie sans avoir à installer un serveur PHP ni consommer un web-service REST sur Internet. J'ai choisi de vous montrer comment charger dans le navigateur des données depuis un fichier JSON stocké directement sur le PC.
I-C. Bibliothèques et outils utilisés pour les besoins de l'article▲
Tout ce que nous voyons dans cet article s'exécute localement sur le poste de travail dans un navigateur web. Seul un éditeur de texte (Notepad++ ou SublimeText) est donc nécessaire pour ce tutoriel.
En revanche, j'ai l'habitude d'utiliser la célèbre bibliothèque Bootstrap (du non moins célèbre réseau social Twitter) qui aide à la présentation et à la définition du style des éléments de la page HTML en général, et que je l'utilise plus particulièrement dans cet article pour aligner mes différents éléments (boutons labels …) sur une grille. Mais là encore, je la télécharge directement au chargement de la page (via une balise link) donc, rien à installer.
II. Un peu de théorie sur JSON▲
Ce format, comme son nom l'indique, est une notation permettant de sérialiser des objets JavaScript et d'ainsi pouvoir les échanger avec d'autres processus distants. Même s'il vient, nativement, du monde JavaScript (cf. la RFC http://tools.ietf.org/html/rfc4627) la plupart des autres langages (tels que PHP ou Java par exemple) ont développé des bibliothèques standards permettant de manipuler facilement ce format. Ce succès interlangage, qui peut paraître assez surprenant, est dû à ses qualités principales :
- sa faible verbosité qui minimise la quantité de données à passer sur le réseau ;son imbrication « unidimensionnelle » (le XML peut s'imbriquer sous deux dimensions : en sous-balises et en attributs) qui simplifie la conception des données ;
- son interprétation triviale dans la plupart des langages de programmation (ce n'est qu'un tableau associatif (tableau de clés/valeurs) qui peut contenir éventuellement d'autres tableaux associatifs), et ceci, sans descripteur. Même en XML, un schéma XSD est souvent nécessaire (bien que l'on revalide la donnée ultérieurement par un autre processus), car il n'est, par exemple, pas possible de faire la différence entre un tableau à un élément et un élément qui n'est pas un tableau.
Le site officiel de JSON http://www.json.org/json-fr.html propose une excellente introduction en français sur cette notation.
Plutôt que de faire un cours sur sa syntaxe minimaliste, je vous renvoie à Wikipédia et à des sites de création et validation de données JSON en ligne comme le célèbre http://www.jsoneditoronline.org/ (preuve que ce format est consacré par l'usage sur le web).
Et pour vous rassurer, voici l'exemple que nous utiliserons dans cet article :
[
{
"nom"
:
"marteau"
,
"desc"
:
"pour enfoncer des clous"
,
"qte"
:
87
,
"prix"
:
9
},
{
"nom"
:
"cle de 12"
,
"desc"
:
"pour les boulons du camion"
,
"qte"
:
25
,
"prix"
:
12
},
{
"nom"
:
"tournevis"
,
"desc"
:
"pour démonter la table"
,
"qte"
:
26
,
"prix"
:
6
},
{
"nom"
:
"pinces multiples"
,
"desc"
:
"pour bricoler le dimanche"
,
"qte"
:
2
,
"prix"
:
17
},
{
"nom"
:
"scie à métaux"
,
"desc"
:
"pour couper la barrière"
,
"qte"
:
78
,
"prix"
:
41
}
]
Ce fichier, qui se nomme data.json, représente une collection d'outils.
III. Un cas concret▲
Nous allons maintenant réaliser un système de visualisation de ce catalogue dans un navigateur Firefox. Contrairement à IE ou Chrome, Firefox permet d'accéder à des fichiers locaux en AJAX dans une page locale (file://). Ce code ne fonctionne donc pas dans un autre navigateur ou si on l'exécute via un serveur web (pour des raisons de sécurité évidentes : un site ne peut pas accéder au système de fichiers local d'un utilisateur à sa guise !).
III-A. Le cahier des charges▲
On souhaite obtenir une interface de ce type :
Un bouton permet de faire défiler tous les outils du catalogue vers l'avant et un autre vers l'arrière
III-B. L'architecture logicielle ▲
Le principe repose sur l'utilisation d'AJAX et particulièrement de l'objet fétiche de cette technologie : XMLHttpRequestqui nous permet de lire le fichier JSON et d'afficher l'outil demandé de façon asynchrone sans recharger notre page web.
Dans une véritable application de production, nous n'irions pas ouvrir un banal fichier de données, mais plutôt faire une requête à un serveur qui nous renverrait des données au format JSON. Néanmoins, cet échange se ferait de façon tout aussi asynchrone et le traitement dans l'objet XMLHttpRequestyserait identique.
Ainsi, nous pouvons considérer que le chargement depuis un fichier des données permet de simuler le dialogue AJAX entre un serveur et la page HTML tout en simplifiant la vie du lecteur qui n'est pas obligé d'installer un serveur d'applications.
III-C. L'objet XMLHttpRequest▲
Voici le célèbre Script oXHR.js qui contient la fonction qui renvoie l'objet XMLHttpRequest selon le système d'exploitation sur lequel s'exécute le navigateur. Je ne commente pas ce script que l'on peut retrouver à travers toute la littérature AJAX depuis 10 ans. Et qui est détaillé par ailleurs dans les premières pages du tutoriel de François DUSSERT.
function getXMLHttpRequest
(
) {
var xhr =
null;
if (
window
.
XMLHttpRequest ||
window
.
ActiveXObject) {
if (
window
.
ActiveXObject) {
try {
xhr =
new ActiveXObject
(
"Msxml2.XMLHTTP"
);
}
catch(
e) {
xhr =
new ActiveXObject
(
"Microsoft.XMLHTTP"
);
}
}
else {
xhr =
new XMLHttpRequest
(
);
}
}
else {
alert
(
"Votre navigateur ne supporte pas l'objet XMLHTTPRequest..."
);
return null;
}
return xhr;
}
III-D. Le code de l'application▲
Voici le code source (HTML5 + JavaScript) que j'embarque sur ma page unique pour l'IHM. En toute rigueur, il conviendrait de séparer l'IHM en HTML5, des traitements métier portés par un fichier JavaScript distinct. Mais à des fins pédagogiques, j'ai sacrifié la séparation des couches sur l'autel de la compréhension.
<!
doctype html>
<
html lang=
"fr"
>
<
head>
<
meta charset=
"UTF-8"
>
<
title>
Catalogue outillage </
title>
<!--
lien vers la bibliothèque bootstrap -->
<
link
href=
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"
rel=
"stylesheet"
>
<!--
lien vers le script contenant la fonction getXMLHttpRequest-->
<
script type=
"text/javascript"
src=
"oXHR.js"
></
script>
<
script type=
"text/javascript"
>
// pointeur sur la position de l'article courant dans le catalogue
var index =
0
;
// initialisation du catalogue
var catalogue =
[];
function executerRequete
(
callback) {
// on vérifie si le catalogue a déjà été chargé pour n'exécuter la requête AJAX
// qu'une seule fois
if (
catalogue.
length ===
0
) {
// on récupère un objet XMLHttpRequest
var xhr =
getXMLHttpRequest
(
);
// on réagit à l'événement onreadystatechange
xhr.
onreadystatechange =
function(
) {
// test du statut de retour de la requête AJAX
if (
xhr.
readyState ==
4
&& (
xhr.
status
==
200
||
xhr.
status
==
0
)) {
// on désérialise le catalogue et on le sauvegarde dans une variable
catalogue =
JSON.parse
(
xhr.
responseText);
// on lance la fonction de callback avec le catalogue récupéré
callback
(
);
}
}
// la requête AJAX : lecture de data.json
xhr.open
(
"GET"
,
"data.json"
,
true);
xhr.send
(
);
}
else {
// on lance la fonction de callback avec le catalogue déjà récupéré précédemment
callback
(
);
}
}
function lireSuivant
(
) {
// connaitre le nombre d'articles dans le catalogue
var longueur =
catalogue.
length;
// manipulation du DOM pour afficher les caractéristiques de l'article
document
.getElementById
(
"nom"
).
innerHTML =
catalogue[
index].
nom;
document
.getElementById
(
"desc"
).
innerHTML =
catalogue[
index].
desc;
document
.getElementById
(
"qte"
).
innerHTML =
catalogue[
index].
qte;
document
.getElementById
(
"prix"
).
innerHTML =
catalogue[
index].
prix;
if (
index <
longueur -
1
) {
index++;
}
}
function lirePrecedent
(
) {
document
.getElementById
(
"nom"
).
innerHTML =
catalogue[
index].
nom;
document
.getElementById
(
"desc"
).
innerHTML =
catalogue[
index].
desc;
document
.getElementById
(
"qte"
).
innerHTML =
catalogue[
index].
qte;
document
.getElementById
(
"prix"
).
innerHTML =
catalogue[
index].
prix;
if (
index >
0
) {
index--;
}
}
// on initialise la lecture au premier élément
executerRequete
(
lireSuivant);
</
script>
</
head>
<
body>
<
section class=
"container"
>
<
article name
=
"données"
class=
"well form-inline pull-left col-lg-5"
>
<
legend>
Outils au catalogue</
legend>
<
label>
Nom</
label>
:
<
label id =
"nom"
></
label><
br>
<
label>
Description</
label>
:
<
label id =
"desc"
></
label><
br>
<
label>
Quantité</
label>
:
<
label id =
"qte"
></
label><
br>
<
label>
Prix</
label>
:
<
label id =
"prix"
></
label><
br>
<
button
class=
"btn btn-primary"
type=
"submit"
onclick
=
"executerRequete(lireSuivant)"
><
span class=
"glyphicon glyphicon-play"
>
</
span>
Lecture avant</
button
>
<
button
class=
"btn btn-primary"
type=
"submit"
onclick
=
"executerRequete(lirePrecedent)"
><
span class=
"glyphicon glyphicon-step-backward"
>
</
span>
Lecture arrière</
button
>
</
article>
</
section>
</
body>
</
html>
On y retrouve l'appel à la fonction getXMLHttpRequest() pour obtenir notre objet XMLHttpRequest. On invoque la méthode open() de cet objet pour lire le fichier, mais c'est la fonction de callback (fonctions de rappel) lireSuivant() qui traite les données chargées.
Pour ce qui est du traitement JSON :
- Ajax, via XMLHttpRequest nous permet donc d'obtenir un objet (notre catalogue d'outils) sérialisé ;
- dans la fonction de callback la méthode parse() de l'objet JSON permet de « désérialiser » notre catalogue sous forme d'un tableau de tableaux associatifs.
III-E. Test de l'application▲
Vous devez disposer de ces fichiers dans un répertoire :
Il vous suffit alors d'ouvrir catalogue.html avec Firefox pour tester l'application.
IV. Conclusion▲
Cet article a permis d'exposer comment utiliser AJAX pour lire des objets stockés au format JSON. Vous pouvez maintenant aborder des frameworks JavaScript comme AngularJS ou Node.js qui utilisent massivement JSON. Un tutoriel illustre d'ailleurs ce point avec AngularJS : AngularJS le MVC côté client.
Nous tenons à remercier Gnuum pour la relecture technique et Claude Leloup pour la relecture orthographique de cet article.