Ajax - Cours Javascript

Introduction

Qu'est ce ajax.

Le terme AJAX veut dire Asynchronous JavaScript And XML soit XML et Javascript asynchrones.

L'AJAX n'est pas une technologie en elle-même, mais un ensemble de technologies couramment utilisées sur le Web :
- (X)HTML, CSS.
- Javascript.
- l'objet XMLHttpRequest pour échanger, récupérer des données avec le serveur Web.

Pour simplifier, il s'agit d'utiliser un
Pour moi, l'AJAX c'est seulement l'utilisation de l'objet XMLHttpRequest. Le reste c'est du DHTML.
C'est pourquoi, nous étudierons seulement l'objet javascript XMLHttpRequest.

Comment ça marche

L'objet ajax XMLHttpRequest est l'élément principal, il va vous permettre d'envoyer au serveur des données au format xml ou texte sous la forme d'une requête HTTP .
Le serveur interprète ces donnés via un langage serveur du type java, php, ....
Une fois le traitement fini, le serveur renvoie à l'objet ajax XMLHttpRequest une réponse au format xml ou texte.
Ce dialogue se fait de façon "asynchrone", c'est à dire sans rechargement de la page html.

Création de l'objet

Définition

La création d'un objet ajax XMLHttpRequest, varie suivant les navigateurs.
Netscape (Firefox/Mozilla) utilise une classe XMLHttpRequest, Internet Explorer utilise un ActiveX appelé XMLHTTP.
Exemple :
Exemple de code :
var httpRequest = null;
if(window.XMLHttpRequest) { // Mozilla, Safari, Firefox ...
  httpRequest = new XMLHttpRequest();
  if (httpRequest.overrideMimeType) {
    httpRequest.overrideMimeType('text/xml');
  }
}else if (window.ActiveXObject) { // IE
  httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}

Dans certain code, j'ai pu voir que l'on testait en plus l'ActiveX ActiveXObject("MSXML2.XMLHTTP") :
Exemple de code :
httpRequest = null;
var XMLHTTP=["MSXML2.XMLHTTP","MICROSOFT.XMLHTTP"];
if(window.XMLHttpRequest){
  httpRequest = new XMLHttpRequest();
}else if (window.ActiveXObject){
  for(var i=0;i<XMLHTTP.length;i++){;
    try{
      httpRequest = new ActiveXObject(XMLHTTP[i]);
      break
    }catch(c){}
  }
}else{
  alert("Votre navigateur ne supporte pas ...");
}

La ligne de code if (httpRequest.overrideMimeType) {...} provoquera des erreurs dans la console JavaScript de Firefox 1.5 ou supérieur la réponse n'est pas du XML valide. Ce comportement est le comportement correct.

Envoi de votre requette

Définition

Vous devez maintenant spécifier l'url de cgi qui va traiter l'information envoyée. Pour cela vous devez spécifier une méthode javascript ajax open(methode, urlcgi, asynchrone).

La méthode ajax open(methode, urlcgi, asynchrone) accepte comme paramètres :
- methode, spécifie la méthode d'envoi de la requête HTTP — GET, POST.
- urlcgi, url de de la page ou du cgi qui va recevoir les informations.
- asynchrone, valeur boolean, true spécifie que l'on attend une réponse du serveur.
Exemple de code :
httpRequest.open('GET', 'http://www.aliasdmc.fr/moncgi.php', true);

Puis pour envoyer votre requête vous devez faire appel à la méthode send(variable). Nous verrons plus tard le paramètre "variable" nous le mettrons à null pour le moment (rub : "Envoyer des valeurs").
Exemple de code :
httpRequest.send(null);

Réponse du serveur

Que faire de la réponse serveur

Vous devez maintenant spécifier les actions à faire quand le serveur vous renvoie une réponse.
Pour cela vous devez spécifier la propriété onreadystatechange de l'objet javascript XMLHttpRequest.
La première méthode consiste a créer une fonction et de l'assigner à la propriété onreadystatechange de l'objet XMLHttpRequest
Exemple de code :
function mafonction(){
  //action
}
m.onreadystatechange = mafonction;

La seconde consiste à créer directement la fonction dans la propriété onreadystatechange de l'objet XMLHttpRequest.
Exemple de code :
httpRequest.onreadystatechange = function(){
  //action
}

