04/03/2004 - Un amico mi ha suggerito un'utile modifica: far si che lo script capisca quando l'elemento cercato è stato trovato ed in tal caso faccia qualcosa come aprire una finestra, inviare il form etc.
La modifica da fare è abbastanza semplice, abbiamo già un ciclo che in ogni caso scorre tutto l'array fino alla fine, anche se durante il ciclo trova un elemento coerente con il testo digitato.
Quel che ci serve è identificare
l'ultimo elemento dell'array coerente con il testo digitato da confrontare con quello identificato volta per volta che aggiorna la select. Durante il ciclo infatti la funzione, così come riportata nella scheda, aggiorna la SELECT appena trova il
primo elemento coerente e: se al prossimo carattere digitato non c'è corrispondenza non fa più nulla (eliminando la selezione), altrimenti continua sempre a selezionare l'elemento se i caratteri continuano a coincidere con quelli dell'opzione.
È evidente che ci basta a questo punto avere disponibile l'ultimo indice coerente di tutta la lista e confrontarlo con quello trovato per la digitazione, e di questo si occupano le righe in rosso nel sorgente modificato:
function Cerca()
{
with (document.modulo)
{
ThisFind=-1;
StringToSearch=input.value;
StringToSearchLength=StringToSearch.length;
var LastOption=-1
if (StringToSearchLength>0)
for (i=0;i<stati.options.length;i++)
{
ThisFind==-1&&stati.options[i].text.toLowerCase().substring(0,StringToSearchLength)==StringToSearch?ThisFind=i:null;
LastOption=stati.options[i].text.toLowerCase().substring(0,StringToSearchLength)==StringToSearch?i:LastOption;
}
else
ThisFind=0;
stati.selectedIndex=ThisFind;
if (LastOption==ThisFind && LastOption!=-1)
alert(stati.options[ThisFind].text);
}
}
La prima riga è la variabile aggiunta:
LastOption (che inizia con -1 quindi con nessun elemento della lista) e che ci servirà per il confronto.
Nel ciclo la porzione di testi della option, lunga quanto la stringa digitata, viene confrontata con la stringa digitata durante
tutto lo scorrere dell'array, ed ogni volta che viene trovata una corrispondenza. Notiamo che se non c'è alcuna corrispondenza (opzione non presente o errore di digitazione che è lo stesso per quel che ne sa lo script) il
valore di LastOption rimane -1, mentre la SELECT rimane scrollata fino all'ultimo elemento coerente ma con nessuna selezione (è stato di fatti selezionato -1 cioè il valore iniziale per ThisFind).
Terminato il ciclo lo script continua come prima a selezionare l'opzione trovata, ma un ulteriore controllo ci consente di vedere se abbiamo finito di scorrere.
Dato che in LastOption c'è l'indice dell'ultimo elemento possibile per i caratteri digitati, questo valore sarà sempre diverso da
ThisFind a meno che un ulteriore carattere non consenta a ThisFind di trovare un'opzione e LastOption con corrisponda all'ultima opzione possibile. Un ulteriore verifica che LastOption sia diversa da -1 (e che quindi corrisponda ad un elemento della lista) e la verifica è fatta: se le condizioni sono entrambe modificate abbiamo finito di scorrere la lista.
Nell'esempio ho usato un alert() per mostrare il nome dello stato trovato, voi ovviamente lo cambierete con ciò che vi serve.
Vediamo ora come avviene il controllo, tenendo presenti le opzioni che cominciano per "mal" e che sono:
125 = Malawi
126 = Malaysia
127 = Maldives
128 = Mali
129 = Malta.
quando digitiamo "mal" ThisFind vale 125, LastOption vale 129. Aggiungendo una "a", con "mala" avremo ThisFind=125 e LastOption=126 (la scelta è ancora possibile fra Malawi e Malaysia)
A questo punto se digitiamo "w", con "malaw" troviamo Malawi" ed avremo ThisFind=125=LastOption.
La ricerca è finita.
Se invece avessimo digitato un carattere che non corrisponde a niente, ad esempio la "x", per la stringa "malax" avremmo avuto sia per ThisFine che per LastOption i valore iniziale "-1", quindi nessun elemento selezionato nella lista.
E l'ultimo controllo non scatta grazie al controllo su LastOption.
Lo script modificato secongo questo aggiornamento non è quello disponibile sul link "Prova" (che resta lo script originale), ma è comunque contenuto nel file zip da scaricare ed è "index_modificato.html".
In questo script vediamo come scorrere "al volo" una lunga lista di OPTION in una SELECT list in accordo con il testo scritto in un box durante la digitazione.
Quello che facciamo è simile al funzionamento dell'HELP di Windows che scorre i suoi argomenti durante la richiesta.
La parte HTML è semplicissima: un campo testo in cui andremo a digitare le prime lettere della parola cercata e naturalmente la SELECT contentente le nostre opzioni. Nell'esempio è un elenco delle nazioni del mondo che qualche tempo fa ho... rubato a non so più quale motore di ricerca :-))
<HTML>
<HEAD>
<SCRIPT>
<!--
function Cerca()
{
with (document.modulo)
{
ThisFind=-1;
StringToSearch=input.value;
StringToSearchLength=StringToSearch.length;
if (StringToSearchLength>0)
for (i=0;i<stati.options.length;i++)
ThisFind==-1&&stati.options[i].text.toLowerCase().substring(0,StringToSearchLength)==StringToSearch?ThisFind=i:null;
else
ThisFind=0;
stati.selectedIndex=ThisFind;
}
}
//-->
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#ffffff">
<FORM NAME="modulo">
<INPUT TYPE="text" NAME="input" VALUE="Scrivi..." CLASS="" onKeyUp="Cerca()" onFocus="this.select()"> <BR>
<SELECT NAME="stati">
<OPTION>Albania</OPTION>
<OPTION>Algeria</OPTION>
<OPTION>American Samoa</OPTION>
<OPTION>Andorra</OPTION>
. . .
. . .
<OPTION>Yugoslavia</OPTION>
<OPTION>Zaire</OPTION>
<OPTION>Zambia</OPTION>
<OPTION>Zimbabwe</OPTION>
</SELECT>
</FORM>
</BODY>
</HTML>
Il campo testo contiene due event-handler:
onFocus="this.select()" serve ad evidenziare il testo contenuto nel box quando al click dell'utente, in questo modo l'inserimento precedente sarà cancellato automaticamente alla prossima digitazione; l'altro event-handler invece intercetta l'inserimento del carattere ed attiva la funzione che esegue la ricerca nell'elenco delle OPTION.
L'obiettivo dello script è inserire in una variabile (
ThisFind) l'indice della SELECT corrispondente alla
prima occorrenza utile trovata nell'elenco evidenziando le opzioni man mano che i primi caratteri vengono digitati, così se nel TEXTBOX inseriamo la lettera "i" lo script scorrerà la lista fino ad "Iceland", poi digitando la "n" vedremo "India", con la "d" vedremo ancora India ed infine digitando la "o" otterremo "Indonesia" che supponiamo sia l'obiettivo della nostra ricerca.
Togliendo invece i caratteri con il BACKSPACE la ricerca funzionerà comunque e la selezione nella lista retrocederà fino a tornare all'inizio ("Albania") quando il box sarà vuoto.
La prima operazione dello script è porre la variabile principale uguale a
-1. Questo valore, che non ha senso per la lista in quanto quest'ultima è assimilabile ad un array, ci serve solo come controllo; nel prosieguo dello script infatti assumerà il valore corrispondente all'elemento della lista, oppure il valore zero.
Subito dopo alle due variabili
StringToSearch e
StringToSearchLength vengono assegnati gli analoghi valori, questo semplicemente per velocizzare lo script ed evitare che la lettura del textbox e la ricerca della lunghezza sia effettuata ad ogni passo del ciclo di ricerca.
A questo punto viene verificato che la lunghezza della stringa da cercare sia maggiore di zero. Se la stringa è vuota vuol dire che non è stato inserito nulla nel texbox dunque la variabile ThisFind è posta a zero così da puntare al primo elemento della lista.
Invece se è stata scritta almeno una lettera nel textbox la ricerca ha inizio ed un ciclo
for (..) {...} inizia a scorrere tutta la lista.
Per ogni passo del ciclo viene controllato che la variabile ThisFind sia ancora uguale a -1 e che le prime lettere del testo corrispondente alla i-esima posizione della lista sia uguale al testo inserito nel textbox. Se queste due condizioni sono verificate, allora ThisFind viene settata al valore di
i, altrimenti lo script non fa nulla.
Questo ci consente di memorizzare la
la prima occorrenza del testo cercato all'interno della lista nella variabile di controllo; poi anche se il ciclo continua comunque fino alla fine della lista, eventuali elementi che dovessero corrispondere al testo cercato saranno ignorati (perché la condizione
ThisFind==-1 non sarebbe più verificata) e non ci ritroveremo come elemento selezionato l'ultimo di quelli trovati invece del primo.
La funzione termina il suo lavoro andando a selezionare, nella SELECT la OPTION di indice ThisFind che così verrà visualizzata dal browser.