LE CONCEPT AJAX

Généralités

Introduction

Ajax, acronyme d'Asynchronous JavaScript and XML, est un concept de programmation qui consiste à effectuer, en arrière-plan et depuis une page chargée dans la fenêtre d'un navigateur, des demandes à un serveur web. La page dans la fenêtre du navigateur reste chargée lors de l'exécution de ces tâches. Les solutions de mise en oeuvre sont nombreuses, mais d'une manière générale, le JavaScript reste toujours présent.

Le concept existe depuis fort longtemps, même si le terme "Ajax", relativement récent, date de 2005. Ajax n'a donc été, en aucune façon, une révolution dans le monde d'internet. Cependant, la communication qui a été faite autour de ce concept a généralisé son utilisation.

Le concept consiste donc, la page demeurant chargée :

Envoi de données

L'envoi des données au serveur peut se faire avec plusieurs méthodes :

Réception de données

La réception des données venant du serveur utilise divers formats :

Modes de fonctionnement

Deux modes de fonctionnement sont possibles :

Mise en oeuvre

Plusieurs solutions permettent de mettre en oeuvre Ajax :

Ajax avec XMLHttpRequest

Introduction

XMLHttpRequest est un outil conçu pour effectuer des requêtes sur le serveur sans recharger la page. En dépit de son nom, il a d'autres usages que de seuls documents XML. Le mode asynchrone est, de loin, le plus utilisé.

A l'époque où XMLHttpRequest n'existait pas encore, il fallait recourir à des astuces, telles qu'un iframe invisible, pour obtenir un résultat similaire.

Premier exemple

L'exemple basique proposé ci-dessous utilise :

Fichier "index.html" :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script>
      function requete(nb1,nb2) {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "calcul.php?nb1="+nb1+"&nb2="+nb2, true);
        xhr.send(null);
        xhr.onreadystatechange = function() {
          if (xhr.readyState == 4 && xhr.status == 200) {
             alert(xhr.responseText);
          }
        };
      }
    </script>
  </head>
  <body>
    <button type="button" onclick="requete(3,6);">Calculer</button>
  </body>
</html>

Fichier "calcul.php" :

<?php
  $nb1=$_GET['nb1'];
  $nb2=$_GET['nb2'];
  $retour=2*$nb1+3*$nb2;
  echo $retour;
?>

Commentaire sur le premier exemple

var xhr = new XMLHttpRequest();

On crée l'objet "xhr" issu de la classe "XMLHttpRequest".

xhr.open("GET", "calcul.php?nb1="+nb1+"&nb2="+nb2, true);

On prépare la requête avec la méthode "open()" prennant trois arguments :

Le dernier argument, facultatif, peut ne pas être précisé. Le mode de fonctionnement par défaut est le mode asynchrone.

xhr.send(null);

On envoi la requête.

xhr.onreadystatechange = function() {
  if (xhr.readyState == 4 && xhr.status == 200) {
    ...
  }
};

Les attributs "readyState" et "statut" peuvent prendre plusieurs valeurs. Pour faire simple :

Deuxième exemple

Ce deuxième exemple a pour objectif de montrer :

Fichier "index.html" :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script>
      function requete() {
        var nb1=document.getElementById("nb1").value;
        var nb2=document.getElementById("nb2").value;
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "calcul.php", true);
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xhr.send('nb1='+nb1+'&nb2='+nb2);
        xhr.onreadystatechange = function() {
          if (xhr.readyState == 4 && xhr.status == 200) {
             resultat=JSON.parse(xhr.responseText);
             alert(resultat.calcul2);
          }
        };
      }
    </script>
  </head>
  <body>
    Premier nombre = <input type="text" id="nb1"><br>
    Deuxième nombre = <input type="text" id="nb2"><br>
    <button type="button" onclick="requete();">Calculer</button>
  </body>
</html>

Fichier "calcul.php" :

<?php
  $nb1=$_POST['nb1'];
  $nb2=$_POST['nb2'];
  $cal1=$nb1*2+$nb2*3+1;
  $cal2=$nb2*3+$nb2*4+2;
  $retour='{
    "calcul1":'.$cal1.',
    "calcul2":'.$cal2.'
  }';
  echo $retour;