Ecoute de la réponse serveur

Dans la fonction qui traite le retour d'informations du serveur (onreadystatechange) vous devez créer une sorte d'écouteur pour savoir ou en est le serveur avec la requête.
pour cela vous devez faire un test sur la propriété ajax readyState qui va vous renvoyer une des ces 5 valeurs :
- 0, non initialisée
- 1, ouverture de la connexion avec le serveur vient de se faire (open())
- 2, envoi de la requête au serveur (send()
- 3, le serveur est entrain d'envoyer les donnés
- 4, terminée, toutes les données sont disponibles
La valeur qui nous intéresse c'est 4.
Exemple de code :
httpRequest.onreadystatechange = function(){
  if(httpRequest.readyState == 4) {
    alert("terminé");
  }
}

Vous remarquerez que je n'utilise pas this.readyState en effet vous devez obligatoirement utiliser le nom l'objet httpRequest que vous voulez tester.

Qu'a répondu le serveur

Un second test doit être effectué, il vérifie le code d'état de la réponse HTTP du serveur grâce à la propriété ajax status. La valeur de status est un code à 3 chiffres. La propriété ajax statusText vous permet de récupérer le message accompagnant le code de réponse.
La valeur qui nous intéresse c'est 200 c'est la réponse qui dit tout est ok.
Exemple de code :
httpRequest.onreadystatechange = function(){
  httpRequest.readyState == 0) {
    if (httpRequest.status == 200) {
      // ok ACTION
    } else {
      // il y a un problème avec la requête
    }
  }
}

Il est conseillé de mettre ce test dans un try{}catch(e){} :
Exemple de code :
try {
  httpRequest.readyState == 4) {
    if (httpRequest.status == 200) {
      // ok ACTION
    } else {
      // il y a un problème avec la requête
    }
  }
} catch( e ) {
  alert("Une exception s'est produite : " + e.description);
}



Vous trouverez d'autres informations sur : Documentation apache [fr]
Voir les autres erreurs :
Apache france
Les réponses HTTP du serveur w3c [en].

Récupération des données

Récupération de l'information

Le serveur a bien envoyé une réponse.
Pour récupérer le contenu de cette réponse vous avez deux possibilités la propriété ajax responseXML et la propriété ajax responseText.

La propriété javascript responseXML récupère les contenus spécifiés XML.
Renvoie un objet XMLDocument ou null pour Netscape (Firefox, mozilla) quand le contenu renvoyé n'est pas xml. Internet Explorer renvoi un objet XMLDocument vide (httpRequest.responseXML.childNodes.length=0).
Si votre contenu n'est pas un format XML valide, Internet Explorer renvoi un objet XMLDocument vide et votre contenu est disponible dans le responseText.

La propriété javascript responseText récupère les contenus non XML et donne une version texte de XMLDocument si celui-ci n'est pas vide ou null.

Exemple de code :
httpRequest.onreadystatechange = function(){
  httpRequest.readyState == 0) {
    if (httpRequest.status == 200) {
      alert(httpRequest.responseXML);
      alert(httpRequest.responseText);
    } else {
      // il y a un problème avec la requête
    }
  }
}

Comment s'avoir si c'est responseXML ou responseText que je dois utiliser ?
Vous êtes sensé connaître le format (texte/xml) de la réponse du serveur, vous pouvez vous baser sur les en-têtes HTTP en utilisant la méthode getResponseHeader().
Exemple de code :
if (httpRequest.status == 200) {
  if(httpRequest.getResponseHeader("Content-Type") == "text/xml"){
    alert(httpRequest.responseXML)
  }else{
    alert(httpRequest.responseText)
  }
}
Cependant le fait qu'Internet Explorer transfère le contenu XML dans responseText quand ce dernier n'est pas valide pose des problèmes.
Après quelques recherches, je me suis appercu que beaucoup de script n'utilise que responseText

Envoyer des valeurs

Définition

Maintenant que vous avez compris le fonctionnement de base de l'ajax nous allons étudier le passage de valeurs au serveur.

