Back to top

Autore Topic: Select list dipendenti  (Letto 1643 volte)

Offline tampe125

  • Appassionato
  • ***
  • Post: 366
    • Mostra profilo
Select list dipendenti
« il: 10 Dic 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:
  • la funzione che costruisce al volo il codice javascript (chiamata JSlinkedSelect)
  • la funzione che elabora la richiesta Ajax e resituisce i valori per la select dipendente (chiamata json_select, dentro un controller chiamato helper)
  • il codice necessario per far partire il tutto
Partiamo dalla generazione del codice javascript; anche in questo caso possiamo dividerlo in due:
  • una parte generale che si occuperà di processare e inserire i nuovi valori nella select dipendente
  • la parte ajax vera e propria, inclusa in una seconda funzione

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.

Codice: [Seleziona]
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()

Codice: [Seleziona]
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:
Codice: [Seleziona]
<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
Codice: [Seleziona]
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:
Codice: [Seleziona]
$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:
  • il formata da utilizzare deve essere quello raw, altrimenti Joomla effettua l'output anche di altro codice che non ci interessa (file javascript, css, metatag ecc ecc); per cui deve essere creata la view corrispondente.
  • la query si basa su un convenzione personale, spero che anche voi adottiate un vostro standard interno, altrimenti... si può fare ma la vedo un po più dura
  • dal punto di vista javascript, sicuramente non è il massimo, ci sarà senz'altro un modo per non dover scrivere tutte le volte il codice.. però io non l'ho trovato :)
  • le funzioni javascript sono state sviluppate per il framework mootools 1.11, che fino a poco tempo fa è stato lo standard su tutte le installazioni di Joomla. Ho fatto delle prove con il plugin della nuova versione attivo e mi sembra che funzioni tutto lo stesso
  • suggerimenti e consigli sono ben accetti

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
www.fabbricabinaria.it
Soluzioni originali ad esigenze quotidiane

 



Web Design Bolzano Kreatif