// 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();
}