Pour la méthode GET :
Vous devez mettre le paramètre de la méthode send à null.
Puis ajouter vos paramètres à la fin de l'urlcgi de la méthode open(methode, urlcgi, asynchrone) comme ceci : urlcgi?nom=valeur&autrenom=autrevaleur
Exemple de code :
httpRequest.open('GET', 'http://www.aliasdmc.fr/moncgi.php? nom=valeur&autrenom=autrevaleur', true);

Pour la méthode POST :
Vous devez mettre le paramètre de la méthode send à nom=valeur&autrenom=autrevaleur;
Exemple de code :
httpRequest.send("nom=valeur&autrenom=autrevaleur")

Vous devez aussi spécifier le type MIME de la requête à l'aide de la méthode setRequestHeader(NomDuHeader, ValurDuHeader) avant de faire un send()
Exemple de code :
httpRequest.setRequestHeader('Content-type','application/x-www-form-urlencoded');

Voici une fonction qui va permettre formater correctement la chaîne à partir d'un objet.
Exemple de code :
function getUrlParametre(objet){
  var result = new Array();
  for(var i in objet){
    result.push(i+"="+encodeURIComponent(objet[i]));
  }
  return result.join('&')
}
var parametre= new Object();
parametre.valeur0="valeur0";
parametre.valeur1="valeur1";
alert(getUrlParametre(parametre));
//valeur0=valeur0&valeur1=valeur1

Traitement des données

Type responseText

Traitment pour une valeur texte comme "aliasdmc"
Si vous voulez remplacer un contenu texte d'une balise html, la solution la plus simple est de faire un nodeValue :
Exemple de code :
var dmc = document.getElementById("alias");
dmc.firstChild.nodeValue= httpRequest.responseText

Si vous voulez l'ajouter avant le contenu texte d'une balise html, la solution la plus simple est de faire un innerHTML :
Exemple de code :
var dmc = document.getElementById("alias");
dmc.firstChild.nodeValue = dmc.firstChild.nodeValue+httpRequest.responseText

Si vous voulez l'ajouter après un contenu d'une balise html, la solution la plus simple est de faire un innerHTML :
Exemple de code :
var dmc = document.getElementById("alias");
dmc.firstChild.nodeValue += httpRequest.responseText


Traitment pour une valeur de type code html "<div>alias<b>dmc</b></div>" :
Si vous voulez remplacer un contenu d'une balise html, la solution la plus simple est de faire un innerHTML :
Exemple de code :
var dmc = document.getElementById("alias");
dmc.innerHTML = httpRequest.responseText

Si vous voulez l'ajouter avant un contenu d'une balise html, la solution la plus simple est de faire un innerHTML :
Exemple de code :
var dmc = document.getElementById("alias");
dmc.innerHTML = dmc.innerHTML+httpRequest.responseText

Si vous voulez l'ajouter après un contenu d'une balise html, la solution la plus simple est de faire un innerHTML :
Exemple de code :
var dmc = document.getElementById("alias");
dmc.innerHTML += httpRequest.responseText

Type responseXML

Traitment pour une valeur XML
Exemple de code :
<root>
    <prenom>alias</prenom>
    <nom>dmc</nom>
</root>

Première étape récupérer le premier noeud (root)
Exemple de code :
var xml = httpRequest.responseXML;
var root_node = xml.getElementsByTagName('root').item(0);
// ou xml.documentElement;

Seconde étape récupérer ses fils (prenom,nom):
Exemple de code :
for(var h = 0;h< root_node.childNodes.length;h++){
  var fils = root_no.childNodes[h];
  if(fils.nodeType==1){
    alert(fils.firstChild.data)
  }
}

Maintenant que vous avez compris le principe de base pour récupérer les informations vous pouvez faire ce que vous voulez de ces données les soque dans un tableau,
Exemple de code :
var toto = new array();
for(var h = 0;h< root_node.childNodes.length;h++){
  var fils = root_no.childNodes[h];
  if(fils.nodeType==1){
    toto[fils.nodeName]=fils.firstChild.data
  }
}

ou les transformer en code html pour les insérer dans votre page
Exemple de code :
var fragment = document.createDocumentFragment();
for(var h = 0;h< root_node.childNodes.length;h++){
  var fils = root_no.childNodes[h];
  if(fils.nodeType==1){
    var el = document.createElement(div)
    el.appendChild( document.createTextNode(     fils.firstChild.data));
    fragment.appendChild(el);
  }
}
var dmc = document.getElementById("alias");
dmc.appendChild(fragment)

