Joomla.it Forum

Non solo Joomla... => Sviluppo => : tampe125 10 Dec 2010, 21:00:26

: Select list dipendenti
: tampe125 10 Dec 2010, 21:00:26
Adesso è giunto il momento di restituire qualcosa alla comunità di Joomla.it che mi ha aiutato in diversi modi e maniere.
Ringrazio soprattutto mmeloni e mau_develop, che nonostante il mio martellamento continuo mi hanno aiutato costantemente.

Passiamo ai fatti.
Io avevo l'esigenza di creare select list dipendenti, come nel classico caso di province->comuni.
In più, il codice che le generava doveva essere dinamico a sua volta, perchè i campi cambiano nome a seconda di dove mi trovo.
Premetto di non essere un mago di javascript, tutto questo è venuto fuori a furia di provare e riprovare, anche perchè Joomla! utilizza la vecchia versione di mootools, e trovare supporto è quasi impossibile.

Il sistema si compone di 3 parti:
Partiamo dalla generazione del codice javascript; anche in questo caso possiamo dividerlo in due:

JSlinkedSelect si aspetta un array di array, perchè in una pagina potrei avere più di una select list dipendente.
Le chiavi dell'array "più interno" sono le seguenti:
$ele['padre']   = elemento "padre". al cambiare del suo valore il figlio caricherà i valori legati
$ele['figlio']   = elemento "figlio".
$ele['table']   = tabella dove si trovano i valori per il figlio.
$ele['where']   = campo di collegamento (join) fra il padre e il figlio.

:
function JSlinkedSelect($select){
$js = "window.addEvent('domready', function(){
var base_url = 'index.php?option=com_miocomponente&controller=helper&task=json_select&format=raw';

function buildSelect(select, options)
{
    var select = $(select);
    select.empty();
    options.each(function(item) {
           
            var option = new Element('option', {
                value: item.value.toString()
            });
            option.setHTML(item.text.toString());
            option.injectInside(select);
    });
}";

foreach($select as $ele){
$js .= $this->_buildAddEvent($ele);
}

$js .= "});";

return $js;
}
Di questa funzione non c'è molto da dire; viene creata il codice JS che si occuperà di "svuotare" il figlio e di inserire le opzioni prendendole dalla risposta in formato JSON.
Il grosso del lavoro viene svolto da _buildAddEvent()

:
function _buildAddEvent($ele){
$js =
"$('{$ele['padre']}').addEvent('change', function(){
if($('{$ele['figlio']}_wait')) $('{$ele['figlio']}_wait').setStyle('display', 'inline');
var req_url = base_url + '&id=' + this.value + '&table={$ele['table']}&where={$ele['where']}';
var JSonReq = new Json.Remote(req_url, {
onComplete: function(response){
buildSelect('{$ele['figlio']}', response);
if($('{$ele['figlio']}_wait')) $('{$ele['figlio']}_wait').setStyle('display', 'none');
}
}).send();
});";

return $js;
}
Ok, facciamo un po' di chiarezza.
Ogni volta che il padre cambierà valore, viene lanciata la relativa funzione.
Innanzi tutto, se presente, viene mostrata la classica immagine di attesa, che deve essere inserita direttamente nel codice HTML in questo modo:
:
<img id="comune_wait" src="images/wait16trans.gif" style="display: none" />
Sinceramente potrebbe essere pensata meglio, ma al momento... :D

Dopodichè vengono composti i parametri della richiesta, quando verrà completata, la risposta sarà processata e inserita nella select figlia.

Andiamo a vedere come viene elaborata la richiesta
:
function json_select(){
$id    = JRequest::getCmd('id');
$join  = JRequest::getCmd('where');
$table = JRequest::getCmd('table');

if((int)$id) $where = " $join = $id";
else $where = " $join = ".$this->_db->Quote($this->_db->getEscaped($id, true), false); #escape + quote della stringa

$query = "SELECT id as id, descr as descr FROM #__{$table} WHERE 1 = 1";
if($where)$query .= " AND $where";
$query .= " ORDER BY 2";

$this->_db->setQuery($query);
$rows = $this->_db->loadObjectList();

$response[] = array('value' => '', 'text' => ' - Seleziona - ');
foreach($rows as $row){
$t['value'] = $row->id;
$t['text'] = $row->descr;
$response[] = $t;
}

echo json_encode($response);
}
Come prima cosa prendo i valori necessari per costruirmi la select (id, campo di join e la tabella interessata). L'id può essere numerico oppure stringa, per cui in quest'ultimo caso effettuo l'escape e il quote. Credo sia sufficiente, ma sono aperto a suggerimenti :)
La query si basa su una convenzione mia interna, in cui tutti i campi "id" si chiamano.. id e tutti i campi di descrizione... descr :D
Una volta caricata la query, organizzo i dati nello standard di Joomla e poi restituisco il tutto a video.

Infine, questo è il modo in cui viene chiamato il tutto:
:
$select[] = array('padre' => 'provincia', 'where' => 'provincia', 'table' => 'comuni', 'figlio' => 'comune' );
$select[] = array('padre' => 'prov_nasc', 'where' => 'provincia', 'table' => 'comuni', 'figlio' => 'comune_nasc');

$js = $helper->JSlinkedSelect($select);

Alcune considerazioni:

Se fosse possibile, mi piacerebbe scrivere un articolo su questa parte, in modo da aiutare anche gli utenti alle prime armi che iniziano a scrivere le proprie estensioni, quindi segnalatemi evenutali errori