Select multipli (o in cascata) in CakePHP con JQuery e AJAX
E’ un classico problema per i form da utilizzare nelle web application: selezionare in una select un elemento e popolare una seconda select con elementi ottenuti dalla scelta della prima.
Il tipico esempio è quello della scelta del Comune: per facilitare la vita all’utente gli si chiede di selezionare la provincia in una prima select per poi scegliere nella seconda tra i comuni della sola provincia selezionata.
Tra i vari modi di ottenere delle select in cascata, ho scelto di sfruttare JQuery, ma soprattutto gli oggetti messi a disposizione da CakePHP nella versione 1.3 per accedervi facilmente.
Installazione di JQuery
Si potrebbe scaricare la libreria sul proprio server e richiamarla da lì, ma preferisco richiamarle dal repository di Google.
echo $this->Html->script(array('https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js'));
per inserirla nel layout, oppure
$this->Html->script(array('https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js'),false);
da utilizzare occasionalmente nella view.
Nel layout
Si deve aggiungere un comando per la scrittura della cache degli script prima del tag di chiusura
echo $this->Js->writeBuffer(); // Write cached scripts
Nel controller
Immaginiamo di dover scegliere la città per un utente, quindi nel controller Users richiamiamo l’heleper
var $helpers = array('Js' => array('Jquery'));
Popoliamo la prima select con i nomi delle province (districts)
function add(){
$this->set('districts',$this->User->City->District->find('list'));
}
Per ottenere l’elenco delle città in base alla provincia selezionata si deve creare un metodo del controller Cities
function getCities(){
$this->layout="ajax";
$district_id = $this->data['City']['district_id'];
$cities = $this->City->find('list',array('conditions'=>array('City.district_id'=>$district_id)));
$this->set('cities',$cities);
}
Nella view Cities/getCities
foreach($cities as $k=>$v){
echo "
";
}
Nella view Users/add
echo $this->Form->create();
echo $this->Form->input('district_id',array('empty'=>true));
echo $this->Form->input('city_id',array('type'=>'select'));
echo $this->Form->end('Invia');
A questo punto bisogna inserire il codice JQuery che attiva il meccanismo, ma lo facciamo utilizzando i metodi del component JS.
Inserire prima del form il seguente codice:
$this->Js->get('#UserDistrictId')->event('change',
$this->Js->request(array('controller'=>'cities','action' => 'getCities'),
array(
'method' => 'POST',
'type'=>'json',
'async' => true,
'update' => '#UserCityId',
'dataExpression'=>true,
'data'=>$this->Js->serializeForm(array('isForm' => true, 'inline' => true))
)
)
);
Fare attenzione al nome delle select interessate, utilizzando la notazione CSS per la loro identificazione ‘#nomecampo’ e la convenzione di CakePHP.















Grazie mille per la condivisione, è una cosa che probabilmente mi servirà tra un po’ ed ero pronto a perderci qualche ora.. adesso invece so da dove partire, con la pappa pronta :)
Se al momento buono avrò qualche cosa di significativo da aggiungere risponderò qui
Bene, sei il benvenuto su questo sito !
Io sto cercando di fare funzionare la stessa cosa però su 1.2 ma di sicuro mi perdo in qualche passaggio.
Allora in cities_controller.php
function getCities() {
$district_id = $this->data['City']['district_id'];
debug($district_id);
$cities = $this->City->find('list',array
('conditions' => array('City.district_id'=>$district_id)));
$this->set('cities',$cities);
}
Mi creo la relativa view getCities.ctp
$v){
echo "$v";
}
?>
Nel controller in cui ho la funzione add, ovvero courses_controller.php inserisco
function add() {
if(!empty($this->data)) {
if($this->Course->save($this->data))
{
$this->Session->setFlash(__('Corso salvato',true));
$this->redirect(array('action' => 'index'));
}
else
{
$this->Session->setFlash('Errore');
}
}
$this->set('districts',$this->Course->City->District->find('list'));
}
La relativa add.ctp del controller
echo $form->create('Course');?>
echo $form->input('district_id',array('empty'=>true));
echo $form->input('city_id',array('type'=>'select'));
echo $form->end('Crea Corso');
echo $ajax->observeField('CourseDistrictId',
array(
'url' => array('controller'=>'cities','action'=> 'getcities'),
'update' => 'CourseCityId',
'frequency' => 0.2,
)
);
$this->render('/cities/getCities');
Ovviamente in default.ctp ho caricato
echo $javascript->link('prototype',false);
echo $javascript->link('scriptaculous',false);
e in app_controller.php ho
var $helpers = array('Html', 'Form', 'Ajax', 'Javascript', 'Session');
Ho controllato il codice sorgente della pagina add.ctp renderizzato e ho
District
Ho letto il tuo post http://www.luizz.it/234/cakephp/controllare-lo-stato-di-un-campo-con-ajax-e-cakephp
e credo di aver fatto le cose in modo corretto.
Grazie in anticipo per l’aiuto.