Vous devez activer Javascript pour accéder à ce site
 

Semaine

RECHERCHE

Asynchronous JavaScript And XML (AJAX)

Normalement, sur un site web, pour aller chercher de l'information supplémentaire sur le serveur, tel que la description d'un produit ou l'horaire d'un film, il faut charger une nouvelle page web. Cependant, si l'information en question est disponible au format XML, un script ECMAScript peut la récupérer sans forcer le chargement d'une nouvelle page ce qui donne l'impression à l'utilisateur que l'application web est rapide, car il ne voit pas de chargement de pages. Le fait de pouvoir charger un fichier XML du serveur d'origine à partir d'un script ECMAScript constitue l'essentiel d'une technique appelée Asynchronous JavaScript And XML (AJAX) (JavaScript asynchrone et XML). Notons qu'à cause du modèle de sécurité ECMAScript, le fichier XML doit être sur le même serveur et être du même nom de domaine que la page HTML.

Vous avez sans doute déjà utilisé une application AJAX. Les sites de courriel en ligne comme Google Mail l'utilisent presque tous pour charger le contenu d'un message sans forcer le chargement d'une nouvelle page.

Si vous connaissez l'API DOM, la programmation d'une application AJAX n'est pas bien difficile. Il vous suffit d'apprendre un peu de ECMAScript. La classe XMLHttpRequest rend AJAX facile parce qu'elle permet d'aller chercher un fichier XML sur le serveur en quelques lignes de code. Voici un exemple simple de page web comportant un script ECMAScript et chargeant du contenu XML, en l'occurence, deux des pages web :

<?xml version="1.0" encoding="ISO-8859-1" ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>

<title>Exemple AJAX</title>

<script language="JavaScript">
/* Cette fonction va chercher un document XML sur
le serveur et appelle la fonction afficherTitre lorsque
c'est fait! */
function chargeDocument(URI) {
 xmlhttp = new XMLHttpRequest();
 xmlhttp.open("GET", URI,true);
 xmlhttp.onreadystatechange=function() {
 if (xmlhttp.readyState==4) {
  afficheTitre(xmlhttp.responseXML);
  }
 }
 xmlhttp.send(null);
}

/* Cette fonction est appelée lorsque le document XML est 
chargé */
function afficheTitre(doc) {
      // on récupère le contenu de l'unique élément titre
      titreele = doc.getElementsByTagName("title").item(0);
      if(titreele.firstChild != null)
        titre=titreele.nodeValue;
      else
        titre = "";
      // on ajoute un élément au document courant
      // "document" est le document XHTML, à ne pas confondre avec "doc"
      elementp = document.createElement("p");
      elementp.appendChild(document.createTextNode(titre));
      body = document.getElementsByTagName("body").item(0);
      body.appendChild(elementp);
}


</script>
</head>
<body>
<p>Vous pouvez cliquer sur les liens suivants plus d'une fois.
À chaque fois, votre navigateur charge un document XHTML et en 
affiche le titre.</p>
<ul>
<li><a href="javascript:chargeDocument('domtutoriel.xhtml');">
Récupère et affiche 
le titre du document domtutoriel.xhtml.</a></li>
<li><a href="javascript:chargeDocument('travail5.xhtml');">
Récupère et affiche 
le titre du document travail5.xhtml.</a></li>
</ul>
</body>
</html>

Le code ECMAScript n'est pas très long comme vous pouvez le constater. L'attribut readyState de l'objet xmlhttp nous permet de déterminer quand le document XML a été chargé (xmlhttp.readyState==4). La propriété onreadystatechange est quant à elle appelée chaque fois que l'objet de type XMLHttpRequest change d'état. Lorsque le document XML est chargé, on peut donc appeler une fonction qui manipule le contenu de la page web (fonction afficheTitre).

En pratique, les programmeurs utilisent parfois des librairies comme jQuery qui fournissent une API différente pour les appels AJAX, mais l'idée demeure la même.