voir aussi le chapitre :
Parcourir un arbe XML (bug Firefox)
Le Dom Core

Autres propriétes et méthodes

La méthode ajax getResponseHeader()

La méthode ajax getResponseHeader(valeur) permet de récupérer les informations passer dans l'entête HTTP.
La méthode ajax getResponseHeader(valeur) accepte comme valeur par exemple :
- Date
- Server
- Content-Type

La méthode ajax abort()

La méthode ajax abort() permet de d'annuler le processus d'envoi et récupération.

A savoir

Problème de cache

Attention, lorsque vous faite une requête qui vous renvoie un contenu XML dynamique, vous devez spécifier l'en-tête Content-Type: text/xml car cette en-tête Internet Explorer produira une erreur JavaScript "Objet attendu" après la ligne à laquelle vous tenterez d'accéder à un élément XML.
Cache-Control: no-cache car sans cette en-tête Internet Explorer mettra la réponse en cache et n'effectuera plus jamais la requête ultérieurement.
Exemple en PHP :
Exemple de code :
<?php
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
?>

Écrasement des requêtes

Un problème connu appelé aussi "race condition".
Si la variable httpRequest est utilisée globalement, ce qui est la cas dans les exemples précédent, les réponses du serveur peuvent s'écraser.

Voici un exemple où la variable httpRequest n'est pas globale et évite le problème de "race condition".
Exemple de code :
function makeRequest(url, param) {
  var XMLHTTP=["MSXML2.XMLHTTP","MICROSOFT.XMLHTTP"];
  var httpRequest = false;
  if (window.XMLHttpRequest) { // Mozilla, Safari,...
    httpRequest = new XMLHttpRequest();
    if (httpRequest.overrideMimeType) {
      httpRequest.overrideMimeType('text/xml');
    }
  }else if (window.ActiveXObject) { // IE
    for(var i=0;i<XMLHTTP.length;i++){;
      try{
        return new ActiveXObject(XMLHTTP[i]);
        break
      }catch(c){}
    }
  }
  if (!httpRequest) {
    alert('Impossible de créer une instance XMLHTTP');
      return false;
    }
  httpRequest.onreadystatechange = function() {
    if (httpRequest.readyState == 4) {
      if (httpRequest.status == 200) {
        //action
      } else {
        alert('Un problèmes est survenu avec la requête.');
      }
    }
  };
  httpRequest.open('GET', url+'?'+param, true);
  httpRequest.send(null);
}

Les script dans les réponses serveurs

Lorsque vous avez des script javascript dans la réponse du serveur ces derniers ne sont pas interprétés.
Voici un fonction qui va permettre de les interpréter.
Exemple de code :
function setScripts(target){
  var xml = target;
  if(typeof(target) == "string"){
    if (window.DOMParser) {
      var parser = new DOMParser();
      xml = parser.parseFromString(target, "text/xml");
    } else if (window.ActiveXObject){
      xml = new ActiveXObject("Microsoft.XMLDOM");
      xml.async = false;
      xml.loadXML(target);
    } else {
      alert('Un probleme est survenu la convertion xml.')
    }
  }
  var allscript = xml.getElementsByTagName("script");
  for(var i=0; i< allscript.length; i++){
    code = allscript[i].nodeValue;
      if(code ==null){
        code = allscript[i].firstChild.nodeValue;
      }
      if(window.execScript){ //ie
        return window.execScript(code);
      } else if(navigator.userAgent.indexOf("KHTML") != -1){ //safari, konqueror..
        var s = document.createElement("script");
        s.type = "text/javascript";
        s.innerHTML = code;
        document.getElementsByTagName("head")[0].appendChild(s);
      } else {
        return window.eval(code);
      }
  }
}
setScripts(m.responseXML);
ou
setScripts(m.responseText);

Liens

Prototype.js

Je vous invite fortement de vous pencher sur le framework (orienté objet) javascript Prototype ou jquery.
C'est pour simplifier est une librairie Javascript permettant de faire des manipulations DOM ou de l'AJAX facilement.
Prototype JavaScript Framework
Documentation en français
jquery JavaScript Framework[en]