codice:
;(function(){
// ------------------------------------- Impostazioni -------------------------------------
var impostazioni = {
testoQuandoVuoto : '-- non disponibile --'
, valoreQuandoVuoto : '-1'
, testoQuandoNonVuoto : '-- seleziona un\'opzione --'
, valoreQuandoNonVuoto : '0'
, disabilitaQuandoVuoto : true
, selezioneAutomaticaQuandoUnicaScelta : true
, mantieniSelezionePerSosia : true
, dati:
[ ['testo 1', 'val 1'
, ['testo 1_1', 'val 1_1'
, ['testo 1_1_1', 'val 1_1_1']
, ['testo 1_1_2', 'val 1_1_2']
]
, ['testo 1_2', 'val 1_2'
, ['testo 1_2_1', 'val 1_2_1']
, ['testo 1_2_2', 'val 1_2_2']
, ['testo 1_2_3', 'val 1_2_3']
]
, ['sosia in testo 1 e testo 2', 'val 1_3'
, ['testo 1_3_1', 'val 1_3_1']
, ['testo 1_3_2', 'val 1_3_2']
, ['testo 1_3_3', 'val 1_3_3']
]
]
, ['testo 2', 'val 2'
, ['testo 2_1', 'val 2_1'
, ['testo_2_1_1', 'val 2_1_1']
, ['testo 2_1_2', 'val 2_1_2']
]
, ['testo 2_2', 'val 2_2'
, ['testo 2_2_1', 'val 2_2_1']
, ['testo 2_2_2', 'val 2_2_2']
, ['testo 2_2_3', 'val 2_2_3']
]
, ['sosia in testo 1 e testo 2', 'val 2_2']
]
, ['testo 3', 'val 3'
, ['testo 3_1 (unica scelta)', 'val 3_1'
, ['testo 3_1_1', 'val 3_1_1']
, ['testo 3_1_2', 'val 3_1_2']
, ['testo 3_1_3', 'val 3_1_3']
, ['testo 3_1_4', 'val 3_1_4']
]
]
, ['testo 4', 'val 4']
]
}
// ----------------------------------------------------------------------------------------
function aggiornaCascata(select, arrDati, isRicorsione){
// Aggiorna la cascata di select (dello stesso gruppo) partendo da quella specificata
if (!select) return false;
arrDati = arrDati || impostazioni.dati;
var indiceSelectCorrente = getIndiceSelect(select)
, testoSelectCorrente = $('>option:selected',select).text()
, arrTesti = [testoSelectCorrente]
, subsetDatiProssimaSelect = []
, corrispondenzaTrovata
, html = ''
;
if (!isRicorsione) {
// Ottengo il percorso corrente della cascata, dalla select combo_0 a quella specificata, creando un array dei testi relativi alle option selezionate
$('.'+getNomeGruppo(select)).each(function(){
var i = getIndiceSelect(this);
if (i<=indiceSelectCorrente) arrTesti[i] = $('>option:selected',this).text();
});
}
// Processo i dati e costruisco il contenuto della select
if(arrDati.length==0) html = optionVuota;
else {
arrTesti.some(function(testo, i){
corrispondenzaTrovata = false
arrDati.forEach(function(dato, n){
attrSelected = '';
if (dato[0]==testo || (arrDati.length==1 && impostazioni.selezioneAutomaticaQuandoUnicaScelta)) {
subsetDatiProssimaSelect = dato.slice(2);
corrispondenzaTrovata = true;
attrSelected = ' selected';
}
if (arrTesti[i]==testoSelectCorrente)
html += '<option value="'+dato[1]+'"'+attrSelected+'>'+dato[0]+'</option>';
});
arrDati = corrispondenzaTrovata ? subsetDatiProssimaSelect : [];
if (!corrispondenzaTrovata) return true;
});
html = (html==''?optionVuota:optionEtichetta)+html;
}
$(select).html(html);
impostaSelect(select);
aggiornaCascata(getProssimaSelect(select), arrDati, true);
}
function getProssimaSelect(select){ return $('.combo_'+(+getIndiceSelect(select)+1)+'.'+getNomeGruppo(select)).get(0); } // Restituisce la prossima select dello stesso gruppo, oppure undefined
function getIndiceSelect(select){ return (select.className.match(/(?:^| )(?:combo_)(\d+)(?: |$)/)||[false]).pop(); } // Restituisce l'indice prelevato dalla classe combo_, oppure false
function getNomeGruppo(select){ return (select.className.match(/(?:^| )(gruppo_[^ ]+)(?: |$)/)||[false]).pop(); } // Restituisce il nome, per intero, della classe gruppo_ (es: gruppo_xyz), oppure false
function impostaSelect(select){ // Imposta la select in base al contenuto e alla selezione attuale
$(select).removeClass('vuoto etichetta').prop('disabled',false)
.has('.etichetta:selected').addClass('etichetta').end().has('.vuoto').addClass('vuoto')
.filter(function(){return impostazioni.disabilitaQuandoVuoto}).prop('disabled',true);
}
var optionVuota = '<option class="vuoto" value="'+impostazioni.valoreQuandoVuoto+'">'+impostazioni.testoQuandoVuoto+'</option>'
, optionEtichetta = '<option class="etichetta" value="'+impostazioni.valoreQuandoNonVuoto+'">'+impostazioni.testoQuandoNonVuoto+'</option>'
;
// Inizializzazione
$(function(){
$('select[class*="combo_"]').filter(function(){return getIndiceSelect(this);})
.change(function(){
impostaSelect(this);
var dati, prossimaSelect = getProssimaSelect(this);
if ($(this)[0].selectedIndex==0) dati = []; // Se è stata selezionata la prima option (etichetta), le select a seguire saranno svuotate
else if (!impostazioni.mantieniSelezionePerSosia) prossimaSelect.selectedIndex = 0; // Se mantieniSelezionePerSosia è false, la prossima select risulterà impostata sulla prima option (etichetta) e quelle a seguire saranno svuotate
aggiornaCascata(prossimaSelect, dati);
});
$('select.combo_0').each(function(){
aggiornaCascata(this);
})
})
})();
Come puoi vedere, sullo script dovrai impostare i dati, con una struttura ad array annidate. L'ho pensata così per essere il più semplice possibile da gestire. Inoltre è indentata volutamente in quel modo per comprendere meglio la struttura.