Coté client
La page HTML
Coté client, nous allons commencer par mettre en place une page HTML, la plus simple possible. Elle sera complétée par deux balises script qui respectivement la liera à notre script javascript et initialisera ce script.
<!DOCTYPE html PUBLIC « -//W3C//DTD XHTML 1.0 Strict//EN » « http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd »>
<html xmlns= »http://www.w3.org/1999/xhtml » xml:lang= »fr » lang= »fr »> <head>
<title>Test d’autocompletion</title>
</head>
<body>
<form name= »form-test » id= »form-test »
action= »javascript:alert(‘soumission de ‘ +
document.getElementById(‘champ-texte’).value) »
style= »margin-left: 50px; margin-top:20px »>
<input type= »text » name= »champ-texte » id= »champ-texte » size= »20″ /> <input type= »submit » id= »bouton-submit »>
</form>
</body>
</html>
Le body de la page ne changera pas de tout l’article. Nous nous contenterons d’y connecter les scripts nécessaires. Ainsi, pour un utilisateur n’ayant pas activé Javascript (un peu près 10% des internautes), le formulaire apparaîtra comme un formulaire normal, sans aide à la complétion.
L’objet xmlHttpRequest
Le premier script que nous allons mettre en place est celui permettant de créer un objet xmlHttpRequest (ou XHR pour les intimes). Cet objet va nous permettre d’effectuer des requêtes vers notre serveur, sans avoir à recharger entièrement la page. Pour plus d’informations sur l’objet et ces méthodes, consultezl’article de siddh sur le sujet.
Pour notre part, nous allons utiliser la méthode suivante permettant de créer un nouvel objet, compatible entre tous les navigateurs actuels supportant l’objet xmlHttpRequest:
// retourne un objet xmlHttpRequest.
// méthode compatible entre tous les navigateurs (IE/Firefox/Opera) function getXMLHTTP(){
var xhr=null;
if(window.XMLHttpRequest) // Firefox et autres xhr = new XMLHttpRequest();
else if(window.ActiveXObject){ // Internet Explorer try {
xhr = new ActiveXObject(« Msxml2.XMLHTTP »); } catch (e) {
try {
xhr = new ActiveXObject(« Microsoft.XMLHTTP »);
} catch (e1) { xhr = null;
}
}
}
else { // XMLHttpRequest non supporté par le navigateur
alert(« Votre navigateur ne supporte pas les objets XMLHTTPRequest… »);
}
return xhr;
}
Mise en place des constantes
Pour fonctionner et se mettre en place, notre script va avoir besoin de 3 constantes:
• _documentForm : le formulaire contenant notre champ texte
• _inputField : le champ texte lui-même
• _submitButton : le bouton submit de notre formulaire
La fonction d’initialisation de notre script prendra donc comme argument une référence sur ces trois éléments.
var _documentForm=null; // le formulaire contenant notre champ texte var _inputField=null; // le champ texte lui-même
var _submitButton=null; // le bouton submit de notre formulaire
function initAutoComplete(form,field,submit){
_documentForm=form;
_inputField=field;
_submitButton=submit;
_inputField.autocomplete= »off »;
}
On désactive l’aide à la saisie des navigateurs en mettant l’attribut autocomplete de notre champ texte falseà.
Cette fonction sera liée à l’évènement window.onload de notre page. Elle sera enrichie au fur et à mesure par des besoins supplémentaires d’initialisation que nous rencontrerons tout au long de cet article.
<script type= »text/javascript »>
window.onload = function(){initAutoComplete(document.getElementById(‘form-test’), document.getElementById(‘champ-texte’),document.getElementById(’bouton-submit’))};
</script>
Vérifier les changements du champ texte
Pour mettre en place notre mécanisme d’auto-complétion, nous devons être capable de détecter les changements dans le champ texte. Cela ne peut pas se faire avec le listener onchange du champ texte, car celui-ci n’est déclenché qu’au moment ou le champ perds son focus.
Détecter les changements à chaque touche appuyée peut se révéler dangeureux, par exemple dans le cas des copier/coller ou autre qui peuvent soit passer inaperçu, soit saturer notre pauvre moteur Ajax de demandes.
Dans ce domaine encore, nous allons prendre exemple sur Google Suggest et mettre en place une méthode qui vérifiera périodiquement les changements survenus dans le champs texte, et exécutera une requête vers le serveur si nécessaire.
var _oldInputFieldValue= » »; // valeur précédente du champ texte var _currentInputFieldValue= » »; // valeur actuelle du champ texte var _resultCache=new Object(); // mécanisme de cache des requêtes
// tourne en permanence pour suggérer suite à un changement du champ texte function mainLoop(){
_currentInputFieldValue = _inputField.value;
if(_oldInputFieldValue!=_currentInputFieldValue){ var valeur=escapeURI(_currentInputFieldValue);
var suggestions=_resultCache[_currentInputFieldValue]; if(suggestions){ // la réponse était encore dans le cache
metsEnPlace(valeur,suggestions)
}else{
callSuggestions(valeur) // appel distant
}
_inputField.focus()
}
_oldInputFieldValue=_currentInputFieldValue;
setTimeout(« mainLoop() »,200); // la fonction se redéclenchera dans 200 ms return true
}
Cette méthode sera appelée la première fois dans la fonction d’initialisation de notre script. Elle contrôle à chacun de ces passages l’état du champ texte et exécute une requête vers le serveur si nécessaire.
_resultCache est un objet qui nous permettra de constituer un cache des requêtes, pour éviter de les renvoyer systématiquement (très utile, par exemple en cas de backspace).
La fonction metsEnPlace mettra en place dans la page nos suggestions, et la fonction callSuggestions exécuteras une requête, via l’objet xmlHttpRequest, vers le serveur de données.
La méthode ci-dessus parait un peu complexe pour le résultat obtenu, mais elle va subir des changements au fur et à mesure des étapes de cet article. En particulier _currentInputFieldValue ne sera plus initialisée à l’intérieur de la méthode mais dans les autres méthodes de gestion des évènements.
escapeURI est une méthode toute simple, permettant d’échapper les caractères spéciaux du champ texte avant d’envoyer la requête au serveur. Cette méthode se base sur des méthodes JavaScript natives des navigateurs.
// échappe les caractères spéciaux function escapeURI(La){
if(encodeURIComponent) { return encodeURIComponent(La);
}
if(escape) { return escape(La)
}
}
L’appel au serveur – méthode callSuggestions
Cette méthode va contacter notre serveur pour récupérer au plus 10 suggestions pour le texte entré dans notre champ texte.
var _xmlHttp = null; //l’objet xmlHttpRequest utilisé pour contacter le serveur
var _adresseRecherche = « options.php » //l’adresse à interroger pour trouver les suggestions
function callSuggestions(valeur){
if(_xmlHttp&&_xmlHttp.readyState!=0){
_xmlHttp.abort()
}
_xmlHttp=getXMLHTTP();
if(_xmlHttp){
//appel à l’url distante
_xmlHttp.open(« GET »,_adresseRecherche+ »?debut= »+valeur,true); _xmlHttp.onreadystatechange=function() {
if(_xmlHttp.readyState==4&&_xmlHttp.responseXML) {
var liste = traiteXmlSuggestions(_xmlHttp.responseXML)
cacheResults(valeur,liste)
metsEnPlace(valeur,liste)
}
};
// envoi de la requête _xmlHttp.send(null)
}
}
Cette fonction utilise l’objet xmlHttpRequest en mode asynchrone (le premier A de Ajax), comme le montre le troisième paramètre de la méthode open() qui vaut true.
Lorsque la réponse du serveur reviendra, le listener lié à l’évènement readyStateChange sera déclenché. Concrètement, cela signifie que quand la requête sera terminée (readyState==4), la fonction traiteXmlSuggestions transformera notre document XML en une liste de suggestions (Array de string) et la méthode metsEnPlace sera déclenchée, avec comme argument le texte dans le champ utilisateur et les possibilités de complétion. La méthode cacheResults permet de garder les demandes précédentes faites au serveur.
// Mécanisme de caching des réponses function cacheResults(debut,suggestions){
_resultCache[debut]=suggestions
}
Transformation du document XML – méthode traiteXmlSuggestions
Cette méthode va gérer la transformation de la réponse du serveur au format XML en une liste de suggestions, sous forme de tableau de chaînes de caractères.
// Transformation XML en tableau function traiteXmlSuggestions(xmlDoc) {
var options = xmlDoc.getElementsByTagName(‘option’); var optionsListe = new Array();
for (var i=0; i < options.length; ++i) { optionsListe.push(options[i].firstChild.data);
}
return optionsListe;
}
La mise en place des suggestions – méthode metsEnPlace
La dernière fonction que nous avons à mettre en oeuvre dans cette phase est la fonction metsEnPlace, qui va mettre les suggestions en place. Ces suggestions sont mises en place dans une liste de suggestions (liste à puce UL pour le moment), créée au moment de l’initialisation de notre script d’auto-complétion.
var _completeListe=null; // la liste contenant les suggestions
// création d’une liste pour les suggestions
// méthode appelée à l’initialisation function creeAutocompletionListe(){
_completeListe=document.createElement(« UL »); _completeListe.id= »completeListe »; document.body.appendChild(_completeListe);
}
function metsEnPlace(valeur, liste) {
while(_completeListe.childNodes.length>0) {
_completeListe.removeChild(_completeListe.childNodes[0]);
}
for (var i=0; i < liste.length; ++i) {
var nouveauElmt = document.createElement(« LI »)
nouveauElmt.innerHTML = liste[i]
_completeListe.appendChild(nouveauElmt)
}
}
Dans un premier temps, la présentation sera inexistante, l’interactivité également. Ce sera l’objet des deux prochaines parties que d’améliorer la présentation de la chose et de mettre toute l’interactivité en place.
Nous en avons maintenant terminé avec la première étape de cet article. Notre page HTML est maintenant capable de dialoguer avec notre serveur (qui est ici résumé à une simple page PHP), et d’intégrer dans la page le retour de ce serveur.
Vous pouvez tester le résultat.
Cette étape représente le coeur d’une page utilisant Ajax. Mais ce n’est pas l’étape la plus compliquée. En effet, il nous reste maintenant à présenter un peu plus convivialement notre liste de suggestions et à lier les évènements survenants sur-le-champ texte à notre liste de suggestions, pour reconstruire un comportement de type liste déroulante. Ces deux étapes sont plus « ingrates » que la première étape: Il n’est plus question d’Ajax dans ces deux étapes, simplement de JavaScript habituel, avec tous les problèmes de compatibilité entre navigateurs.
Ces deux étapes sont les objets des deux sections suivantes.
Introduction
1 – Etape 1 – Faire communiquer le client et le serveur
1-A – Coté serveur
1-B – Coté client
1-B-1 – La page HTML
1-B-2 – L’objet xmlHttpRequest
1-B-3 – Mise en place des constantes
1-B-4 – Vérifier les changements du champ texte
1-B-5 – L’appel au serveur – méthode callSuggestions
1-B-6 – Transformation du document XML – méthode traiteXmlSuggestions
1-B-7 – La mise en place des suggestions – méthode metsEnPlace
2 – Etape 2 – Présentation
2-A – Initialisation des règles de style
2-B – Calcul dynamique du positionnement
2-C – Initialisation de la div de suggestions
2-D – Mise en place de la liste de suggestions
3 – Partie 3 – Gestion des évènements
3-A – Gestion des touches
3-A-1 – Sur le document
3-A-2 – Sur le champ texte
3-B – Gestion de la suggestion en surbrillance
3-B-1 – choix d’une suggestion en surbrillance
3-B-2 – méthodes de gestion de la surbrillance
3-C – Gestion de la souris
3-D – Détails finaux