Voici un exemple similaire, mais qui récupère, cette fois-ci, le fichier RSS du journal le Devoir et en affiche les principales manchettes (le fichier RSS est une représentation en XML du contenu du journal). Pour que cela fonctionne avec un navigateur comme Firefox, il faut au préalable charger le fichier ledevoir.xml et le déposer dans le même répertoire que le fichier XHTML contenant le script AJAX, sur votre disque. Le fil de nouvelles du devoir se trouve normalement à l'adresse « http://www.ledevoir.com/rss/ledevoir.xml ». Le navigateur Chrome ne permet pas la chargement de fichiers locaux de cette manière, nous y reviendrons.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>

<title>Exemple plus avancé en AJAX</title>

<script language="JavaScript">

/* Cette fonction va chercher un document XML sur
le serveur et appelle la fonction afficherTitres lorsque
c'est fait! */
function chargeDocument(URI) {
try {
 
 xmlhttp = new XMLHttpRequest();
 xmlhttp.open("GET", URI,true);
 xmlhttp.onreadystatechange=function() {
 if (xmlhttp.readyState==4) {
  afficheTitres(xmlhttp.responseXML);
  }
 }
 xmlhttp.send(null);
 } catch(o) {alert(o);}
}
/* Cette fonction est appelé lorsque le document XML est 
chargé */
function afficheTitres(doc) {
      titres = doc.getElementsByTagName("title");
      elementol = document.createElement("ol");
      var longueur = titres.length;
      for ( k = 0; k &lt; longueur ; ++k) {
        elementli = document.createElement("li");
        elementli.appendChild(
          document.createTextNode(
            titres[k].firstChild.nodeValue
          )
        );
        elementol.appendChild(elementli);
      }
      body = document.getElementsByTagName("body").item(0);
      body.appendChild(elementol);
}
</script>
</head>
<body>
<ul>
<li><a href="javascript:chargeDocument('ledevoir.xml');">Récupère 
et affiche les nouvelles du devoir.</a></li>
</ul>
</body>
</html>

Finalement, si on souhaite insérer non pas seulement du texte, mais des éléments provenant d'un autre document, on peut obtenir ce résultat avec la fonction importNode :

<?xml version="1.0" encoding="ISO-8859-1" ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>

<title>Exemple AJAX avec importNode</title>

<script language="JavaScript">
/* Cette fonction va chercher un document XML sur
le serveur et appelle la fonction afficheListe lorsque
c'est fait! */
function chargeDocument(URI) {
 xmlhttp = new XMLHttpRequest();
 xmlhttp.open("GET", URI,true);
 xmlhttp.onreadystatechange=function() {
 if (xmlhttp.readyState==4) {
  afficheListe(xmlhttp.responseXML);
  }
 }
 xmlhttp.send(null);
}

/* Cette fonction est appelé lorsque le document XML est 
chargé */
function afficheListe(doc) {
      ule = doc.getElementsByTagName("ul").item(0);
      // on récupère l'élément ul avec tout son contenu:
      body = document.getElementsByTagName("body").item(0)
      body.appendChild(document.importNode(ule,true));
}


</script>
</head>
<body>
<p>Vous pouvez cliquer sur les liens suivants plus d'une fois.
À chaque fois, votre navigateur charge un document XHTML et en 
affiche une partie du contenu.</p>
<ul>
<li><a href="javascript:chargeDocument('domtutoriel.xhtml');">Récupère et affiche 
une liste du document domtutoriel.xhtml.</a></li>
<li><a href="javascript:chargeDocument('travail5.xhtml');">Récupère et affiche 
une liste du document travail5.xhtml.</a></li>
</ul>
</body>
</html>

