Nested ajax dropdownlist

I want the content of my "installation_id" dropdownlist to change when I select something in the company_id dropdownlist.  I have read similar problems in this forum and they have given me a few hints but I do not get this to work.

When I select something in the "company_id" dropdownlist nothing happens. In the code below I am trying a fixed value for the company_id.

Maybe someone can help me in the right direction here.

Here is some parts of my code:

StatuslogController.php :



	   public function actionloadInstallations()


   {


      $options = '';	  


     


 $options = installations::model()->findAllByAttributes(array('companies.company_id'=>1));


		


	  


	  $return = CHtml::listData($options, 'id', 'field_name');


	  


      return $return;


   } 


\views\statuslog\create.php



<div class="simple">


<?php echo CHtml::activeLabelEx($statuslog,'company_id'); ?>


<?php echo CHtml::activeDropDownList($statuslog, 'company_id', CHtml::listData(companies::model()->Companies, 'id', 'name'),


array(


'ajax' => array(


'type'=>'POST',


'url'=>'index.php?r=statuslog/loadInstallations',


'update'=>'#installation_id',


),


)); ?>


</div>











<div class="simple">


<?php echo CHtml::activeLabelEx($statuslog,'installation_id'); ?>


<?php echo CHtml::activeDropDownList($statuslog, 'installation_id', CHtml::listData(installations::model()->installations, 'id', 'field_name')); ?>





I coded this extension to do the same thing but your solution might be a lot easier. http://github.com/do…nedDropdown.php

I think it fails on the return value of your actionloadInstallations(), you pass back a php array and jquery doesn't know what do do with that. Pass it back as html and it might work. (In my extension I pass back json, this is then converted to html by jquery) Also, use Firebug to debug your ajax request.

More explain how to use this extension please…

Thanks…

Thanks dalip for your answer, I will try out your suggestion and report back here when I am done.

Usage of the widget mentioned above: http://wiki.github.c…chaineddropdown

I try this extentsion like this.

In controller:



<?php





        public function actiondrop()


	{


		$this->render('Drop');


	}


	public function actionloadCategories()


	{


		$sectionID=$_POST['sectionid'];


		$criteria=new CDbCriteria;


		$criteria->condition='section=:sec';


		$criteria->params=array(':sec'=>$sectionID);


		$cate=categories::model()->findAll($criteria);


	}


In my view:



<?php echo CHtml::form(); ?>





<?php $section=sections::model()->findAll(); ?>


<div class="simple">


<?php echo CHtml::dropDownList('sectionid','', CHtml::listData($section,'id','name')); ?>


</div>


<div class="simple">


<?php


$this->widget('application.extensions.DropDown.ChainedDropdown',


array('url'=>array('innerSite/LoadCategories') ,


'name'=>'id','ID'=>'id','onchangeSelector'=>'sectionid'));


?>


</div>








<div class="action">


<?php echo CHtml::submitButton('Submit'); ?>


</div>





</form>


But, the second dropdown still empty or does not load categories of selected section.

And I don't know where the mistake.

Thanks

The action you're calling should output json in the format {‘1’:’New York ’,’2’:’Alabama’}

Thanks to quick reply :)

In the view source is like this. (I add '<?php' in the first line just to make it coloured)



<?php 





<form action="/ycms/innerSite/Drop" method="post">


<div class="simple">


<select name="sectionid" id="sectionid">


<option value="1">Wellcome Page</option>


<option value="2">About Us</option>


<option value="3">News</option>


<option value="4">Services</option>


<option value="5">Solutions</option>


<option value="6">Projects</option>


<option value="7">Documentation</option>





<option value="8">F.A.Q</option>


</select></div>


<div class="simple">


<select id="id" name="id">


</select></div>








<div class="action">


<input type="submit" name="yt0" value="Submit"/></div>





</form>





<script type="text/javascript">


/*<![CDATA[*/


