Un premier appel Ajax avec Prototype.js : Ajax.Request
Par Pascal MARTIN le samedi 20 janvier 2007, 18:30 - Développement Web - Lien permanent
prototype.js est une bibliothèque de fonctions JavaScript écrite par Sam Stephenson ; elle est utilisée comme base par le framework Ruby on Rails, ainsi que par la bibliothèque script.aculo.us.
Prototype.js inclut tellement de fonctionnalités qu'il n'est pas possible de toutes les présenter en un article.
Je me limiterai ici uniquement à une partie des fonctionnalités Ajax : celles constituant la base de toute requête, ainsi que celles facilitant la tâche au développeur par rapport à une utilisation directe de l'objet XMLHttpRequest.
D'autres articles suivront, allant plus loin que ce à quoi je me limiterai pour celui-ci, ne voulant pas le rendre trop long.
Pour information, une référence prototype.js est disponible en ligne : Référence prototype.js.
Et voici la Documentation de l'API de prototype.js
Je ne peux que vous encourager à les parcourir !
prototype.js
Pour cet article, j'utiliserai la version 1.5.0 de la bibliothèque prototype.js[1].
Pour faciliter les choses, vous pouvez la télécharger ici :
- prototype.js 1.5.0 (69 Ko)
- prototype.js 1.5.0 compressée (53 Ko)
La version "compressée" correspond à la version "standard", qui a été compressée grâce à l'outil JSMin, qui - pour résumer - supprime les espaces blancs inutiles d'un fichier JavaScript.
Elle présentent toutes deux les mêmes fonctionnalités, mais la version "compressée" est de taille moins importante. Elle est donc plus rapide à télécharger pour vos utilisateurs - au prix d'une grosse perte en terme de lisibilité[2].
Quelques méthodes utilitaires
Avant de commencer, je vais introduire quelques fonctions/méthodes fournies par prototype.js, que j'utiliserai dans mes exemples.
(Ces fonctions étant présentes dans la librairie, autant les utiliser ; cela rend notre code plus court, et c'est la bibliothèque qui gère les éventuels problèmes de compatibilité entre navigateurs)
$()
La fonction $() est un alias - raccourci - de la fonction document.getElementById().
Comme la fonction correspondante du DOM, elle retourne l'élément qui a l'identifiant ("id") passé en paramètre.
Par exemple :
$('test').innerHTML = '<p>Hello World !</p>';
est identique à :
document.getElementById('test').innerHTML = '<p>Hello World !</p>';
La fonction $() va tout de même un peu plus loin, puisqu'elle accepte en paramètre une liste d'identifiants d'éléments - auquel cas elle retournera un tableau (Array) contenant les éléments demandés.
Element.show ; Element.hide
Les méthodes Element.show(element) et Element.hide(element) permettent respectivement d'afficher et de masquer un élément.
Les deux lignes suivantes sont équivalentes[3] :
Element.show('chargement');
et
document.getElementById('chargement').style.display = '';
Dans les deux cas, le "display: none" disparaît de la liste de styles de l'élement chargement.
Première requête Ajax avec Prototype.js
Comme lorsque nous avons effectué une requête en utilisant directement l'objet XHR, nous avons besoin de trois composantes :
- Une page cliente : HTML, XHTML, ...a
- Quelques lignes de JavaScript exécutant la requête, et obtenant le résultat.
- Et un programme côté serveur, qui sera appelé par la requête Ajax - par exemple, un script PHP - il s'appellera "test2.php".
Page cliente
La page cliente que j'utiliserai pour nos exemples est des plus simples :
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <title>AJAX : Exemple de client</title> <script type="text/javascript" src="prototype-1.5.0.js"></script> <script type="text/javascript" src="test2.js"></script> </head> <body> <p> <a href="" onclick="gestionClic(); return false;"> Cliquez ici ! </a> </p> <div id="resultat"> </div> </body> </html>
Quelques points :
- Inclusion de prototype.js
- Inclusion du fichier test2.js, dans lequel se trouvera mon code JavaScript
- Un lien qui déclenchera l'exécution d'une fonction de ce code JS
- Et un élément où sera affiché le résultat - notez qu'il a pour identifiant "
resultat"
Ajax.Request
C'est la classe Ajax.Request qui permet, avec prototype.js, de réaliser des requêtes Ajax.
Pour tous mes exemples, je développerai une fonction nommée gestionClic - celle appelée lors d'un clic sur le lien présenté un peu plus haut.
Voici sa première version :
function gestionClic() { var url = './test2.php'; var myAjax = new Ajax.Request( url, { method: 'get', onComplete: gestionReponse }); } // gestionClic()
Une requête Ajax est toujours émise vers une URL ; c'est le premier paramètre attendu par la méthode Ajax.Request().
Le second paramètre permet de définir un grand nombre d'options, définissant des paramètres spécifiques, ou, surtout, quelles méthodes seront appelées lors du cycle de vie de l'objet XMLHttpRequest.
Ici, nous utilisons deux paramètres :
methodpermet de définir quelle méthode HTTP sera employée par la requête. En général, on utilise'GET'ou'POST', la seconde étant la méthode par défaut si aucune n'est spécifiée.onCompletepermet d'indiquer quelle fonction devra être exécutée une fois l'appel Ajax terminé. Typiquement, cette fonction exploitera les données obtenues via la-dite requête.
Ici, une fois la requête terminée, c'est la fonctiongestionReponsequi sera appelée - nous en présenterons une version un peu loin.
PHP côté serveur
Côté serveur, encore une fois, j'utiliserai le PHP.
Le programme développé pour cet exemple est des plus simples : il n'effectue qu'un affichage :
<?php header('Content-Type: text/html; charset: UTF-8'); echo 'Hello World!'; ?>
Obtention et utilisation du résultat
Revenus côté client, il est maintenant temps d'exploiter le retour de notre requête Ajax.
Pour cela, conformément à ce qui a été défini lors de l'appel de Ajax.Request, voici la fonction gestionReponse :
function gestionReponse(xhr) { if (xhr.status == 200) { $('resultat').innerHTML = xhr.responseText; } else { $('resultat').innerHTML = xhr.status; } }
Le (premier[4]) paramètre passé par Ajax.Request à la fonction définie comme déclenchée une fois la requête terminée (événement onComplete) est l'objet XMLHttpRequest utilisé pour effectuer la requête.
Puisque nous avons branché cette fonction sur l'événement onComplete, elle sera appelée lorsque la requête Ajax sera terminée, quel que soit le code statut HTTP renvoyé par le serveur.
Dans le cas où tout s'est bien passé, la propriété status de l'objet XMLHttpRequest reçu en paramètre vaut 200 ("OK") :
Si l'URL appelée correspond à une page existante, accessible, et ne causant pas d'erreur :
var url = './test2.php';
Alors, nous afficherons à l'écran le contenu renvoyé par le serveur - en l'occurence, "Hello World!".
Pour cela, nous utiliserons la propriété responseText de l'objet XHR, en vue d'obtenir les données "affichées" par le programme PHP.
Mais si l'URL appelée correspond à une page inexistante - par exemple :
var url = './test-404.php';
Alors, nous afficherons le code statut HTTP renvoyé par le serveur - ici, puisque la page n'existe pas, ce sera "404".
(Nous pourrions aussi utiliser la propriété statusText, pour afficher le message correspondant - en l'occurence, "Not Found")
Passer des paramètres
Est-il vraiment nécessaire de souligner qu'effectuer une requête Ajax n'est pas très utile si ce qu'elle renvoi ne dépend pas de paramètres que vous lui passez ?
Le passage de paramètre peut se faire en GET ou en POST, comme présenté ci-dessous :
Passer des paramètres en GET
prototype.js accepte deux syntaxes pour le passage de paramètres :
- Sous forme d'une chaîne de caractères :
'param1=valeur1¶m2=valeur2¶m3=valeur3' - Et sous forme d'un tableau associatif :
{param1: 'valeur1', param2: 'valeur2', param3: 'valeur3'}
La seconde méthode est celle qui est recommandée - il faut avouer qu'un tableau associatif est plus lisible, et plus facile à manipuler, qu'une chaîne de caractères.
En GET, les paramètres sont passés comme option, celle-ci étant nommée parameters :
function gestionClic() { var url = './test2.php'; var myAjax = new Ajax.Request( url, { method: 'get', parameters: 'param1=valeur1¶m2=valeur2¶m3=valeur3', onComplete: gestionReponse }); } // gestionClic()
Ou avec la seconde écriture :
function gestionClic() { var url = './test2.php'; var myAjax = new Ajax.Request( url, { method: 'get', parameters: {param1: 'valeur1', param2: 'valeur2', param3: 'valeur3'}, onComplete: gestionReponse }); } // gestionClic()
Dans les deux cas, en ayant comme programme côté serveur ceci :
<?php header('Content-Type: text/html; charset: UTF-8'); echo '<pre>' . print_r($_GET, true) . '</pre>'; ?>
Nous obtiendrons l'affichage suivant - en supposant que la fonction appelée en fin de requête Ajax fait, comme plus haut, un simple affichage écran de ce qui a été renvoyé par le serveur :
> Array > ( > [param1] => valeur1 > [param2] => valeur2 > [param3] => valeur3 > )
Nous voyons bien que les trois paramètres ont été reçus par le serveur, et que l'association entre les noms de paramètres et leurs valeurs a été conservée.
Et passer des paramètres en POST
Normalement, une requête en GET ne devrait pas causer de modification de données... Et les navigateurs conservent parfois les données de requêtes GET en cache - plus fréquemment qu'avec des requêtes POST.
En POST, nous disposons des deux mêmes possibilités qu'en GET pour passer des paramètres... Mais ceux-ci peuvent être passés à Ajax.Request soit via l'option parameters - comme plus haut - soit par l'option postBody.
Note : si la seconde est utilisée, la première est ignorée.
En général, on utilise postBody, pour passer des données en POST :
function gestionClic() { var url = './test2.php'; var myAjax = new Ajax.Request( url, { method: 'post', postBody: 'param1=valeur1¶m2=valeur2¶m3=valeur3', onComplete: gestionReponse }); } // gestionClic()
Avec comme programme serveur le suivant :
<?php header('Content-Type: text/html; charset: UTF-8'); echo '<pre>' . print_r($_POST, true) . '</pre>'; ?>
Nous obtiendrons exactement le même affichage que tout à l'heure, lorsque nous passions nos données en GET.
Attention : le passage de paramètres en utilisant postBody ne peut pas se faire en utilisant un tableau associatif !
L'écriture suivante est incorrecte :
postBody: {param1: 'valeur1', param2: 'valeur2', param3: 'valeur3'}
Avec cette écriture, le serveur ne reçoit aucune donnée !
Une solution pour contourner ce problème est d'utiliser la fonction $H(), qui permet de créer un objet Hash à partir d'un objet en notation litérale, et d'utiliser la méthode toQueryString() de la classe Hash pour convertir cet objet en une chaîne telle qu'acceptée par l'option postBody, de la manière suivante :
postBody: $H({param1: 'valeur1', param2: 'valeur2', param3: 'valeur3'}).toQueryString()
Et là, nous obtenons le fonctionnement attendu.
Aller plus loin
Quelques articles viendront bientôt, qui constitueront une suite logique à celui-ci :
- Utiliser JSON comme format d'échange de données avec prototype.js
- Les gestionnaires d'événements qui peuvent être définis pendant une requête avec Ajax.Request : il y en a de nombreux, qui viennent compléter le
onCompleteque nous avons ici utilisé. - Afficher un message de chargement pendant l'exécution des requêtes Ajax avec prototype.js
Je mettrai cette liste à jour au fur et à mesure que les articles seront en ligne, afin de rajouter les liens correspondant.
N'hésitez pas à vous abonner au flux RSS (voir colonne de droite), pour être informé des nouveaux articles parus sur ce blog !
Mises à jour
- MAJ le vendredi 23 février 2007 : Ajout de liens à la partie Aller plus loin.
Notes
[1] Quand j'ai commencé à rédiger ceci, la version la plus récente de prototype.js était la 1.5.0_rc2 ; mais la 1.5.0 est sortie avant que cet article ne soit terminé
[2] Typiquement, vous pouvez utiliser la version non compressée lorsque vous développez, et la version compressée une fois votre application en production. Cela dit, testez tout de même votre application avec la version compressée avant la mise en production - on n'est jamais trop prudent !
[3] Elles sont équivalentes que ce soit dans l'effet - l'élément est affiché - ou dans le fonctionnement : la première est un raccourci pour la seconde
[4] Nous verrons dans un autre article qu'il peut y en avoir un second, dans le cas où le serveur avait retourné des données au format JSON
Pour être averti lors de la publication de nouvelles entrées, n'hésitez pas à vous abonner au flux RSS ou ATOM des articles de mon blog !
Commentaires
J'ai lu tous les articles de ce blog, ils sont vraiment excellent et m'ont permis de ma lancer dans la pratique de prototype.js.
J'attends avec impatience d'autres articles qui explorent d'autres parties de ce framework javascript
vous mériteriez plus de commenyaires
Bien ayant énormément apprécié
le style global du blog ( symbolique pour les liens externes, langue entre crochets ) la mise en forme de l'article m'a rebuté.
D'autant que sous Firefox et un écran de qualité moyenne ça devient absolument illisible ( les parties "CODE" ).
Dommage
oui je confirme sous mozilla, c'est illisible
ou sinon les articles sont bien
Bah, le problème a du être résolu, car chez moi tout passe nickel et ce sous n'importe quel navigateur.
Puis merci pour cet article, je connaissais et utilise ce framework, mais peu de personnes frenchy en parle (à mon gout) et c'est bien dommage, car prototype c'est excellent... D'ailleurs faudrait p'tete que je m'y mette un de ces quatre à faire un article dessus...
Bonne continuation
++
Merci pour ce commentaire
Le problème de lisibilité a en effet dû être résolu : j'ai changé un peu tout la skin du site, y compris les styles appliqués aux portions de code, il y a quelques semaines.
Vous comptez écrire des articles, en français, à propos de prototype ?
C'est rare... trop rare !
Bon courage !
Effectivement, l'aspect sous Firefox est nickel maintenant.
Merci.
{{Vous comptez écrire des articles, en français, à propos de prototype ?
C'est rare... trop rare !
Bon courage !}}
Re-bonjour,
Et encore bravo pour ce blog sympathique.
Oui, j'aimerais bien mettre en place quelques tutos et comparaisons parlant de prototype. Je pense qu'il y a beaucoup à en dire, mais j'aimerais l'exprimer via mes expériences personnelles... Je vous ferais signe dès que les articles seront là
++
OK %)
Merci beaucoup pour ces explications qui m'ont été bien utiles ! Enfin, j'ai compris comment Ajax fonctionnait. Un grand bravo à vous.
Bonjour, j'ai un petit problème. Comment fait on pour passer dans les parameters, un tableau 2D ???
Merci je galère depuis ce matin sans avoir trouver de solution.
Bonjour,
Si vous réussissez à obtenir un appel qui ressemble à ceci :
Le serveur recevra param2 sous forme d'une liste (tableau une dimension), et param3 sous forme d'une matrice (tableau 2D) :
Par contre, c'est un peu lourd à écrire, et peu dynamique ^^
Pour arriver à quelque chose qui soit générique, je dois avouer que je n'ai pas trouvé de méthode qui fasse ça automatiquement dans prototype.js ; avec un peu de chance, ça doit se faire en écrivant la fonction (éventuellement récursive) qui va bien...
Sinon, il y a aussi la "solution de facilité", qui est d'envoyer votre matrice sérialisée sous forme d'une chaine de caractères au format JSON, et de la désérialiser côté PHP, ce qui donnerait, côté JS :
Et côté serveur :
C'est peut-être brutal, mais tellement plus simple, en même temps...
Encore un tuto bidon qui marche pas..
C'est con il se passe rien quand on appuis sur le bouton =')
Bonjour,
Tutoriel très clair qui fonctionne parfaitement.
J'ai quand même fait une modification pour un problème de compatibilité avec internet explorer : au lieu d'utiliser $('resultat').innerHTML = xhr.responseText; j'utilise la méthode de prototype : $('resultat').replace(xhr.responseText);
Merci
Vincent
Cela fonctionne parfaitement et c'est très simple d'utilisation. Merci et bravo pour ton magic js
Slt,
Super tuto et qui marche très bien! Par contre je ne comprend pas pourquoi lorsque je modifie le fichier .php la modification n'est pas automatique quand je clique sur le lien. il faut actualiser la page d'abord?
merci pour ce tuto ! :D
Pas évident de trouver des ressources en francais sur prototype
Bonjour,
J'ignore si ce sujet est encore suivi, mais je tente ma chance car... petit problème
Tout d'abord, merci à Pascal pour ce tuto !! Rarement vu un tel modèle de clarté et de didactique !!
Mais... voici mon problème:
J'ai quelque peu modifié et adapté le modèle ainsi:
Dans la partie HTML, j'ai remplacé le lien et son clic par une petite liste déroulante avec un onChange:
@@
<select id="listeBranches" size="5" onchange="gestionChange()"> <option value="Français">Français</option> <option value="Français">Français</option> <option value="Langues germaniques">Langues germaniques</option> <option value="Religion">Religion</option> </select>@@
En voyant les 2 lignes que j'ai placées dans la liste, on se doute peut-être de la nature de mon problème: le c cédille n'est pas lu convenablement dans ma page PHP.
Voici ce qu'est devenue la fonction GestionClic:
@@
function gestionChange() { var idBranches = $F('listeBranches'); var url = './page10_maj.php'; var myAjax = new Ajax.Request( url, { method: 'get', parameters: {param1: 'BUL1', param2: idBranches, }, onComplete: gestionReponse }); } // gestionClic()@@
La page PHP à pour but d'interroger une Database suivant le critère sélectionné dans la liste déroulante.
Ca fonctionne parfaitement pour tout, sauf pour le Français !!
Voici le code de la page PHP:
@@
<?php header('Content-Type: text/html; charset: cp1252'); include ($_SERVER["DOCUMENT_ROOT"]."/outils/connexion.php"); $sql="select NOM from profs where ".$_GET[param1]." = '".$_GET[param2]."'"; echo $sql."<br>"; $res=mysql_query($sql); echo "Résultat requete: ".$res; echo "Nbre reponses: ".mysql_num_rows($res); while ($ligne=mysql_fetch_array($res)) { $NOMS[]= $ligne[NOM]; }@@
La requête SQL n'est pas interprétée correctement à cause du c cédille.
A noter que le mot "Résultats" ne s'affiche pas correctement non plus !!
Le problème est donc sans doute dans cette page PHP.
J'ai sans résultat probant tenté de remplacer le charset par iso-8859-1 et par cp1252.
Alors si quelqu'un avait une petite idée de solution, je lui en serais très reconnaissant.
Merci d'avance de toute aide.
Mike