La classe XMLHttpRequest fait l'objet d'une spécification du W3C. La construction d'un objet XMLHttpRequest est simple (xmlhttp = new XMLHttpRequest();) et généralement suivie de l'appel xmlhttp.open qui prend de 2 à 5 paramètres dont la méthode, l'URL, une valeur booléenne stipulant si l'appel est synchrone ou asynchrone, un nom d'utilisateur et un mot de passe. Les deux derniers paramètres sont utilisés si la ressource est protégée par mot de passe. On utilise généralement des appels asynchrone, pour éviter que le navigateur ne fige en attendant la réponse du serveur. La méthode est une des méthodes définie par le protocole HTTP (RFC 2616) dont GET, PUT, POST, et DELETE.

On utilise le plus souvent AJAX avec des requêtes GET. Comme les requêtes GET ne nécessitent pas la transmission d'un document, on termine la requête avec « xmlhttp.send(null); ». Puisque la requête est asynchrone (le plus souvent) on doit définir une fonction qui sera appelée lorsque la réponse arrivera du serveur (onreadystatechange). Si la réponse du serveur est un fichier XML, on peut le récupérer avec l'attribut « responseXML ». Le document responseXML s'utilise comme tout document DOM. On peut aussi manipuler le document XHTML qui a fait l'appel AJAX avec l'API DOM.

En somme, si on connaît bien l'API DOM, et si on connaît un peu d'ECMAScript, il est facile de développer des applications AJAX si on cible un navigateur comme Firefox ou Chrome. Par contre, les navigateurs diffèrent souvent beaucoup les uns des autres et, en particulier, Internet Explorer ne respecte pas les recommandations du W3C ce qui rend le développement plus difficile.

Voici quelques sites qui utilisent AJAX :

Google rend disponible gratuitement son Google Web Toolkit qui permet de construire des applications AJAX en Java fonctionnant avec tous les principaux navigateurs. Il existe d'autres librairies AJAX telles que jQuery, Dojo, la Yahoo! User Interface Library et Prototype.

À lire: Le site mozilla.org a plusieurs articles sur AJAX (en anglais).

Les fichiers locaux

Pour des raisons de sécurité, certains navigateurs comme Chrome ne permettent pas le chargement AJAX d'un fichier sur le disque local ou sur un serveur distinct de celui où se trouve la page web. On peut tout de même simuler l'effet AJAX localement en demandant à l'utilisateur de charger un fichier local explicitement avec un boîte de saisie à cet effet. Vous pouvez suivre cet exemple:

<?xml version="1.0"  ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>

<title>Exemple AJAX</title>

<script language="JavaScript">
function afficheTitres(doc) {
     titres = doc.getElementsByTagName("title");
     elementol = document.createElement("ol");
     var longueur = titres.length;
     for ( k = 0; k &lt; longueur ; ++k) {
       elementli = document.createElement("li");
       elementli.appendChild(document.createTextNode(titres[k].firstChild.nodeValue));
       elementol.appendChild(elementli);
     }
     body = document.getElementsByTagName("body").item(0);
     body.appendChild(elementol);
}

function chargeDocument(f) {
        var fileReader = new FileReader();
        fileReader.onload = function(evt) {
           var doc = new DOMParser().parseFromString(this.result, 'application/xml');
           afficheTitres(doc);
        }
        fileReader.readAsText(f);
    }
}
</script>
</head>
<body>
  <p>Récupére et affiche
  les nouvelles du devoir: </p>
<input type="file" onchange="readfile(this.files)" ></input>

</body>
</html>

On peut aussi insérer un document XML directement dans un fichier HTML au sein d'un élément de type script comme dans cet exemple:

<html>
<header>
<script id="telephone" type="application/xml">
<annuaire>
   <individu><nom>Jean</nom></individu>
   <individu><nom>Pierre</nom></individu>
 </annuaire>
</script>
<script>
// charge le document XML
function chargeXML() {
  var monxml = document.getElementById("telephone").textContent;
  return new DOMParser().parseFromString(monxml, "application/xml");
}
</script>
</header>
<body>
</body>
</html>

© Daniel Lemire, 2014. Tous droits réservés.