70. Utiliser AJAX

70.1. Présentation

Le fonctionnement habituel, lors de connexions client serveur, est d’utiliser un formulaire coté client et d’envoyer les valeurs au serveur. Celui-ci traitera les informations puis créera une nouvelle page qu’il enverra au client.

AJAX permet de masquer les transactions client serveur. Nous allons réaliser toutes les transactions en JavaScript et récupérer le résultat dans une variable. Cela nous permettra de traiter nous même le résultat renvoyé par le serveur. L’objectif est ensuite de modifier dans la page le strict nécessaire.

Cette article est à conseiller sur le fonctionnement d'AJAX.

70.2. Initiation Javascript

70.2.1. Types de variables

JavaScript propose un certain nombre de types de variables. Ils sont indiqués par le type de la valeur assignée à la variable. Pour définir une variable, la syntaxe est :

var mavariable;

On peut également lui assigner une valeur :

var mavariable = "hello world";

On peut noter plusieurs types de données :

  • Boolean ;

  • Integer ;

  • Float ;

  • String ;

Pour les définir, rien de plus simple :

var mavar = true;
var mavar = 156;
var mavar = "Bonjour";

La gestion des types est seulement nécessaire dans des cas particuliers comme lors de comparaisons de valeurs. Il est alors possible de forcer le type d’une variable lorsque c’est nécessaire :

// Passer une chaîne de caractères en entier
var unInt = parseInt("111");
// Passer un entier en chaîne de caractère
var uneStr = 111 + "";

70.2.2. Positionner le code dans la page

Le code javascript est généralement placé dans la partie <head> de la page ou dans un fichier séparé .js.

<html>
	<head>
		<title></title>
		<script type="text/javascript" src="/javascript/fonctions.js"></script>
		<script language="JavaScript">
			// mon code Js
			var maVar;
		</script>
	</head>
	<body>
	</body>
</html>

70.2.3. Structure de base

Pour pouvoir coder, il nous manque encore quelques petites choses. Tout d’abord, la syntaxe des fonctions :

function Nom_de_la_fonction (param1, param2) {
	// instructions;
}

La syntaxe du for :

for (i = 1; i <= 10; i++){
	;
}

La syntaxe du if :

if (condition) {
	;
} else {
	;
}

70.2.4. Les chaînes de caractères

Les chaînes de caractères sont un type très utilisé. Voici donc quelques fonctions très pratiques :

  • Longueur de la chaîne de caractère : variable.length.

  • Mettre une chaîne en majuscule : variable.toUpperCase().

  • Mettre une chaîne en minuscule : variable.toLowerCase().

  • Concaténation de chaîne : "cours" + "_" + "eof" donne "cours_eof".

  • Récupérer une partie d’une chaîne : variable.substr(1 , 2) retourne pour variable = "toto" : "ot". Le premier paramètre est l’index du premier caractère que l’on choisit et le deuxième paramètre le nombre de caractère. Le premier caractère d’une chaîne a pour index : 0.

70.2.5. Intéragir avec le code HTML

Il existe de nombreuses possibilités d’intéragir avec le document HTML directement en JavaScript. L’intérêt d’AJAX est de ne pas avoir à recharger la page, on va donc voir comment écrire simplement dans le document HTML. La solution simple est de donner un identifiant (un id) à un élément HTML, par exemple, <div id="message"> et d’utiliser la propriété innerHTML pour changer le contenu :

document.getElementById("message").innerHTML = "Message : "+ MonMessage;

Il est préférable de penser le document HTML comme un document XML. Il est alors possible de créer des noeuds et de les ajouter. On parle alors du Document Object Model.

70.2.6. Programmation orientée objet

Puisque le langage JavaScript permet de faire de l’objet, autant en profiter. Voici comment définir des objets :

// Définition d'un Objet.
function MonObjet() {
	// Attributs 
	this.monAttribut = "";
}

// Définition d'une méthode.
MonObjet.prototype.maMethode = function(param) {
	// Code de la méthode
}

// Création d’un Objet.
var instanceDeMonObjet = new MonObjet();

/*!
 *	Exemple
 */
