// Déclaration de l'objet requete. var req; // Fonction appelée quand des données sont reçues // (en fait, à tous les stades du traitement de la requête). function remplissage() { // Si la requête vient de se terminer if (req.readyState== 4) { // si le résultat est un succès if (req.status == 200) { // On remplit le select avec le retour de la requête. // (qui ici a la forme <option>valeur1</;option><option>valeur2</;option>... document.getElementById('mot').innerHTML= req.responseText; } } } function autoCompleteManuel() { // On récupère la valeur actuelle du champ mot. var debutMot= document.getElementById('debutMot').value; if (debutMot.length > 2) { // On crée l'objet requête (pour firefox) req= new XMLHttpRequest(); // Quand un événement se produit (début, fin de requête...), on appelle remplissage: req.onreadystatechange= remplissage; try { // Appel de la requête, avec le mot en argument req.open("GET","dico/complete?debut="+ encodeURIComponent(debutMot),true); req.send(null); // C'est fini } catch (e) { alert(e); } } }La servlet appelée lors de la complétion est la suivante :
public class DictionnaireCompletion extends HttpServlet { private TreeSet<String> dictionnaire= new TreeSet<String>(); public void init() throws ServletException { try { InputStream in = getClass().getResourceAsStream("dictionnaire.txt"); BufferedReader reader= new BufferedReader(new InputStreamReader(in, "ISO-8859-1")); String l; while ((l= reader.readLine())!= null) { dictionnaire.add(l); } } catch (IOException e) { throw new ServletException(e); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String debut= request.getParameter("debut"); response.setContentType("text/plain"); response.setCharacterEncoding("UTF-8"); PrintWriter w = response.getWriter(); System.out.println("recut "+ debut); for (String m: dictionnaire.tailSet(debut)) { // Si le mot commence bien par début, l'ajouter. // Sinon: terminer la boucle. if (m.startsWith(debut)) { w.print("<option>"); w.print(protectHTML(m)); w.print("</option>"); } else break; } } /** * Protège tous les caractères spéciaux pour HTML. * @param m * @return */ private String protectHTML(String m) { StringBuffer buff= new StringBuffer(); for (int i=0; i< m.length(); i++) { switch (m.charAt(i)) { case '<': buff.append("<"); break; case '>': buff.append(">"); break; case '&': buff.append("&"); break; default: buff.append(m.charAt(i)); break; } } return buff.toString(); } /** * @param debut * @return */ private ArrayList<String> getMots(String debut) { ArrayList<String< mots= new ArrayList>String>(); return mots; }
<script type="text/javascript" src="js/dojo/dojo.js"></script> <script type="text/javascript"> // Chargement de l'objet ComboBox : dojo.require("dojo.widget.ComboBox"); </script> <select dojoType="ComboBox" mode="remote" dataUrl="dico/completeDojo?debut=%{searchString}" autoComplete="true" name="dico2" ></select>et la partie intéressante de la servlet :
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String debut= request.getParameter("debut"); if (debut== null) debut= ""; response.setContentType("text/plain"); response.setCharacterEncoding("UTF-8"); PrintWriter w = response.getWriter(); w.print("["); boolean virgule= false; int taille= 0; for (String m: dictionnaire.tailSet(debut)) { // On s'arrête si on a plus de 50 réponses. if (++taille > 50) break; // Si le mot commence bien par début, l'ajouter. // Sinon: terminer la boucle. if (m.startsWith(debut)) { if (virgule) w.print(",\n"); w.print("[\""); w.print(protectHTML(m)); w.print("\",\""); w.print(protectHTML(m)); w.print("\"]"); } else break; virgule= true; } w.print("]"); w.close(); }
La documentation de bind se trouve à l'adresse http://manual.dojotoolkit.org/io.html
<form> <input id="debutMotDojo" name="debutMotDojo" onkeyup="autoCompleteManuelDojo()"> <select id='motDojo' name="motDojo" style="width: 16em"></select> </form> <script type="text/javascript"> dojo.require("dojo.io.*"); function autoCompleteManuelDojo() { var debutMot= document.getElementById('debutMotDojo').value; if (debutMot.length > 2) { dojo.io.bind({ url : "dico/complete?debut="+ encodeURIComponent(debutMot), load : chargerCompletionDojo, mimetype: "text/html" } ); } } // type : load ou error // data : texte de la réponse // evt : événement DOM function chargerCompletionDojo(type,data,evt) { document.getElementById('motDojo').innerHTML= data; } </script>
<!-- Javascript for linking autocompletion to actual page elements --> <script type="text/javascript"> <script type="text/javascript" src="<c:url value='/js/prototype.js'/>"></script> function updateRelationObjects() { var url= '<c:url value="/appli/subRelation"/>'+ "?relationType=" +$F('relationName'); // Mets à jour le champ d'id "relationObjects" à partir des données provenant de l'URL. // Le contenu renvoyé par l'URL remplace le contenu du select. new Ajax.Updater('relationObjects', url, {asynchronous:true}); } </script> <select name='signSearch.relationName' id="relationName" onchange="javascript:updateRelationObjects()"> <option value="NONE"><none></option> <option value="POSTURE">posture</option> <option value="ACTION">action</option> </select> <select name='signSearch.relationObject' id='relationObjects'> <option value="NONE"><none></option> </select>
Différence avec les autres : le protocole est POST.
Pour mettre en place l'autocomplétion, il faut définir un champ, et une division (div) qui recevra la liste des complétions possibles :
<form> <!-- Le champ --> <input type="text" id="scAutocomplete" name="scParametre"></inp <!-- La liste des données pour la complétion --> <div id="scChoix" class="autocomplete"></div> </form>Il convient ensuite, dans le fichier de style CSS, de placer les informations utiles pour cacher et montrer la liste de complétion.
/* Pour la completion Ajax */ div.autocomplete { position:absolute; width:250px; background-color:white; border:1px solid #888; margin:0px; padding:0px; } div.autocomplete ul { list-style-type:none; margin:0px; padding:0px; } div.autocomplete ul li.selected { background-color: #ffb;} div.autocomplete ul li { list-style-type:none; display:block; margin:0; padding:2px; height:32px; cursor:pointer; }Enfin, on appelle une méthode de Scriptaculous pour mettre en place l'auto complétion:
<script type="text/javascript"> // premier argument : l'ID du champ à compléter // second : l'ID de la division qui reçoit les données d'autocomplétion // options : // paramName: le nom du paramètre passé à la servlet (récupéré par getParameter()) // minChars : la complétion n'a lieu qu'a partir de deux caractères. new Ajax.Autocompleter("scAutocomplete", "scChoix", "dico/completeSC", {'paramName' : 'debut', minChars: 2}); </script>La servlet doit renvoyer (à partir d'une requête POST) une liste HTML :
<ul> <li>valeur1</li> <li>valeur2</li> <li>valeur3</li> </ul>Elle a donc pour nous la forme :
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Note : scriptaculous utilise a priori UTF-8. Cette déclaration permet // à notre servlet de décoder correctement les caractères accentués. request.setCharacterEncoding("UTF-8"); String debut= request.getParameter("debut"); response.setContentType("text/plain"); response.setCharacterEncoding("UTF-8"); PrintWriter w = response.getWriter(); System.out.println("recut "+ debut); w.println("<ul>"); for (String m: dictionnaire.tailSet(debut)) { // Si le mot commence bien par début, l'ajouter. // Sinon: terminer la boucle. if (m.startsWith(debut)) { w.print("<li>"); w.print(protectHTML(m)); w.print("</li>"); } else break; } w.println("</ul>"); w.close(); }