?>

Commentaire sur le deuxième exemple

xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

La méthode POST consiste généralement à envoyer des valeurs contenues dans un formulaire. Il est nécessaire de modifier les en-têtes d'envoi des données.

resultat=JSON.parse(xhr.responseText);

La chaîne de caractères reçue, au format JSON, est convertie en un objet "resultat". Il comporte ici les deux attributs "calcul1" et "calcul2".

Ajax avec jQuery

Introduction

La mise en place de XMLhttpRequest dans les navigateurs s'est faite progressivement. De plus au début, la syntaxe variait selon les navigateurs. L'utilisation d'une bibliothèque telle que jQuery présente donc un avantage et un inconvénient.

La bibliothèque jQuery contient la fonction "$.Ajax()", prenant divers arguments :

ArgumentValeur
urlLe fichier ciblé
type'POST' ou 'GET', selon le type de requête
dataLes données envoyées au serveur
dataType'json', 'xml', 'text' ou 'html' selon le type de données venant du serveur
successLa fonction à appeler si la requête a réussi
errorLa fonction à appeler si la requête a échoué
completeLa fonction à appeler une fois la requête effectuée.

Exemple

L'exemple basique proposé ci-dessous utilise :

Par rapport à l'exemple précédent, seul le fichier "index.html" est modifié :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script src="jQuery.js"></script>
    <script>
      $(document).ready(function() {
        $('#f').submit(function(event) {
          event.preventDefault();
          $.Ajax({
            type: 'POST',
            url: 'calcul.php',
            data: $(this).serialize(),
            dataType: 'json',
            success: function(resultat) {
              alert(resultat.calcul2);
            }
          });
        });
      });
    </script>
  </head>
  <body>
    <form id="f" method="post">
      Premier nombre = <input type="text" name="nb1"><br>
      Deuxième nombre = <input type="text" name="nb2"><br>
      <button type="submit">Calculer</button>
    </form>
  </body>
</html>

Commentaire

