8. jQuery et AJAX▲
On présente souvent jQuery (et d'autres bibliothèques similaires) comme un framewok AJAX. C'est une erreur, les chapitres précédents sont là pour démontrer !
Cette affirmation tient surtout à la montagne que se font certains de la technologie AJAX, la considérant presque comme un monstre sacré accessible seulement pour une poignée d'initiés. C'est bien évidemment faux et AJAX, une fois que l'on en a compris le principe, est relativement simple à manier.
Nous allons donc voir les différentes solutions proposées par jQuery pour faciliter toutes les opérations liées à AJAX. En effet, jQuery vous permet bien sûr de simplifier la syntaxe de vos appels, mais offre aussi la possibilité d'utiliser des raccourcis de code très efficaces pour les opérations les plus courantes et gère les cas plus complexes grâce à des possibilités de paramétrage très poussées.
Tous les termes inclus dans l'appellation AJAX (Asynchronous JavaScript And XML) ne sont là que pour rendre l'acronyme imposant, à tel point qu'un groupe de développeurs, constatant qu'AJAX n'avait pas besoin de serveur (en tout cas de langage serveur) ni de XML, ont créé par dérision un nouvel acronyme pour des requêtes simples : AHAH (Asynchronous HTTP And HTML). Vous noterez l'aspect volontairement moqueur de cet acronyme. Mais dans un sens, ils ont raison. En effet, il faut voir AJAX comme un équivalent aux liens hypertexte. Lorsque vous cliquez sur un lien hypertexte (balise <a>), le navigateur récupère une adresse (la valeur de l'attribut href), envoie une requête au serveur sur cette adresse, le serveur quant à lui crée si besoin une page (si l'adresse demandée correspond à un script serveur du type PHP), sinon il récupère le contenu du fichier correspondant et renvoie ce résultat au navigateur qui affiche la nouvelle page. Une requête AJAX, c'est exactement la même chose, mais dans le cadre de la partie JavaScript de la page.
Lorsqu'un événement prédéfini est lancé (et il s'agit souvent d'un clic), JavaScript récupère une adresse à interroger, ouvre une connexion avec le serveur et lui transmet la requête. Là encore, le serveur interprète le script appelé si besoin, sinon il lit le fichier demandé et renvoie la réponse à l'interpréteur JavaScript du navigateur. Bien sûr, ici, il ne s'agit plus d'afficher une nouvelle page, donc le résultat renvoyé par le serveur devra être adapté à un traitement par JavaScript qui permettra d'interpréter la réponse et si besoin de modifier l'affichage.
À titre d'exemple, une requête basique en JavaScript s'écrirait :
var xhr = new XMLHttpRequest();
var parametre = '?nom=' + document.getElementById('champNom').value;
parametre+= '&prenom=' + document.getElementById
('champPrenom').value;
xhr.open('GET', 'ajax.php' + parametre);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
traitementAjax(xhr.responseText);
}
xhr.send(null);
La première ligne crée une nouvelle instance de l'objet JavaScript XMLHttpRequest comme on le ferait avec n'importe quel objet.
On crée ensuite une chaîne correspondant aux paramètres à envoyer au serveur (ici, des valeurs de champs de formulaire) que l'on fait précéder d'un point d'interrogation car les paramètres seront transmis en GET, donc inclus dans l'URL. Le point d'interrogation permet au langage serveur de savoir où commencent les paramètres, chaque paire paramètre / valeur étant, quant à elles, séparées par des esperluettes (caractère &).
On ouvre ensuite une connexion vers le serveur avec la méthode open() à laquelle on passe en paramètre le type de requête (le plus souvent GET ou POST) et l'URL appelée (à laquelle il ne faut pas oublier d'ajouter les paramètres).
On définit ensuite les actions à accomplir à chaque changement d'état de la requête (événement onreadystatechange) et si les propriétés readyState et status correspondent à une réponse reçue, on appelle une fonction de rappel.
Enfin, on lance la requête avec la méthode send(). La requête étant de type GET, on lui passe la valeur null en paramètre car aucun paramètre ne peut être transmis. En cas de requête de type POST, alors on construit la chaîne de paramètres de la même façon, mais sans le point d'interrogation initial, et on passe cette chaîne en paramètre de la méthode send(). Il sera aussi nécessaire en POST d'ajouter une instruction avant d'appeler la méthode send() pour spécifier le header envoyé au serveur :
xhr.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');
Bien que simplifié au maximum, cet exemple permet de gérer la plupart des besoins. La syntaxe n'est pas particulièrement compliquée. Toutefois, il faut prendre en compte que jusqu'à la version 7, Internet Explorer n'implémente pas l'objet XMLHttpRequest et qu'il faut dans ce cas utiliser un activeX. En comparaison, le code équivalent avec jQuery serait :
$.get('ajax.php', 'nom='+$('#champNom').val()+'&prenom='+$('#champPrenom')
.val(), function(reponse){
traitementAjax(reponse);
});
La syntaxe est un peu particulière et nous la détaillerons ultérieurement.
8-1. Qu'est-ce qu'une requête asynchrone ?▲
Une autre notion importante à connaître concernant AJAX est l'aspect asynchrone. Lorsqu'une requête est asynchrone (et ce sera la majorité des cas a priori), alors le script n'attend pas la réponse du serveur pour continuer son exécution, c'est pour cela que tous les traitements relatifs au résultat de la requête doivent se faire dans la fonction de rappel de l'événement onreadystatechange. Mais cet événement se déclenche plusieurs fois ; comme son nom l'indique à chaque changement de la valeur de la propriété readyState :
Une requête asynchrone peut avoir cinq readyState distincts :
- 0 : la requête n'est pas initialisée (mais l'objet a été créé) ;
- 1 : la requête a été initialisée (appel de la méthode open() ;
- 2 : la requête a été envoyée (appel de la méthode send() ;
- 3 : le serveur est en cours d'envoi de la réponse ;
- 4 : le serveur a fini d'envoyer la réponse.
Dans la plupart des cas, seul l'état 4 est utilisé, mais l'état 3 peut avoir un intérêt dans des cas spécifiques. Il convient toutefois de se méfier : si le serveur renvoie une réponse courte, alors l'ensemble sera retourné en une seule fois, dans ce cas, les états 3 et 4 sont quasiment confondus. En revanche, s'il y a beaucoup de données à récupérer, alors il y a de fortes chances pour qu'elle soit envoyée en plusieurs paquets. Dans ce cas de figure, l'état 3 permet de commencer à traiter la portion de réponse reçue et de faire moins attendre l'utilisateur.
En parallèle à l'état de la requête, on observera aussi la valeur de la propriété status, qui correspond à la valeur du status HTTP de la réponse (par exemple, la valeur 200 signifie que la page a bien été trouvée, 404 qu'elle n'a pas été trouvée, etc.). En fonction de cette valeur, on pourra donc savoir si la requête a bien abouti ou non.
Il est aussi possible de forcer une requête synchrone en passant un troisième paramètre à la méthode open(), de type booléen, avec la valeur false. Dans ce cas, le script sera figé en attendant la réponse du serveur. Il devient alors inutile d'utiliser l'événement onreadystatechange :
var xhr = new XMLHttpRequest();
var parametre = '?nom=' + document.getElementById('champNom').value;
parametre+= '&prenom=' + document.getElementById('champPrenom').
value;
xhr.open('GET', 'ajax.php' + parametre, false);
xhr.send(null);
traitementAjax(xhr.responseText);
Le point important à retenir, c'est qu'en mode asynchrone, il faut toujours attendre la réponse du serveur avant d'essayer de la traiter !
8-2. AJAX vu par jQuery▲
Nous venons de voir qu'en JavaScript pur, la syntaxe diffère selon que l'on utilise une requête GET ou POST et selon que l'on est en mode synchrone ou non. Comme toujours, jQuery s'efforce de vous simplifier les choses et la syntaxe sera similaire dans tous les cas.
$.get( url, [parametres,] [callback(reponse, textStatus, jqXHR),]
[dataType]);
$.post( url, [parametres,] [callback(reponse, textStatus, jqXHR),]
[dataType]);
Pour ces deux méthodes, url représente la page à appeler, parametres les paramètres à envoyer à cette page, callback la fonction de rappel à lancer si la requête est considérée comme réussie, cette fonction récupère en paramètres la réponse reçue, le texte associé au statut de la réponse HTTP et l'objet interne de jQuery représentant l'objet XMLHttpRequest, enfin dataType précise le type des données attendues en réponse.
Les paramètres peuvent être passés soit sous forme de chaîne (dans le cas d'une requête GET, ne pas mettre le « ? ») soit sous forme d'objet de couples nom / valeur. Attention toutefois : si vous passez les paramètres sous forme d'objet, jQuery les transformera en interne en chaîne, d'autre part, cela ne présage pas de ce que vous allez recevoir comme type de réponse, passer un objet de type JSON en paramètre ne signifie pas que l'on attend en réponse un objet JSON.
La fonction de rappel sera lancée uniquement si la requête aboutit. Cela ne limite pas nécessairement à un status HTTP à 200, par exemple, une requête avec un status 301 (Moved Permanently) est aussi considérée réussie. Les paramètres que récupère cette fonction de rappel sont d'abord la réponse du serveur, qui aura préalablement été traitée en fonction de ce qu'elle est supposée représenter, le texte correspondant à l'état de la requête pour l'objet AJAX de jQuery et enfin l'objet jqXHR qui est l'objet AJAX créé en interne par jQuery (attention, il ne s'agit pas de l'objet XMLHttpRequest lui-même).
Enfin, le dataType correspond au type de données attendues en retour : xml, html, script, json, jsonp ou text. Si vous connaissez le type de données que vous allez recevoir, il est conseillé de le préciser, sinon, jQuery va essayer de deviner ce dont il s'agit.
À titre d'exemple, voyons deux cas concrets :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<title>AJAX</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
$(function(){
$.get('ajax/ajax.html', function(data){
alert(data);
});
});
</script>
</head>
<body>
<h1>Ajout de contenu via AJAX</h1>
<div id="dynamique">
</div>
</body>
</html>
<h2>Paragraphe AJAX</h2>
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In
vehicula, lorem eget auctor accumsan, dui lorem consequat quam, in
187
bibendum quam sapien eget augue. Duis adipiscing, justo eget tempor
semper, diam mauris laoreet urna, nec congue elit turpis imperdiet
risus. Aliquam facilisis venenatis neque sit amet ultricies. Donec
dolor metus, bibendum et iaculis quis, sollicitudin eu felis.
Pellentesque quam augue, ullamcorper a interdum eu, facilisis ac
quam. Suspendisse tortor elit, rutrum at volutpat id, gravida at
sem. Integer nec venenatis ligula. Class aptent taciti sociosqu ad
litora torquent per conubia nostra, per inceptos himenaeos. In non
magna feugiat sapien consectetur scelerisque quis non turpis. Aenean
posuere tellus ac sapien semper sodales sodales libero fermentum.
Nulla facilisi. Nam interdum tellus mi, at tincidunt enim. Praesent
sit amet turpis urna, sit amet sollicitudin velit. Pellentesque nisl
nunc, commodo quis gravida viverra, cursus in risus. Sed non justo
mauris, at mollis magna. Praesent sit amet fermentum purus.
</div>
L'exemple jquery-7-1.html affichera, si vous l'exécutez en local (c'est-à-dire depuis un répertoire de votre ordinateur, donc avec un protocole file:), le résultat de la figure 7-1.
Alors qu'en modifiant l'appel de la méthode et en précisant le type de valeur reçue :
$(function(){
$.get('ajax/ajax.html', function(data){
alert(data);
}, 'html');
});
on obtient le résultat montré à la figure 7-2.
Il devient donc possible d'intégrer la réponse reçue dans le document (l'exemple donné spécifie des paramètres pour montrer la façon dont ils sont ajoutés à l'URL) :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<title>AJAX</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
$(function(){
$.get('ajax/ajax.html', 'param=valeur', function(data){
$('#dynamique').html(data);
}, 'html');
});
</script>
</head>
<body>
<h1>Ajout de contenu via AJAX</h1>
<div id="dynamique">
</div>
</body>
</html>
Cet exemple affichera le résultat de la figure 7-3.
Vous noterez que pour cet exemple, nous avons utilisé un serveur local, c'est-à-dire installé sur l'ordinateur, pour pouvoir faire une requête serveur (http://localhost/). Il existe de nombreux serveurs locaux disponibles permettant d'installer la suite logicielle Apache, PHP et MySQL (par exemple WAMP ou EasyPHP pour Windows) vous permettant ainsi de disposer sur votre ordinateur d'un serveur pour effectuer vos tests avec le langage PHP installé et préconfiguré, ainsi que le SGBD MySQL.
Notez aussi que la console de Firebug permet d'obtenir toutes les informations liées à la requête.
Néanmoins, les méthodes get() et post() ne sont que des raccourcis d'une méthode plus globale et plus paramétrable de jQuery, la méthode ajax().
Dans le cas de l'exemple précédent, dont le but est de remplir un élément avec le contenu renvoyé par la requête, nous aurions pu utiliser un autre raccourci AJAX destiné à ce genre de manipulation, la méthode load(). Cette méthode appelle une URL est remplace le contenu de la collection jQuery en cours par la réponse reçue du serveur.
$(selecteur).load( url, [parametres,] [callback(reponse, textStatus, jqXHR)]);
Comme le montre la syntaxe, cette méthode s'applique à une collection d'objets jQuery, quant à la fonction de rappel, elle est utilisée pour effectuer des traitement complémentaires au remplacement du contenu des éléments. Notre exemple adapté à cette méthode deviendra donc :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<title>AJAX</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
$(function(){
$('#dynamique').load('ajax/ajax.html');
});
</script>
</head>
<body>
<h1>Ajout de contenu via AJAX</h1>
<div id="dynamique">toto
</div>
</body>
</html>
La méthode ajax() peut être appelée de deux façons distinctes :
- $.ajax(url, options);
- $.ajax(options);
Une syntaxe a priori très simple : une URL à appeler et un objet spécifiant les options particulières à appliquer à la requête. Il est d'ailleurs possible de préciser l'URL à appeler directement dans les options.
À titre d'exemple, la requête précédente s'écrirait, avec la méthode ajax() :
$.ajax({
url: 'ajax/ajax.html',
method: 'get',
data: {param: 'valeur'},
dataType: 'html',
success: function(data){
$('#dynamique').html(data);
}
});
Il existe un grand nombre de paramètres utilisables dans l'objet options, certains couramment utiles (en particulier ceux présents ci-dessus), d'autres réservés à des utilisations bien spécifiques d'AJAX. Dans l'exemple précédent, il n'y a pas d'intérêt particulier à utiliser la méthode ajax(), il est donc préférable de passer par get(). Dans ce cas, l'essentiel des options utilisables par la méthode ajax() ne sont pas définies et ce sont donc leurs valeurs par défaut qui sont prises en compte. Ceci dit, il est possible de redéfinir les valeurs par défaut de chaque paramètre avec la méthode ajaxSetup().
Le tableau 7-1 récapitule les réglages possibles de la méthode ajax(), avec si besoin leur valeur par défaut, qui peut donc être modifiée avec la méthode ajaxSetup(). Certains paramètres, essentiellement destinés à des utilisations d'AJAX de niveau très élevé, ne seront pas détaillés au-delà du strict nécessaire.
Tableau 7-1 : Paramètres de la méthode ajax()
Paramètre | Valeur par défaut | Description |
accepts | Dépend de dataType | Spécifie le paramètre header de la requête indiquant le type de contenu accepté pour la réponse |
async | true | Force la requête à être synchrone ou non. N'a d'utilité que pour forcer le mode synchrone |
beforeSend(jqXHR, settings) | Sans objet | Méthode appelée avant d'envoyer la requête, à laquelle sont passés en paramètres l'objet AJAX |
cache | true, sauf pour les dataType script et jsonp | Booléen indiquant s'il faut utiliser ou non le cache du navigateur pour les pages déjà appelées |
complete(jqXHR, textStatus) | Sans objet | Fonction (ou tableau de fonctions) de rappel appelée(s) lorsque la requête est terminée (sans considération de réussite ou d'échec). Cette fonction est appelée après celles liées à la réussite ou l'échec de la requête |
contents | Sans objet | Objet de paires chaîne/expression régulière indiquant comment doit être traitée la réponse reçue (exemple : {'xml' : /xml/}) |
contentType | 'application/x-www-form-urlencoded' | En-tête HTTP envoyée au serveur. La valeur par défaut, importante pour les requêtes de type POST est normalement suffisante |
context | L'objet options de la requête en cours | Permet de spécifier une valeur spécifique pour la valeur $(this) des fonctions de rappel (si cette valeur doit être modifiée, elle contiendra logiquement un élément du DOM |
converters | {« * text »: window.String, « text html »: true, « text json »: jQuery.parseJSON, « text xml »: jQuery.parseXML} | Objet de paires dataType / fonction retournant la façon de traiter ce dataType |
data | Sans objet | Paramètres à envoyer au serveur, sous forme de chaîne ou d'objet |
datatype | Tente de deviner | Indique le type de données attendues du serveur. Les valeurs possibles sont xml, html (les balises script rencontrées seront évaluées), script (autorise les requêtes hors domaine), json, jsonp (autorise les requêtes hors domaine) ou text |
error(jqXHR, textStatus, erreur) | Sans objet | Fonction de rappel (ou tableau de fonctions) appelée si la requête échoue. Les paramètres passés sont l'objet AJAX de jQuery, la version textuelle du type d'erreur (null, error, abort, timeout ouparseerror) et l'erreur HTTP renvoyée |
global | true | Détermine si l'on doit utiliser ou non les événements globaux de l'objet jQuery AJAX |
headers | {} | Objet précisant les headers HTTP à envoyer avec la requête |
ifModified | false | Permet de forcer une requête à être considérée comme échouée si la réponse n'a pas changé depuis la précédente requête (se base sur la valeur Last-Modified du header de la réponse |
isLocal | Dépend du protocole de la page en cours | Permet de forcer l'environnement courant comme étant local (le plus souvent, correspond à une page lancée depuis l'explorateur de fichiers en protocole file:) |
jsonp | callback | Pour une requête de type jsonp (voir plus loin), modifie le nom du paramètre passé dans la requête dont la valeur correspond à la fonction à lancer à la réception de la réponse |
jsonpCallback | aléatoire | Détermine le nom de la fonction de rappel appelée |
mimeType | Sans objet | Valeur à attribuer au type mime de la réponse |
password | Sans objet | Mot de passe à envoyer au serveur pour appeler une page nécessitant une authentification HTTP |
processData | true | Détermine si les paramètres passés sous forme de tableau doivent être convertis en chaîne avant l'envoi |
scriptCharset | Sans objet | Pour les requêtes de type GET et utilisant un dataType script ou jsonp, permet de modifier l'encodage des caractères de la réponse |
statusCode | {} | Objet de paires statut HTTP/ fonction de rappel indiquant la fonction à appeler si la réponse renvoie le status correspondant |
success(reponse, textStatus, jqXHR) | Sans objet | Fonction (ou tableau de fonctions) à appeler si la requête est considérée réussie |
timeout | Jet | Détermine un délai au-delà duquel la requête sera stoppée |
traditionnal | false | Force jQuery à sérialiser l'objet de paramètres sans récursivité (si ce paramètre vaut true et que l'un des paramètres contient un objet, alors la valeur associée sera[object Object] et non la sérialisation de cet objet) |
type | GET | Méthode de la requête (notez que GET et POST sont les plus fréquemment utilisées, mais d'autres peuvent être utilisées, sans garantie de compatibilité des navigateurs pour certaines méthodes) |
url | Sans objet | URL à laquelle envoyer la requête |
username | Sans objet | Nom d'utilisateur à envoyer au serveur pour appeler une page nécessitant une authentification HTTP |
xhr | ActiveXObject si nécessaire, sinon XMLHttpRequest | Fonction de création de l'objet AJAX, devant retourner l'objet à utiliser pour la requête |
xhrFields | Sans objet | Objet définissant les propriétés supplémentaires de l'objet xhr (par exemple withCredential pour l'utilisation de requêtes interdomaines de type CORS) |
8-3. Les requêtes interdomaines▲
Historiquement, les requêtes AJAX sont limitées par la politique de même origine de JavaScript (Same Origin Policy). Pour des raisons de sécurité, cette limitation empêche JavaScript d'accéder à des ressources provenant d'un domaine différent. Mais l'essor d'AJAX a rapidement soulevé la problématique d'échanges justifiés entre domaines. Pour cela, plusieurs techniques sont possibles.
La plus simple et répandue d'entre elles consiste à faire la requête sur son propre serveur qui lui se chargera d'aller récupérer les données distantes. D'autre part, des réglages au niveau du serveur permettent d'effectuer des requêtes appelées « partage de ressources entre domaines » (Cross Origin Resource Sharing ou CORS). Cependant, cette technique nécessite des réglages du serveur pour accepter ce type de demandes et n'est pas encore disponible sur tous les navigateurs (en particulier, Opera n'implémente pas cette fonctionnalité et Internet Explorer la reconnaît seulement à partir de la version 8 avec un objet qui lui est propre XDomainRequest). Une autre technique - limitée aux ressources de type script (JavaScript ou JSON) - utilise la possibilité pour un script d'appeler son contenu quel que soit le domaine par son attribut src. Il est donc possible de créer une balise HTML <script>, de définir son attribut src hors du domaine en cours, puis, une fois le script évalué (et donc compilé en mémoire), supprimer la balise pour éviter de surcharger le DOM. C'est le mécanisme utilisé par jQuery pour les requêtes dont le dataType est script.
Un mécanisme similaire permettrait la récupération de données de type JSON depuis n'importe quel domaine. Le problème est qu'une réponse JSON n'est supposée retourner qu'un objet, donc l'ajout d'une balise <script> entraînerait juste la création d'un objet anonyme dont il serait du coup impossible de récupérer le contenu puisque n'étant associé à aucune variable. Une technique, appelée JSONP (JSON with Padding ou JSON englobé), a donc vu le jour. Elle permet de contourner ce problème en précisant un paramètre supplémentaire à la page appelée (pour jQuery, le paramètre vaut par défaut callback) dont la valeur correspond au nom de la fonction à appeler au retour de la requête. Le serveur, de son côté, devra englober le résultat renvoyé dans une syntaxe d'appel de la fonction avec comme argument l'objet JSON attendu.
Par exemple, pour l'appel de la page qui suit :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<title>AJAX</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
$(function(){
$.ajax('http://dmouronval.developpez.com/jsonp.txt', {
dataType: 'jsonp',
jsonpCallback: 'callback'
});
});
function callback(donnees){ $('#dynamique').
append('<ul><li>'+donnees.toto+'</li><li>'+donnees.test+'</li>');
}
</script>
</head>
<body>
<h1>Ajout de contenu via AJAX</h1>
<div id="dynamique">
</div>
</body>
</html>
Il faudra retourner un résultat du type :
callback({toto: 'tata', test: 5})
Ainsi, la balise script générée par jQuery contiendra bien l'appel à la fonction callback ; le résultat à l'exécution est illustré à la figure 7-4.
Notez que le résultat est récupéré par le biais d'une balise <script>, la requête n'est donc pas accessible dans Firebug comme une requête AJAX classique. En revanche, l'onglet Réseau permet de voir que le script a bien été récupéré sur un serveur distant. D'autre part, ne cherchez pas la balise <script> dans l'onglet HTML : une fois le script récupéré et compilé par le navigateur, la balise devient inutile et est retirée du DOM.
Plus généralement, pour récupérer des données de type JSON, vous pourrez utiliser le raccourci AJAX getJSON() dont la syntaxe est :
$.getJSON( url[, parametres][, callback(donnees, textStatus, jqXHR)]);
Les paramètres sont désormais habituels.
Si l'URL contient un paramètre permettant de déterminer qu'il s'agit d'une fonction de rappel (typiquement callback= ?) alors la requête sera considérée de type jsonp.
8-4. Sérialiser des données à envoyer▲
Les données à envoyer au serveur via AJAX sont souvent issues d'un formulaire HTML ou d'un tableau ou objet de données JavaScript. Grâce à jQuery, vous disposez de différentes méthodes permettant de transformer automatiquement ces données en chaînes de requêtes.
La méthode param() prend en argument un objet et le transforme en chaîne de caractères :
$.param(objet);
Ainsi, le code suivant :
var tab = [1,2,3],
obj = {a: 1, b: 2, c: 3};
$('#dynamique').append($.param(obj));
affichera la chaîne :
a=1&b=2&c=3
Le paramètre employé dans cet exemple est relativement simple, il s'agit d'un objet avec un seul niveau de valeurs. Mais vous aurez peut-être besoin d'utiliser des objets plus complexes avec plusieurs niveaux d'imbrication. Dans ce cas, il est possible, en PHP, d'utiliser une astuce de la syntaxe de création de tableaux pour pouvoir récupérer plusieurs paramètres ayant le même nom dans une variable de type array(). Par exemple, en PHP, les instructions :
tab[] = 1;
tab[] = 2;
tab[] = 3;
permettront de créer un tableau de trois éléments.
De façon similaire, si un paramètre reçu via $_GET ou $_POST utilise cette syntaxe, cela créera un tableau pour le nom donné. Dans le cas des objets JavaScript imbriqués, jQuery va donc se servir de cette astuce pour former la chaîne de requête. Ainsi, le code précédent utilisé avec l'objet :
var obj = {
a: 1,
b: {
b1: 'b1',
b2: 'b2',
b3: 'b3'
},
c: 3
};
affichera la chaîne :
a=1&b[b1]=b1&b[b2]=b2&b[b3]=b3&c=3
Cela peut ne pas sembler très lisible. En fait, jQuery échappe automatiquement certains caractères susceptibles d'être problématiques, notamment les crochets. Si on utilise la méthode JavaScript decodeURI-Component() sur le résultat récupéré, on obtient :
a=1&b[b1]=b1&b[b2]=b2&b[b3]=b3&c=3
qui correspond exactement au résultat attendu.
Un second argument booléen peut être passé à la méthode param(), si vous utilisez ce paramètre, alors la sérialisation du tableau ne se fera que sur un niveau d'imbrication, dans ce cas, l'exemple précédent deviendra :
$('#dynamique').append($.param(obj, true));
Il affichera, dans sa version utilisant decodeURIComponent() :
a=1&b=[object+Object]&c=3
La propriété b devient donc [object Object] et n'est pas sérialisée. Notez au passage que dans une URL, le caractère « + » correspond à un espace.
De façon similaire, la méthode serialize() permet de transformer les valeurs de champs de formulaire en chaîne de requête. Cette méthode s'applique à une collection jQuery représentant des éléments de formulaire (ou les formulaires eux-mêmes). Cette méthode prend en compte tous les types d'élément de formulaire qui possèdent un attribut name (à l'exception des input de type submit). De façon similaire, la méthode serializeArray() permet de sérialiser des éléments de formulaires en un tableau d'objets contenant comme propriétés les noms des champs et leurs valeurs.
8-5. Les événements AJAX▲
Nous avons déjà vu certains des événements AJAX qu'il est possible de traiter avec jQuery, par exemple success ou error. Jusqu'à présent, nous avons vu ces gestionnaires comme paramètres des options de la requête ou comme fonctions de rappel pour les raccourcis. Il est aussi possible de les utiliser comme des méthodes de l'objet jqXHR et d'autres événements sont disponibles de façon globale.
Le tableau 7-2 récapitule l'ensemble des événements AJAX offerts par jQuery.
Tableau 7-2 : événements Ajax
$(selecteur).ajaxComplete() | Lancé lorsqu'une requête AJAX est terminée. La fonction de rappel prend en paramètres l'objet event, l'objet XMLHttpRequest (dont vous pouvez utiliser les propriétés responseText ou responseXML) et l'objet de paramètres de la requête |
$(selecteur).ajaxError() | Lancé lorsqu'une requête renvoie une erreur. La fonction de rappel prend en paramètres l'objet event, l'objet jqXHR, l'objet de paramètres de la requête et l'erreur retournée |
$.ajaxPrefilter() | Lancé avant chaque requête AJAX afin de modifier les options de la requête. La fonction de rappel prend en paramètres l'objet d'options à utiliser pour la requête, les paramètres par défaut de l'objet jqXHR (qu'il est donc possible de modifier pour affecter les futures requêtes) et l'objet jqXHR. Il est aussi possible de passer en premier paramètre à cet événement une chaîne contenant les dataType (séparés par des espaces) pour lesquels la fonction doit être lancée |
$(selecteur).ajaxSend() | Lancé juste avant l'envoi de la requête. La fonction de rappel prend en paramètres l'objet event, l'objet jqXHR et les options de la requête |
$(selecteur).ajaxSend() | Lorsqu'une requête est sur le point d'être lancée, jQuery vérifie si d'autres sont déjà en cours, si ce n'est pas le cas, l'événement est lancé. La fonction de rappel ne prend pas de paramètres |
$(selecteur).ajaxStop() | Lorsqu'une requête se termine, jQuery vérifie si d'autres sont en cours, si ce n'est pas le cas, l'événement est lancé. La fonction de rappel ne prend pas de paramètres |
$(selecteur).ajaxSuccess() | Lancé lorsqu'une requête se termine avec succès. La fonction de rappel prend en paramètres l'objet event, l'objet XMLHttpRequest et les paramètres de la requête |
8-6. L'objet Deferred()▲
L'objet Deferred(), apparu avec la version 1.5, n'est pas spécifique aux requêtes AJAX, mais y trouve une utilité particulière.
Il s'agit d'un objet global de jQuery qui permet de créer des enchaînements à effectuer ultérieurement en fonction de certains paramètres. Dans le cas particulier des requêtes AJAX, il peut être utilisé pour prévoir les actions à effectuer si la requête réussi ou si elle échoue. Créer un objet Deferred() est très simple :
var dfr = $.Deferred();
var dfr = new $.Deferred();
L'utilisation du mot-clé new est optionnelle.
Une fois l'objet créé, il est possible de lui affecter des fonctions de rappel en cas de réussite ou d'échec.
La méthode done() permet d'affecter une ou plusieurs fonctions de rappel ou un tableau de fonctions en cas de réussite, la méthode fail() affecte ce même types de fonctions en cas d'échec :
dfr.done(function(){}, function(){}).fail([function(){}, fonction2]);
Ainsi, lorsque jQuery aura déterminé si l'objet doit traiter le succès ou l'échec, il lancera les fonctions associées.
Il est possible de lancer des fonctions dans tous les cas de figure, pour cela, on utilise la méthode always() :
dfr.always(function(){});
Enfin, il est possible de grouper les définitions des méthodes done() et fail() à l'aide de la méthode then() :
dfr.then(doneCallbacks, failCallbacks);
Attention, les deux paramètres doivent être présents (éventuellement, ils peuvent prendre la valeur null).
Toutes ces méthodes renvoyant l'objet Deferred() peuvent donc être chaînées.
Lors de l'évolution de votre script, vous pouvez désormais à tout instant décider d'accepter ou de rejeter l'objet Deferred() en fonction de certains critères. La méthode resolve() permet de lancer toutes les fonctions liées au succès (c'est-à-dire celles associées aux méthodes always() et done() , inversement, reject() lancera toutes les fonctions associées à l'échec (méthodes always() et fail() . Vous pouvez passer à ces méthodes des paramètres supplémentaires pour les fonctions appelées :
dfr.resolve(valeurs);
dfr.reject(valeurs);
Notez aussi (et surtout) que jQuery ne se charge pas de savoir si un objet Deferred() doit être accepté ou refusé, c'est à vous de le faire dans votre code. Ainsi, une requête AJAX échouée n'aura aucun impact sur l'objet Deferred() puisque jQuery n'a aucun moyen de savoir qu'il est associé à telle ou telle requête (ou du reste à n'importe quel autre événement).
Alternativement aux méthodes resolve() et reject(), vous pouvez préciser un contexte (valeur de $(this) dans les fonctions de rappel) à l'aide des méthodes resolveWith() et rejectWith().
Enfin, vous pouvez connaître à tout moment l'état de l'objet Deferred() à l'aide des méthodes isRejected() et isResolved().
Lorsque les méthodes resolve() ou reject() ont été appelées, l'objet change d'état et il n'est plus possible de lui faire changer son état. En revanche, il reste possible d'ajouter des fonctions de rappels correspondant à chaque état, si elles correspondent à l'état actuel de l'objet, alors les fonctions nouvellement affectées seront lancées immédiatement.
Pour conclure sur l'objet Deferred(), notez qu'il s'agit de méthodes avancées destinées à des codes complexes, comme la création de plugins, dans la plupart des cas, vous ne devriez pas en avoir l'utilité.
La version 1.7 de jQuery a apporté des nouveautés quant aux méthodes Ajax. Reportez-vous au chapitre 9.