jQuery(document).ready(function() {


function generateSelect(value){ var o = ''; for(key in value)	{ o += '<option value="' + key + '">' + value[key] + '</option>';} if(o!=''){ jQuery(o).prependTo("#id"); }} 	


function getData(value)	{ jQuery("#id").empty(); jQuery.getJSON('/ycms/innerSite/LoadCategories', { value: value }, generateSelect);}


		jQuery("#sectionid").change(function () { getData(this.value); });var n=jQuery("#sectionid").attr('value'); getData(n);


});


/*]]>*/


</script>








Here is my database table:



<?php





--


-- Table structure for table `categories`


--





CREATE TABLE IF NOT EXISTS `categories` (


  `id` int(11) NOT NULL AUTO_INCREMENT,


  `name` varchar(255) NOT NULL DEFAULT '',


  `section` int(11) NOT NULL,


  `published` tinyint(1) NOT NULL DEFAULT '0',


  PRIMARY KEY (`id`),


  KEY `cat_idx` (`section`,`published`)


) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ;





--


-- Dumping data for table `categories`


--





INSERT INTO `categories` (`id`, `name`, `section`, `published`) VALUES


(1, 'Why we are best', 1, 1),


(2, 'About Us', 2, 1),


(3, 'News', 3, 1),


(4, 'Services', 4, 1),


(5, 'Solutions', 5, 1),


(6, 'Current Projects', 6, 1),


(7, 'Documentation', 7, 1),


(8, 'F.A.Q', 8, 1);





-- --------------------------------------------------------





--


-- Table structure for table `sections`


--





CREATE TABLE IF NOT EXISTS `sections` (


  `id` int(11) NOT NULL AUTO_INCREMENT,


  `name` varchar(255) NOT NULL DEFAULT '',


  `published` tinyint(1) NOT NULL DEFAULT '0',


  PRIMARY KEY (`id`)


) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ;





--


-- Dumping data for table `sections`


--





INSERT INTO `sections` (`id`, `name`, `published`) VALUES


(1, 'Wellcome Page', 1),


(2, 'About Us', 1),


(3, 'News', 1),


(4, 'Services', 1),


(5, 'Solutions', 1),


(6, 'Projects', 1),


(7, 'Documentation', 1),


(8, 'F.A.Q', 1);








Like you see, I want to load Categories base of selected section.

How to make controller and view in this case?

Let your controller action output in the format mentioned above. So 'number->value' in json.

E.g.



		$data=Location::model()->findAll();





		$data=CHtml::listData($data,'id','name');


		echo CJavaScript::encode($data);


Again, use Firebug to debug ajax requests and javascript in general. Makes life much easier.

I've figured out how to do this without the extension I wrote. It's quite a bit easier this way.

Say I have a form with countries and cities for example (E.g. USA->New York, LA etc…)

My view will look like



 echo CHtml::dropDownList('country_id','', CHtml::listData($countries,'id','name'),


array(


'ajax' => array(


'type'=>'POST', //request type


'url'=>'dynamiccities', //url to call


'update'=>'#city_id', //selector to update


))); 


echo CHtml::dropDownList('city_id','', array()); //empty since it will be filled by the other dropdown


Now whenever the first dropdown is changed an ajax request will occur to the url and the entries of the second dropdown will be replaced.

The action called by the url will look something like this:



    public function actionDynamiccities(){


		$data=Location::model()->findAll('parent_id=:parent_id', array(':parent_id'=>(int) $_POST['country_id']));





		$data=CHtml::listData($data,'id','name');





            foreach($data as $value=>$name)


            {


                 echo    CHtml::tag('option',array('value'=>$value),CHtml::encode($name),true);


            }





		die();


	}


Thanks dalip, very helpful!

I had to add the form as in

array(’:parent_id’=>(int) $_POST[‘name_of_form’][‘country_id’])
, but that may be due to having several forms on the page?

Anyways, works fine, thanks!

//Magnus

It depends on the form and whether you use 'active' form fields. You can debug this by looking at the ajax request. You'll find all form values are being posted on the in the ajax request unless you override the 'data' key in the ajax configuration array.

I almost give up!

Thanks dalip.

But, I have problem now how to insert option instruction in first list like:

In country dropdownlist:

==Select Country==

In Satate dropdownlist:

==Please Select Country First==

And after user selected Country and state, the text below appear:

Your selected Country is: country_name

Your selected Satate is: state_name

Big thanks again…

Try this modification:

echo CHtml::dropDownList('country_id','', CHtml::listData($countries,'id','name'),

array(

'empty'=>'==Select Country==',

'ajax' => array(

/Tommy

Thanks Tommy, it works!

And in: echo CHtml::dropDownList(‘city_id’,’’, array(‘empty’=>’==Please Select Country First====’,));

Now is the last step, how to generate result:

Your selected Country is: country_id

Your selected City is: city_id

I think you can replace the 'update' part with:

'success'=>'js:function(html){jQuery("#city_id").html(html); jQuery("#you_selected").attr("innerHTML", jQuery("#country_id :selected").text());}',

and add:

echo 'You selected: <span id="you_selected">nothing yet</span>';

/Tommy

Edit: found out how get the selected text instead of selected id.

Thanks you Tommy

The ‘success’ code is works in Country dropdownlist. When I try the same way in City Dropdownlist, the code display in the list…  ;D

How to get value of 'id' for each dropdownlist?

I have other items in my dropdown lists but I tested something similar to:



<?php





'success'=>'js:function(html){jQuery("#city_id").html(html); jQuery("#selected_country").attr("innerHTML", jQuery("#country_id :selected").text());}',





echo 'You selected: <span id="you_selected">nothing yet</span>';





'success'=>'js:function(html){jQuery("#street_id").html(html); jQuery("#selected_city").attr("innerHTML", jQuery("#city_id :selected").text());}',





echo 'You selected: <span id="selected_city">nothing yet</span>';





echo CHtml::dropDownList('street_id','', array());


?>





This seems to work but there's one remaining problem: when the city list is filled in, the '==select city==' part is lost and a selection change has to be made to trig the Ajax call (and 'You selected …'). I don't know how to solve this. Maybe there's a better solution than the one I tried.

These statements can of course be executed in the same script:



jQuery("#selected_country").attr("innerHTML", jQuery("#country_id :selected").text());


jQuery("#selected_city").attr("innerHTML", jQuery("#city_id :selected").text());


Edit:

I read your question again. I guess you want to assemble the selected values in the client for later posting, right? My initial thought was to save them one by one in the controller actions.

You can get the id's this way:



jQuery("#selected_country").attr("innerHTML", jQuery("#country_id :selected").val());


jQuery("#selected_city").attr("innerHTML", jQuery("#city_id :selected").val());


I need to grap country and city 'id' to generate table list.

So, after user selected the options, the next action is;



<?php


$criteria=new CDbCriteria;


$criteria->condition='country_id=:country_selected AND city_id=:city_selected';


$criteria->params=array(':country_selected'=>$_POST['country_selected'],':city_selected'=>$_POST['city_selected']);





$table_list=content::model()->findAll($criteria);

Maybe something like the following.

In your view :



<?php


echo CHtml::dropDownList('city_id','', array(),


  array(


    'empty'=>'==select city==',


    'ajax' => array(


      'type'=>'POST',


      //'url'=>'test/dynamiccity',


      'url'=>'index.php?r=test/dynamiccity',


      'success'=>'js:function(html){jQuery("#table_id").html(html);}',


    )


  )


);


?>


<div id="table_id">


</div>


In your controller action for the city dropdownlist:



<?php


// $table_list = <select from db> (use $_POST[country_id], $_POST[city_id])


$this->renderPartial('listTable', array('table_list'=>$table_list));


?>


add view file listTable.php:



<table class="dataGrid">


<?php foreach($table_list as $n=>$model): ?>


  <tr class="<?php echo $n%2?'even':'odd';?>">


    <td><?php echo CHtml::encode($model->id); ?></td>


    <td><?php echo CHtml::encode($model->attr1); ?></td>


    <td><?php echo CHtml::encode($model->attr2); ?></td>


  </tr>


<?php endforeach; ?>


</table>


Edit: fixed typo