Autocompletamento dei campi input text con javascript e ajax
Wed, 03/26/2008 - 16:01 — bugbuster
Questa guida è basata sul tutorial che ho preso da qui e il cui autore è Nicholas C. Zakas.
L'effetto finale sarà questo:
NB: Con Internet Explorer 7 l'esempio qui riportato non funziona correttamente per problemi legati a incompatibilità con lo StyleSheet del tema Garland di Drupal. Motivo in più per usare Firefox. In ogni caso il codice è funzionante, quello che da problemi è il foglio di stile.
Per ottenere tutto questo sarà necessario utilizzare javascript (programmazione ad oggetti) e scrivere qualche riga nel foglio di stile della pagina.
Se volete utilizzare il codice per implementare questo oggetto velocemente potete andare direttamente al metodo veloce, se invece volete vedere come viene realizzato l'autocompletamento, potete partire da qui:
Metodo Lento
Come potete notare, quando scrivete qualcosa nel campo input (per es 'b'), la parola viene automaticamente completata con il primo suggerimento trovato ('baldassarre'), selezionando la parte aggiunta ('aldassarre'):
Comincieremo creando il codice necessario per fare questa operazione.
Il programma sarà costituito da due entità, la classe principale che chiameremo AutoSuggestControl e una classe di utilità che fornirà i suggerimenti ad AutoSuggestControl e che chiameremo StateSuggestions.
Intanto creiamo la classe AutoSuggestControl. Per inizializzarla dovremo passargli la textbox che avrà l'autocompletamento, e un istanza della classe StateSuggestions:
Oltre al riferimento alla textbox e all'istanza del suggeritore, ci sarà utile un indice (cur) per gestire la posizione del focus nella lista dropdown, un riferimento chiamato layer in cui salveremo il riferimento al <div> per creare la lista dropdown ed infine c'è la chiamata al metodo init() che inizializzerà l'oggetto.
Selezione del testo
Adesso creiamo il metodo della classe AutoSuggestControl per evidenziare la porzione della parola suggerita. Il metodo avrà come parametri la posizione del carattere di partenza e il numero dei caratteri da evidenziare nella textbox:
AutoSuggestControl.prototype.selectRange = function (iStart, iLength) {
if (this.textbox.createTextRange) { // metodo per Explorer
var oRange = this.textbox.createTextRange();
oRange.moveStart("character", iStart);
oRange.moveEnd("character", iLength - this.textbox.value.length);
oRange.select();
} else if (this.textbox.setSelectionRange) { // metodo per Mozilla
this.textbox.setSelectionRange(iStart, iLength);
}
this.textbox.focus();
};
Autocompletamento
Adesso che siamo in grado di selezionare una parte di parola, creaiamo il metodo che scrive nella textbox la parte rimanente della parola suggerita.
Il metodo avrà come parametro la parola suggerita.
AutoSuggestControl.prototype.typeAhead = function (sSuggestion) {
if (this.textbox.createTextRange || this.textbox.setSelectionRange) {
var iLen = this.textbox.value.length;
this.textbox.value = sSuggestion;
this.selectRange(iLen, sSuggestion.length);
}
};
nell'ordine questo metodo
salva la lunghezza della parola scritta dall'utente
scrive nella textbox la parola suggerita
il metodo autosuggest()
Questo metodo riceverà un array di stringhe contenente tutte le parole suggerite e un booleano. Il parametro booleano serve per sapere se mostrare o no la lista dropdown.
Controlla che l'array non sia vuoto, se è vuoto nasconde la lista dropdown, altrimenti chiama la funzione typeAhead per scrivere nella text box la prima parola conenuta nell'array.
La gestione degli eventi
Dovremo gestire i tasti premuti sulla tastiera, controllare quale tasto è stato premuto e agire di conseguenza. Se per esempio viene premuto SHIFT non dobbiamo fare nulla, e questo vale per tutta una serie di tasti, qua sotto potete vedere i tasti che non gestiremo con il relativo codice:
Key
Code
Key
Code
Backspace
8
Print Screen
44
Tab
9
Delete
46
Enter
13
F1
112
Shift
16
F2
113
Ctrl
17
F3
114
Alt
18
F4
115
Pause/Break
19
F5
116
Caps Lock
20
F6
117
Esc
27
F7
118
Page Up
33
F8
119
Page Down
34
F9
120
End
35
F10
121
Home
36
F11
122
Left Arrow
37
F12
123
Up Arrow
38
Right Arrow
39
Down Arrow
40
Quindi i tasti qui sopra non li gestiremo, mentre gestiremo i tasti con codice 8 e 46 (Backspace e Delete) mostrando la lista dropdown ma senza modificare la parola, chiameremo quindi requestSuggestions con il secondo parametro a false, che, ricordo, serve proprio a evitare che venga eseguito il metodo typeAhead. Per tutti gli altri tasti chiameremo requestSuggestions lasciando anche che venga eseguito typeAhead:
Il fornitore dei suggerimenti
Possiamo ora scrivere la classe che suggerirà le parole, ovvero SuggestionProvider. Essa avrà un metodo, requestSuggestion() che fornirà ad AutoSuggestControl una lista di parole. Inoltre in questa classe salveremo la lista delle parole tra cui cercare i suggerimenti.
Ma la parte interessante è il metodo requestSuggestions:
come parametri accetterà il reference al controllore (per richiamare la sua funzione autosuggest) più il booleano per eseguire o meno il typeAhead:
StateSuggestions.prototype.requestSuggestions =
function (oAutoSuggestControl /*:AutoSuggestControl*/, bTypeAhead) {
var aSuggestions = [];
var sTextboxValue = oAutoSuggestControl.textbox.value;
if (sTextboxValue.length > 0){
// trasformo tutto in minuscolo
var sTextboxValueLC = sTextboxValue.toLowerCase();
//cerco le parole che combaciano
for (var i=0; i < this.states.length; i++) {
// trasformo anche i suggerimenti in minuscolo
var sStateLC = this.states[i].toLowerCase();
if (sStateLC.indexOf(sTextboxValueLC) == 0) {
aSuggestions.push(sTextboxValue + this.states[i].substring(sTextboxValue.length));
}
}
}
//fornisco i suggerimenti al controllore AutoSuggestControl
oAutoSuggestControl.autosuggest(aSuggestions, bTypeAhead);
};
La lista dropDown
La lista che compare sotto la nostra text box, non è altro che un div con uno stile adatto e posto esattamente sotto la text box. Vedremo che per calcolare la posizione esatta non sarà così semplice.
Questo, intanto, è lo stile del conenitore dei suggerimenti, il box:
In questa parte della guida andrò più veloce poichè la maggiorparte sono metodi che interagiscono con il DOM del documento.
Ora vediamo di implementare intanto il metodo per nascondere la lista dropDown, a questo scopo modificheremo lo stile del membro "layer" della classe AutoSuggestControl, che corrisponderà al DIV del box contenente i suggerimenti.
AutoSuggestControl.prototype.hideSuggestions = function () {
this.layer.style.visibility = "hidden";
};
Vediamo ora come evidenziare uno degli elementi della lista:
AutoSuggestControl.prototype.highlightSuggestion =
function (oSuggestionNode) {
for (var i=0; i < this.layer.childNodes.length; i++) {
var oNode = this.layer.childNodes[i];
if (oNode == oSuggestionNode) {
oNode.className = "current"
} else if (oNode.className == "current") {
oNode.className = "";
}
}
};
Ora è arrivato il momento di creare la lista dropdown con il DIV. Il metodo createDropDown, oltre ad inserire i DIV nel documento, registrerò i gestori degli eventi per la lista.
Dobbiamo ora posizionare la lista nel punto esatto, sotto il text box, per farlo sembrare una vera dropdown menu.
Per farlo dobbiamo trovare le coordinate del punto in basso a sinistra del box, e calcolarne la larghezza.
Scriviamo due metodi che ci aiutano nell' arduo compito:
AutoSuggestControl.prototype.getLeft = function () {
var oNode = this.textbox;
var iLeft = 0;
while(oNode.tagName != "BODY") {
iLeft += oNode.offsetLeft;
oNode = oNode.offsetParent;
}
return iLeft;
};
AutoSuggestControl.prototype.getTop = function () {
var oNode = this.textbox;
var iTop = 0;
while(oNode.tagName != "BODY") {
iTop += oNode.offsetTop;
oNode = oNode.offsetParent;
}
return iTop;
};
I due metodi risalgono di nodo in nodo, dalla textbox al nodo "BODY", prendendo l'offset sinistro (o alto) rispetto al nodo superiore, e sommandoli ogni volta. Alla fine del ciclo avremo in pixel la distanza della textbox dal bordo sinistro e alto della pagina.
Usiamo i due metodi appena visti per far apparire la lista nel punto esatto creando questo metodo che accetta una lista di suggerimenti e li mostra nel layer, in pratica crea un div dentro a layer per ogni suggerimento e ci scrive dentro la parola:
AutoSuggestControl.prototype.showSuggestions = function (aSuggestions) {
var oDiv = null;
this.layer.innerHTML = "";
for (var i=0; i < aSuggestions.length; i++) {
oDiv = document.createElement("div");
oDiv.appendChild(document.createTextNode(aSuggestions[i]));
this.layer.appendChild(oDiv);
}
this.layer.style.left = this.getLeft() + "px";
this.layer.style.top = (this.getTop()+this.textbox.offsetHeight) + "px";
this.layer.style.visibility = "visible";
};
Possiamo pensare ora alla gestione degli eventi della tastiera, come l'uso delle freccie per muoversi in alto e in basso nella lista dropdown.
A questo scopo creiamo i metodi che ci permettono di navigare nella lista:
AutoSuggestControl.prototype.nextSuggestion = function () {
var cSuggestionNodes = this.layer.childNodes;
if (cSuggestionNodes.length > 0 && this.cur < cSuggestionNodes.length-1) {
var oNode = cSuggestionNodes[++this.cur];
this.highlightSuggestion(oNode);
this.textbox.value = oNode.firstChild.nodeValue;
}
};
AutoSuggestControl.prototype.previousSuggestion = function () {
var cSuggestionNodes = this.layer.childNodes;
if (cSuggestionNodes.length > 0 && this.cur > 0) {
var oNode = cSuggestionNodes[--this.cur];
this.highlightSuggestion(oNode);
this.textbox.value = oNode.firstChild.nodeValue;
}
};
Per gestire i tasti su e giu dobbiamo creare un metodo che gestirà questi due eventi e richiamerà i metodi appena scritti per navigare nella lista
// funzione che verrà bindata per gestire gli eventi key arrow
AutoSuggestControl.prototype.handleKeyDown = function (oEvent) {
switch(oEvent.keyCode) {
case 38: //up arrow
this.previousSuggestion();
break;
case 40: //down arrow
this.nextSuggestion();
break;
case 13: //enter
this.hideSuggestions();
break;
}
};
Abbiamo finalmente finito di scrivere i metodi funzionali alla nostra applicazione, ma dobbiamo ancora inizializzarli, questo ci permetterà di legare gli eventi della tastiera con i metodi di gestione che abbiamo scritto. Ecco quindi il metodo init:
AutoSuggestControl.prototype.init = function () {
var oThis = this;
//quando si verifica un evento onkeyup, esegui questa funzione
//passandogli l'oggetto oEvent che è una cosa propria del DOM:
this.textbox.onkeyup = function (oEvent) {
// può essere che con Explorer non ci sia l'oggett oEvent,
// al suo posto viene utilizzato l'oggetto event della classe window:
if (!oEvent) {
oEvent = window.event;
}
// assegno a handleKeyUp la gestione dell'evento onkeyUp
oThis.handleKeyUp(oEvent);
};
// per gestire le freccie e l'enter per il menu a tendina
this.textbox.onkeydown = function (oEvent) {
if (!oEvent) {
oEvent = window.event;
}
oThis.handleKeyDown(oEvent);
};
// per gestire la perdita del focus, dovrò nascondere la tendina
this.textbox.onblur = function () {
oThis.hideSuggestions();
};
this.createDropDown();
};
Si conclude così la guida per la creazione di un text box con l'autocompletamento e con l'autosuggeritore.
Per provarlo da voi leggete ancora il metodo veloce qui sotto, dove trovate anche il file javascript con tutto il codice necessario.
Metodo Veloce
Prendete il codice javascript da qui che dovrete includere nella vostra pagina, per esempio scrivendo nell'header qualcosa come
<script type="text/javascript" src="/scripts/autocompletamento.js"></script>
Aggiungete ancora questo script nell'header della pagina che avrà la text box:
<script type="text/javascript">
window.onload = function () {
var oTextbox = new AutoSuggestControl(document.getElementById("txt1"), new StateSuggestions());
}
</script>
Inserite nel vostro foglio di stile CSS queste righe:
a questo punto dovete creare un campo input text con id=txt1: <input id="txt1" type="text"/>
Per modificare le parole suggerite aprite il file javascript, troverete un array con tutte le parole possibili, vi basterà modificare quell'array scrivendo le parole che volete che vi vengano suggerite.
Se trovate degli errori nel codice o qualche malfunzionamento non esitate a scrivermi alla mail che trovate nella sezione contatti.
Comments
Post new comment