L’elemento select
è uno dei componenti HTML più longevi. Questo elemento è tuttora considerato uno standard, com’era sin nelle prime versioni di HTML. Data l’anzianità del componente, nelle moderne interfacce Web la presenza di una vecchia select
rischia di far apparire sorpassata l’interfaccia stessa. Ciò nonostante l’utilità della select
resta indiscussa: ogni volta che vogliamo far scegliere ad un utente un elemento all’interno di un elenco possiamo utilizzare una select
. Lavorando coi moderni strumenti di sviluppo, come ad esempio jQuery, abbiamo a disposizione valide alternative. JQuery offre moltissimi modi di visualizzare un elenco a scelta multipla: tecniche di questo tipo sono abbondantemente documentate sul Web, per cui risulta superfluo parlarne in questa sede. Preferiamo invece affrontare un argomento poco discusso, ma che si presenta spesso nella pratica: il miglioramento di un’interfaccia preesistente, contenente un elemento del tipo select
. In particolare vedremo come aggiornare un’interfaccia di questo tipo senza stravolgere la struttura HTML.
Passiamo subito alla pratica, considerando un esempio concreto. Supponiamo di avere una form HTML che contenga dei campi di tipo select
. Se la pagina è sviluppata usando le normali strutture HTML e CSS, senza alcun “enhancement” offerto da JavaScript o jQuery, probabilmente avremmo qualcosa del genere
Figura 1 – Form HTML con select ordinarie
La presenza dei campi select
è utile dal punto di vista funzionale ma deludente da quello estetico. Se confrontiamo l’interfaccia con le moderne tendenze notiamo che la presenza delle due select
compromette l’aspetto la pagina, perché renderizzate in modo diverso dagli altri campi. Come primo passo sostituiamo l’HTML della select
con il seguente codice:
1 2 3 4 5 6 7 | <select class='lookup_list'> <option value='1'>Zagreus s.n.c.</option> <option value='2'>Levis s.r.l.</option> <option value='3'>InterNom s.p.a.</option> etc... etc... </select> <input type='textbox' class='lookup_data' value='Levis s.r.l.'/> |
In questo modo abbiamo duplicato l’informazione, che risulta sia nella select
, sia nel successivo campo di input. L’idea è quella di mostrare la select
solamente quando necessario, cioè quando l’utente deve cambiare il valore del campo. In tutti gli altri casi nasconderemo la select
e mostreremo il campo di input, che possiamo renderizzare in modo più armonioso rispetto alla select
. Nelle prossime pagine vediamo qual è il codice jQuery necessario.
Codice jQuery
Codice jQuery
La struttura HTML di pagina precedente è volutamente ridondante. Ciò permette di adattare l’interfaccia alla situazione: avremo un “look & feel” su misura per la visualizzazione, e un altro “look & feel” per la modalità di editing dei dati. In particolare sfrutteremo i nomi delle classi CSS per identificare gli elementi HTML, in modo da manipolarli con jQuery. La prima cosa da fare, quando carichiamo la pagina, è quella di nascondere tutte le select
, cioè
1 | $('.lookup_list').hide() ; |
Dove la classe CSS lookup_list
identifica tutte le select
della form (vedi HTML di pagina precedente). Quando l’utente si posiziona con il mouse sopra il campo che contiene una select
dobbiamo invece nascondere i campi di input e visualizzare la select
in questione. Il codice per gestire questi eventi è abbastanza semplice
1 2 3 4 5 6 7 8 | $('.lookup_data').focus( function() { $(this).hide() ; $(this).prev().show() ; }) ; $('.lookup_list').blur( function() { $(this).hide() ; $(this).next().show() ; }) ; |
Qui sopra sfruttiamo gli event handler standard di jQuery, che intercettano rispettivamente l’evento “acquisizione del focus” e “perdita del focus”. Ricordiamo che l’acquisizione del focus può avvenire in modi diversi: il campo potrebbe acquisire il focus quando l’utente ci clicca sopra col mouse, oppure quando l’utente si sposta avanti o indietro con il tasto TAB.
Esiste quindi un potenziale problema. Se alcuni campi di tipo select
sono collocati l’uno di seguito all’altro (come in figura 1 a pagina precedente) quando l’utente si sposta dal primo campo al successivo succede una cosa un po’ strana: il primo campo perde il focus mentre il secondo lo acquisisce. Questa simultaneità di eventi sulla stessa classe CSS può confondere jQuery, che non sa più quale evento gestire. Per evitare sorprese di questo tipo aggiungiamo un codice di controllo
1 2 3 4 | $('input:not(.lookup_data)').focus( function() { $('.lookup_list').hide() ; $('.lookup_data').show() ; }) ; |
Il codice qui sopra risolve ogni problema. Tutte le volte che il focus torna su un qualsiasi campo che non sia associato ad una select
diciamo al browser di ripristinare la situazione iniziale, cioè nascondiamo le select
e visualizziamo i campi di tipo normale.
Sincronizzazione
Sincronizzazione
Il codice di pagina precedente è completo dal punto di vista di gestione dell’interfaccia. Tutto dovrebbe funzionare come previsto: quando l’utente si sposta su un campo che prevede una select
jQuery si occupa di far apparire la select
stessa. Non appena l’utente lascia tale campo la select
scompare, facendo apparire al suo posto il campo normale. Tutto questo riguarda però solo l’interfaccia, ovvero manca il codice che si occupa di sincronizzare il valore della select
con quello mostrato dal campo ordinario. Questo codice non è sempre necessario, ma dipende da quello che dobbiamo fare con la form HTML. Se prevediamo l’invio della form attraverso un metodo standard del tipo HTTP POST, potremmo aver bisogno di valorizzare l’opzione scelta dall’utente. Per garantire la sincronizzazione tra i due campi accoppiati (select
e input
) possiamo usare un codice come questo
1 2 3 4 5 | $('.lookup_list').change(function() { var option = "option[value='" + $(this).val() + "']" ; var value = $(this).find(option).text() ; $(this).next().val(value) ; }) ; |
Il codice viene invocato tutte le volte che l’utente cambia il valore della select
corrente (evento change). Vediamo un esempio: se la select
contenesse dieci opzioni possibili e l’utente scegliesse l’opzione numero 7, l’istruzione $(this).val()
ritornerebbe proprio il valore 7. Ciò significa che la variabile option
assumerebbe il valore
1 | option[value='7'] |
Conseguentemente l’istruzione successiva risulterebbe questa
1 | var value = $(this).find(“option[value='7']”).text() ; |
Che sfrutta il selettore dell’attributo per individuare l’opzione scelta dall’utente, leggerne il contenuto e assegnarla alla variabile value
. Con questo stratagemma il valore impostato nella select
, risulta sempre sincronizzato a quello del campo di tipo input.
Mettendo tutto assieme abbiamo un sistema che permette di utilizzare le select
in maniera moderna e flessibile, preservando la struttura HTML. L’unica accortezza è quella di fare attenzione all’ordine col quale specifichiamo i componenti HTML. In questo caso abbiamo inserito prima l’elemento select
e poi il campo di tipo input. Qualsiasi sia l’ordine da noi scelto è importante rispettarlo, perché gli snippet utilizzano le istruzioni prev
e next
per identificare i componenti HTML. Ad esempio, se volessimo invertire l’ordine della select
rispetto al campo di input, dovremmo anche invertire tutte le istruzioni prev
con un next
, e viceversa.