$(document).ready(function() {

Le document doit être chargé au préalable...

$('#f').submit(function(event) {

La fonction est appelée lorsque l'utilisateur clique sur le bouton "submit" du formulaire.

event.preventDefault();

La méthode "preventDefault()" empêche le navigateur de déclencher son comportement par défaut.

data: $(this).serialize(),

La méthode "serialize()" de jQuery simplifie l'écriture des données à envoyer au serveur. Il serait possible d'écrire le code ci-dessous à la place.

data: 'nb1='+nb1+'&nb2='+nb2,

Ajax avec un IFRAME

Introduction

Cette solution était mise en oeuvre bien avant l'apparition de la classe XMLhttpRequest de JavaScript. Elle présente donc une excellente compatibilité avec l'ensemble des navigateurs, récents ou anciens. Naturellement, cette solution est rarement retenue dans les projets modernes.

Exemple

Le tout premier exemple de cet exposé est repris. Le fichier "index.html" est modifié comme il suit.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script>
      function requete(nb1,nb2) {
        document.getElementById('cache').src = 'calcul.php?nb1='+nb1+'&nb2='+nb2;
        document.getElementById('cache').onload = function() {
          resultat=document.getElementById('cache').contentDocument;
          alert(resultat.body.textContent);
        }
      }
    </script>
  </head>
  <body>
    <button type="button" onclick="requete(3,6);">Calculer</button>
    <iframe id="cache" style="display:none;"></iframe>
  </body>
</html>

Fichier "calcul.php" retourne une page au format HTML :

<html>
  <head></head>
  <body>
    <?php
      $nb1=$_GET['nb1'];
      $nb2=$_GET['nb2'];
      $retour=2*$nb1+3*$nb2;
      echo $retour;
    ?>
  </body>
</html>

Commentaire

<iframe id="cache" style="display:none;"></iframe>

L'élément iframe permet d'intégrer une page HTML, pour l'instant inexistante et cachée avec le style "display:none;", dans la page principale.

document.getElementById('cache').src = 'calcul.php?nb1='+nb1+'&nb2='+nb2;

La page "calcul.php" est chargée dans l'iframe avec ses paramètres.

resultat=document.getElementById('cache').contentDocument;
alert(resultat.body.textContent);

Le résultat contenu entre les balises <body> et</body> est affiché dans une boîte de dialogue.

Variantes

Il existe plusieurs variantes à la solution présentée ci-dessus :

document.getElementById("monimage").src="image.php?param1=1&param2=2"

Ajax en complétant le DOM

Introduction

Une application web comporte, en général, un nombre important de fonctions. Parfois certaines fonctions, secondaires, ne sont appelées qu'en de rares occasions. Pour éviter de charger sur le client du code qui ne sera probablement pas interprété, il est possible de ne le charger qu'en cas de besoin.

Il s'agit toujours d'Ajax, mais aucune donnée n'est transmise au serveur. Sa mission est simplement de fournir, à la demande, du code en JavaScript. Pour se faire, une solution consiste à faire évoluer le DOM en y ajoutant les noeuds nécessaires.

Exemple

Fichier "index.html" :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script>
      function tester() {
        script_complementaire = document.createElement("script");
        script_complementaire.src="complement.js";
        document.body.appendChild(script_complementaire);
      }
    </script>
  </head>
  <body>
    <input type="button" value="TESTER" onclick="tester();">
  </body>
</html>

Fichier "complement.js" :

alert("Le script complémentaire est appelé!");

Commentaire

Dans l'exemple de base ci-dessus, le fichier "complement.js" est chargé dans la page lorsque l'utilisateur clique sur le bouton "TESTER".

Acquisition périodique

Introduction

Il est parfois nécessaire qu'une requête de type Ajax se fasse de manière cyclique et automatique. Il s'agit, par exemple, d'afficher des informations en temps réel.

Les solutions proposées ci-dessous, bien que fonctionnelles, sont de moins en moins utilisées car elles sont gourmandes en ressources. Elles ont tendance à être remplacées par des solutions basées sur les WebSockets.

La fonction "setTimeOut()"

La fonction "setTimeOut()", disponible avec les premières versions de JavaScript, présente l'avantage d'être compatible avec l'ensemble des navigateurs. Comme elle n'appelle qu'une seule fois la fonction souhaité, il est nécessaire de créer un rappel. L'exemple ci-dessous est celui d'une fonction "requete()", appelée une fois la page complètement chargée, et ce toutes les cinq secondes.

<script>
  function requete() {
    ...
    setTimeout(requete,5000);
  }
  window.onload=requete();
</script>

A l'aide d'un identifiant, on peut annuler l'exécution de "setTimeout()" avec la fonction "clearTimeout()".

<script>
  var identifiant=setTimeout(requete, 5000); 
  ...
  clearTimeout(identifiant);
</script>

La fonction "setInterval()"

La fonction "setInterval()", relativement récente, présente l'avantage d'être plus simple à mettre en oeuvre. L'exemple ci-dessous est similaire à celui vu précédemment. On note qu'avec certains navigateurs, le délai de "setTimeout()" n'est pas très stable. On préfère donc souvent utiliser "setTimeout()" en boucle, à la place de "setInterval()".

<script>
  function requete() {
    ...
  }
  window.onload=function(){
    setInterval(requete,5000);
  };
</script>

A l'aide d'un identifiant, on peut annuler l'exécution de "setInterval()" avec la fonction "clearInterval()".

<script>
  var identifiant=setInterval(requete, 5000); 
  ...
  clearInterval(identifiant);
</script>

L'attribut "refresh" de la balise "meta"

Cette solution est utilisée dans le cas d'une page web chargée dans un iframe. Cette page web comporte une balise "meta" avec l'attribut "refresh", de sorte qu'elle se réactualise de façon automatique après un certain délai. Dans l'exemple ci-dessous, ce délai est défini à cinq secondes.

<meta http-equiv="refresh" content="5">