jeudi 12 novembre 2009
Dans l'ergonomie d'une interface, c'est toujours gagnant d'avoir un champ autocomplete. J'en utilise depuis des années dans mes projets et étonnamment, j'ai toujours utilisé exclusivement le composant de la librairie Yahoo! User Interface (mieux connu sous le nom YUI). Ce qui me fait penser que je n'ai pas encore essayé celui de la version YUI 3 donc pour le moment, j'expliquerai comment intégrer celui de la version 2.
- Téléchargez YUI 2 - Full Developer Kit
- Décompressez l'archive zip
- Placez le répertoire yui à l'intérieur de votre projet (pour faire simple)
- Les librairies qu'on aura besoin se trouvent dans yui/build
Pour utiliser le composant autocomplete, il faut placer en entête (entre les balises HEAD) une référence vers chacune de ces librairies JavaScript et il ne faut pas oublier d'inclure la feuille de style CSS.
<link type="text/css" rel="stylesheet" href="/yui/build/autocomplete/assets/skins/sam/autocomplete.css">2. Créer le markup HTML pour YUI
<script type="text/javascript" src="/yui/build/yahoo/yahoo-min.js"></script>
<script type="text/javascript" src="/yui/build/event/event-min.js"></script>
<script type="text/javascript" src="/yui/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript" src="/yui/build/datasource/datasource-min.js"></script>
<script type="text/javascript" src="/yui/build/get/get-min.js"></script>
<script type="text/javascript" src="/yui/build/connection/connection-min.js"></script>
<script type="text/javascript" src="/yui/build/animation/animation-min.js"></script>
<script type="text/javascript" src="/yui/build/json/json-min.js"></script>
<script type="text/javascript" src="/yui/build/autocomplete/autocomplete-min.js"></script>
YUI a besoin de savoir dans quelle portion du DOM il doit chercher le markup pour appliquer les changements. Pour cela, il faut placer la classe "yui-skin-sam" sur un conteneur. La documentation suggère de le mettre comme attribut de la balise BODY, mais on peut aussi bien le mettre sur un DIV :
<div class="yui-skin-sam">Ce snippet de code devrait faire parti d'un formulaire quelconque dans lequel le champ d'auto-complétion serait intégré. Le champ qui possède l'ID "ac_field" est celui où l'utilisateur entrera un mot clé au clavier. Au fur et à mesure que les touches seront enfoncées, les propositions de résultats qui correspondent seront affichées dans le conteneur "ac_container" que YUI prend en charge automatiquement. Enfin, le champ caché "selected_id" servira à récupérer la clé unique qui correspond à l'enregistrement sélectionné dans la liste déroulante de l'autocomplete.
<div id="container">
<input type="text" id="ac_field" />
<div id="ac_container"></div>
<input type="hidden" id="selected_id" name="selected_id" value="" />
</div>
</div>
3. Initialisation JavaScript
Maintenant, on est prêt à initialiser le composant et à programmer la façon dont il réagira. Pour faciliter le tout, je vais utiliser un peu de jQuery alors il ne faut pas oublier d'attacher une librairie supplémentaire en entête.
D'abord, il faut définir une source de données. Dans mon cas, j'utilise un XMLHttpRequest (XHR) pour obtenir la liste à partir d'un fichier dynamique PHP qui recevra un paramètre $_GET['q'] pour chercher dans une base de données et qui filtrera les résultats (clause LIKE).
Ensuite, j'indique que le résultat que retournera ma source de données XHR utilisera la notation JSON. Je pourrais aussi bien choisir parmi plusieurs autres types dont le XML mais j'ai une nette préférence pour la structure JavaScript Object Notation.
Tout ce que votre fichier PHP doit retourner, c'est du JSON, peu importe la façon qu'il est généré (statique, par la base de données, json_encode(), etc). Je vous recommande de vérifier la syntaxe résultante avec ce validateur JSON.
Ce que je retourne respecte le schéma suivant (tel qu'indiqué plus loin) :
{Pour la suite, j'ai commenté à l'intérieur du code pour que ça soit plus facile à suivre :
"Results" :
[
{"id":100,"name":"Firefox"},
{"id":200,"name":"Internet Explorer"},
{"id":300,"name":"Safari"}
]
}
$(document).ready( initAutoComplete );4. Personnalisation
function initAutoComplete(){
// Source
var oDS = new YAHOO.util.XHRDataSource("/ajax/list.php");
// le paramètre envoyé à list.php sera nommé "q"
oDS.scriptQueryParam = "q";
oDS.responseType = YAHOO.util.XHRDataSource.TYPE_JSON;
oDS.responseSchema = {
resultsList: "Results",
fields:["name", "id"]
};
// Contrôle autocomplete
var oAC = new YAHOO.widget.AutoComplete("ac_field", "ac_container", oDS);
// on affiche l'autocomplete dès qu'il y a au moins 2 caractères
oAC.minQueryLength = 2;
// on veut absolument qu'on choisisse un élément de la liste
oAC.forceSelection = true;
// ce qui se passe lorsqu'on sélectionne un item
// on copie la clé unique (ID) dans le champ caché
oAC.itemSelectEvent.subscribe(
function(type, args) {
var oData = args[2];
$("#selected_id").val(oData[1].toString());
}
);
}
Dans mon exemple, j'ai écrit le strict minimum pour que ça fonctionne. Il sera peut-être nécessaire d'ajouter un peu de CSS pour faire une mise en page correcte. À mesure que vous explorerez ce composant, vous verrez qu'il y a une tonne d'options possibles et que la documentation est tellement vaste qu'on a parfois de la difficulté à savoir où commencer. C'est d'ailleurs la raison pour laquelle j'ai décidé d'en faire un tutoriel le plus simplifié possible. J'espère qu'il vous sera utile.
P.s. comme les lignes de code sont longues et que la largeur de page est trop étroite, ça provoque des sauts de lignes indésirables. Je vous recommande de cliquer sur "View plain" dans le coin supérieur gauche de chaque bloc de code, ça sera plus lisible et plus facile à copier.
Ce qui m'embête ce sont les 10 requetes http pour un module qui n'aurait besoin que de 2 js (jQuery et le fichier d'auto-complétion). Une requete est envoyée à chaque frappe de l'utilisateur, le script php la traite et retourne la liste des suggestions en string, puis il suffit de mettre à jour le bloc dans lequel elle se trouve. Je ne suis pas très au fait des contraintes de normes mais en tout cas, c'est optimisé.
(téléchargez http://developer.yahoo.com/yslow/ et testez votre blog)
Effectivement, ça peut sembler beaucoup pour l'exemple, mais dans un environnement professionnel, mieux vaut les condenser en un seul fichier js, le compresser (avec YUI Compressor) et de gzipper le tout (après la première requête, tout est en cache).
Sinon, YUI réagit exactement comme tu le décris avec Ajax. Si tu veux moins de requêtes selon la frappe, tu peux ajuster minQueryLength à la hausse.
C'est possible qu'il y ait des optimisations à faire si ta base de données est gigantesque (caching, index, etc) mais sinon, c'est très performant.