function carre() {
	this.cote = 0;
}
carre.prototype.setCote = function(newCote) {
	this.cote = newCote;
	return this.cote;
}
carre.prototype.aire = function() {
	return this.cote * this.cote;
}
carre.prototype.perimetre = function() {
	return this.cote * 4;
}

var monCarre = new carre();

70.3. AJAX

Nous allons maintenant voir les différents éléments de la connexion client serveur.

70.3.1. PHP

Coté serveur, nous utiliserons PHP. Nous allons appeler un script auquel nous passerons des informations en GET et il nous retournera l’utilisateur. Voici un script permettant de vérifier si le nom d’utilisateur est correct :

<?php
	$login = isset($_GET["loginToCheck"]) ? $_GET["loginToCheck"] : 0;
	$correctLogin = "arno";
	if ($login == $correctLogin)
		return "ok";

	return "Essayez encore";
?>

Il n’y a donc aucune difficulté particulière du coté serveur.

70.3.2. Récupérer du texte

Nous allons maintenant récupérer du texte en JavaScript. Pour ce faire nous allons utiliser trois fonctions :

  • Une pour définir l’url php à appeler et la méthode d’affichage.

  • Une pour appeler l’url php.

  • Une pour utiliser le résultat.

La première fonction sert donc à définir deux variables et enchainera toutes les tâches. C’est elle que nous utiliserons :

function getInfosToDisplay (param) {
	// send request mode
	url = "http://monsite/monscript.php?monparam=" + param;
	// Méthode affichant le résultat.
	methodToCall = "useTxtInfo";
	// Appelle la méthode pour se connecter au serveur.
	loadXMLDoc(url, methodToCall);
}

Voyons maintenant loadXMLDoc :

function loadXMLDoc (url, methodToCall) {
	// Pour les navigateurs non IE.
	if (window.XMLHttpRequest) {
		objReq= new XMLHttpRequest();
		// methodToCall sera la fonction appelée lorsque la page php sera chargée.
		objReq.onreadystatechange = eval(methodToCall);
		objReq.open("GET", url, true);
		objReq.send(null);
	// Pour Internet Explorer ( activeX doit être activé).
	} else if (window.ActiveXObject) {
		objReq = new ActiveXObject("Microsoft.XMLHTTP");
		if (objReq) {
			objReq.onreadystatechange = eval(methodToCall);
			objReq.open("GET", url, true);
			objReq.send();
		}
	}
}

Le fait de passer la méthode et le script php en paramètre nous permettra de réutiliser loadXMLDoc pour appeler des scripts php différents et des méthodes d’affichages différentes. loadXMLDoc sera donc facilement réutilisable.

Il ne nous reste plus qu’à afficher le résultat :

function useTxtInfo() {
	if (objReq.readyState == 4) {
		// 4 signifie que le chargement est "complet".
		if (objReq.status == 200) {
			// Le serveur web retourne ok (il aurait retournée 404 si le script n’existait pas, etc.).
			// On récupère le texte dans la variable serverAnswer.
			serverAnswer = objReq.responseText;
			// On affiche.
			document.getElementById("answer").innerHTML = serverAnswer;
		} else {
			alert("Problème :\n" + objReq.statusText);
		}
	}
}

Et voila, il ne reste plus qu’à créer un div avec l’id "answer" dans la page html pour afficher la réponse.

Voici le codee utilisé (côté serveur) pour les besoins du test :

[adminbdd html]$ cat server.php
<?php
	// L'en-tête Access-Control-Allow-Origin sert à définir le domaine pour lequel les données pourront être renvoyées.
	header("Access-Control-Allow-Origin: *");
	$login = isset($_GET["loginToCheck"]) ? $_GET["loginToCheck"] : 0;
	$correctLogin = "arno";
	if ($login == $correctLogin)
		echo "ok";
	else
		echo "Essayez encore";
?>

Le code côté client :

<html>
	<head>
		<title></title>
		<script type="text/javascript">
 
			function getInfosToDisplay (login) {
				// send request mode
				url = "http://192.168.5.53/server.php?loginToCheck=" + login;
				// Méthode affichant le résultat.
				methodToCall = "useTxtInfo";
				// Appelle la méthode pour se connecter au serveur.
				loadXMLDoc(url, methodToCall);
			}
			
			function loadXMLDoc (url, methodToCall) {
				// Pour les navigateurs non IE.
				if (window.XMLHttpRequest) {
					objReq = new XMLHttpRequest();
					// methodToCall sera la fonction appelée lorsque la page php sera chargée.
					objReq.onreadystatechange = eval(methodToCall);
					objReq.open("GET", url, true);
					objReq.send();
				// Pour Internet Explorer ( activeX doit être activé).
				} else if (window.ActiveXObject) {
					objReq = new ActiveXObject("Microsoft.XMLHTTP");
					if (objReq) {
						objReq.onreadystatechange = eval(methodToCall);
						objReq.open("GET", url, true);
						objReq.send();
					}
				}
			}
			
			function useTxtInfo() {
				if (objReq.readyState == 4) {
					// 4 signifie que le chargement est "complet".
					if (objReq.status == 200) {
						// Le serveur web retourne ok (il aurait retournée 404 si le script n’existait pas, etc.).
						// On récupère le texte dans la variable serverAnswer.
						serverAnswer = objReq.responseText;
						// On affiche.
						document.getElementById("answer").innerHTML = serverAnswer;
					} else {
						alert("Problème :\n" + objReq.statusText);
					}
				}
			}
 
		</script>
	</head>
	<body>
		<input type="text" onKeyUp="javascript:getInfosToDisplay(this.value)" />
		<div id="answer"></div>
	</body>
</html>

70.3.3. Récupérer du XML

Cette solution est simple et permet de récupérer du texte, ou du code HTML formaté, mais elle est peu pratique pour des données.

Par exemple, dans le cas d’un agenda collaboratif, il n’est pas possible de récupérer les événements.

Lorsque l’on souhaite récupérer des données pour les traiter en JavaScript (les dates de début et de fin des évènements pour l’agenda), on peut utiliser du XML. Le PHP nous renvoie alors un document XML que l’on récupère. La différence sera juste dans useTxtInfo, d’où l’intérêt de découper.

Voici un exemple de la syntaxe à utiliser.

Flux XML :

<lststudent>
	<student>
		<id>1</id>
		<name>Arnauld</name>
	</student>
	<student>
		<id>2</id>
		<name>Johan</name>
	</student>
	<student>
		<id>3</id>
		<name>Denis</name>
	</student>
</lststudent>

Code JavaScript :

function useXmlInfoForStudent() {
	if (objReqStudent.readyState == 4) { // status is complete
		if (objReqStudent.status == 200) { // webserver return ok
			// on récupère du XML
			serverAnswer = objReqStudent.responseXML;
			var lststudent = serverAnswer.getElementsByTagName('lststudent');
			
			for (i = 0 ; i < lststudent[0].childNodes.length ; i++) { //for each student of lstStudent
				//display all the student
				for (j = 0 ; j < lstday[0].childNodes[i].childNodes.length ; j++) { //for each node of studeny				
					if (lstday[0].childNodes[i].childNodes[j].childNodes[l].nodeType != 1) //on test si le noeud contient quelque chose
						continue; // s’il est vide on passe au suivant

					//on récupère le nom du node
					curNodeName = lstday[0].childNodes[i].childNodes[j].nodeName;
					
					switch (curNodeName) {
					case "id":
						// on récupère l’id
						buffId = lstday[0].childNodes[i].childNodes[j].childNodes[l].firstChild.nodeValue;
						break;
					case "name":
						// on récupère le nom
						buffName = lstday[0].childNodes[i].childNodes[j].childNodes[l].firstChild.nodeValue;
						break;
					}
				}
				// on a un nouvel étudiant, traitement de l’étudiant ici
				document.getElementById("listeEtudiant").innerHTML += "<br />id : " + buffId
				document.getElementById("listeEtudiant").innerHTML += " | nom : " + buffName;
			}
		}
	}
}

Comme vous le voyez, le XML est un peu plus difficile à traiter mais il offre énormément de souplesse.