Activedropdownlist Not Updated By Ajax

Dear Community,

I have been trying for a while now to find a way around my current problem but somehow the system won’t behave the way I was hoping for.

Please let me first explain what I am trying to achieve and then I will describe my approach and where I am blocked.

I am developing an application for a “Small Ad’s” web site. (i.e. an online second-hand platform). For convenience, the Items have 2 levels of grouping the first being “Category” and the second is the “Sub-category”. (one Cat has many sub-cats).

When creating a new ad, the user must choose the category->sub-category of his item. So far so good, now comes the tricky part:

After having picked a sub-category from a dropdown list, I want to dynamically load a sub-view that shows additional input fields that are specific to the sub-category that was chosen. (e.g. when selling a car, the user should see the fields for Brand, Model , Mileage, etc. and when selling a phone, there is no need for the Mileage field).

5802

Capture.JPG

[u]

So here is my approach:[/u]

in the _form.php , the selection of a value from the Sub-category dropdown triggers (via ajax call) a controller action that partially renders a sub-view (with category-specific fields). The rendered sub-view is returned via ajax to the main form.

This works ok, the only trouble is that I can not pass $form or $model objects the the sub-view.

Relevant _form.php code:




<?php $form=$this->beginWidget('CActiveForm', array(

	'id'=>'article-form',

	'htmlOptions' => array(

        'enctype' => 'multipart/form-data',

    ),

	'enableAjaxValidation'=>false,

)); ?>


	<p class="note">Fields with <span class="required">*</span> are required.</p>


	<?php echo $form->errorSummary($model); ?>


	<div id="Category" style="display:block">

		<?php $this->beginWidget('zii.widgets.CPortlet', array('title'=>'Category',)); ?>

		<div class="row">

			<?php echo $form->labelEx($model,'sub_cat_id'); ?>

			<?php echo $form->dropDownList(

                                                $model,

                                                'sub_cat_id', 

                                                Subcat::model()->getSubCatGroup(),

                                                array('ajax'=>array(

                                                            'type'=>'POST',

                                                            'url'=>CController::createUrl('article/IncludeForm'),

                                                            'data'=>array('sub_cat_id' => 'js:this.value'),

                                                            'error'=> 'function(){alert(\'Bad AJAX\');}',

                                                            'update'=>'#_subforms',


                                                            ))						

                                                ); ?>

			<?php echo $form->error($model,'sub_cat_id'); ?>

			

		</div>

			

		<?php $this->endWidget(); ?>

	</div>

	

	

	<div id="_subforms">...</div> 

...

//The dummy form loads a sub_view that contains all ajax declarations from the "real" subviews

<?php $dummy_ajax_subform = $this->renderPartial('_subform_dummyAjax',array('model' => Article::model()),true); ?>

...




The controller action that renders the subform:




public function actionIncludeForm() 

	{	

		if (Yii::app()->request->isAjaxRequest)

		{

			$subcat_id = Yii::app()->request->getParam( 'sub_cat_id' );

                        

			switch ($subcat_id) {

			  case $subcat_id == "1": //Cars

				$myHtml = $this->renderPartial('_subform_cars',array('model' => Article::model(),'subcatid'=>$subcat_id),false,false);

				break;

			  case $subcat_id == "11": //Computers

				$myHtml = $this->renderPartial('_subform_computers',array('model' => Article::model(),'subcatid'=>$subcat_id),false,false);

				break;

			  default:

				$myHtml = CHtml::encode('forms not yet available...');

			} 

			echo $myHtml;

			Yii::app()->end(); // this ends Yii application in case of Ajax requests.                                  

		}

	}



As you can see, the last parameter of the "renderpartials" is "false". Some subforms may contain ajax calls and if the parameter were "true", then the ajax declaration of the subform would be loaded again and again instead of overwriting each other. I have solved the ajax problem from the subform by loading a "dummy_view" (with the ajax scripts) directly in the main form.

Code sample of a subform:




<?php  $this->beginWidget('zii.widgets.CPortlet', array('title'=>'Ad details',)); ?>

        <div class="row">    

		<?php echo CHtml::activeLabel($model,'prop_brand'); ?>

                <?php echo CHtml::activeDropDownList($model, 'prop_brand', FormFieldItems::model()->getFFbySubCat('BRAND',$subcatid),

                                                    //**

                                                    //Axax call

                                                    array(

                                                    'prompt' => 'Select brand ...',

                                                    'ajax' => array(


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

                                                            'url'=>CController::createUrl('article/subitemffsubcat'), //url to call	

                                                            'data'=>array('prop_brand'=>'js:this.value',

                                                                            'sub_cat_id'=>'js: $("#Article_sub_cat_id option:selected").val()'),  

                                                            'update'=>'#prop_model',

                                                            ),


						));

                ?>

	</div>


	<div class="row">

		<?php echo CHtml::activeLabel($model,'prop_model'); ?>

		<?php echo CHtml::dropDownList('prop_model','',array('empty' => 'Select brand first')); ?>

                <!--?php echo CHtml::activeDropDownList($model,'prop_model',array('empty' => 'Select brand first')); ?-->

                

	</div>


	<div class="row">

		<?php echo CHtml::activeLabel($model,'prop_year'); ?>

                <?php echo CHtml::activeDropDownList($model,'prop_year', 

                                                FormFieldItems::model()->getFFbyCode('YEAR'),

                                                array('empty' => 'Select a mfg year')); ?>

	</div>

....

<?php $this->endWidget(); ?>



The dummy form:




<?php $subcatid = 1 ?>

       

        <div class="row">

                   <?php echo CHtml::activeDropDownList($model, 'prop_brand', FormFieldItems::model()->getFFbySubCat('BRAND',$subcatid),

                                                    //**

                                                    //Axax call

                                                    array(

                                                    'prompt' => 'Select brand ...',

                                                    'ajax' => array(


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

                                                            'url'=>CController::createUrl('article/subitemffsubcat'), //url to call	

                                                            'data'=>array('prop_brand'=>'js:this.value',

                                                                            'sub_cat_id'=>'js: $("#Article_sub_cat_id option:selected").val()'),  

                                                            'update'=>'#prop_model',

                                                            ),


						));

                ?>

	</div>




Until now, everyting works fine, the sub-forms are dynamically loaded, the ajax calls from the subform work thanks to the dummy_subform.

Here is where the problem starts:

The "prop_brand" dropdown is the master of the "prop_model" dropdown. This means that for instance in the subcategory "Cars", when selecting the brand "Audi", I should expect the "prop_model" dropdown to be filled with all Audi models. The table containing the "model" records is called "tbl_form_field_subitems" and it is linked to both the sub-category table (tbl_subcat) and the master items table (tbl_form_field_items).

At the beginning, I thought that I could simply fetch the sub_item records via a controller action and then populate the dropdown from the sub_form with the results.

Code snippet from the controller action:




public function actionSubItemFFSubCat()    

        {   

            $ffcode = Yii::app()->request->getParam( 'prop_brand' );

            $subcat = Yii::app()->request->getParam( 'sub_cat_id' );

            

            $criteria = new CDbCriteria;

            $criteria->addCondition('parent_item_id=:ffcode');

            $criteria->addCondition('subcat_id=:subcat');

            $criteria->params=array(':ffcode'=>$ffcode, ':subcat'=>$subcat);

            

            $fflist=FormFieldSubitems::model()->findAll($criteria);

           

            $formfieldSubItemArray = CHtml::listData($fflist, 'id', 'item_label_en');


            foreach($formfieldSubItemArray as $value=>$item_label_en)

		{

			echo CHtml::tag('option',

					   array('value'=>$value),CHtml::encode($item_label_en),true);

		}

            

        }



Unfortunately this does not work the way I was hoping for.

The following part of the subform should receive the ajax return values:




<?php echo CHtml::dropDownList('prop_model','',array('empty' => 'Select brand first')); ?>

<!--?php echo CHtml::activeDropDownList($model,'prop_model',array('empty' => 'Select brand first')); ?-->

                

	</div>



In the code sample there are 2 dropdown boxes:

The first one (dropDownList) is able to receive the Ajax result and it is populated correctly but since it is not bound to the $form or $model objects, the selected values won’t be saved in the DB.

The second one (activeDropDownList) , for a reason I can not understand, simply does not process the Ajax response and therefore it stays empty.

Remember that the subform does not know about the $form object, so I won’t be able to use “$form->dropDownList”.

So after a lot of trial and error and googling, I finally think that I may need the help of experts in order to find my way out.

Now that I have explained my approach and discussed the choices I made, would anyone be able to get me on the right track?

If you know of better ways to dynamically include subforms, (especially if these ways would have spared me all the trouble of registering the ajax calls in a dummy subform), and be able to have a dependent dropdown inside this subform, then I beg you to tell me.

Thanks in advance for any replies.

Ok guys, the problem is solved… it had nothing to do with the loading of a subform.

I got caught by my own game.

After a good night’s sleep I realized that when I replaced the “dropDownlist” with “activeDropDownlist” for the “prop_model” field in the “sub-form”, I only adjusted the prop_brand ajax declaration in the subform itself. I completely forgot that the “real” ajax declaration was made in the “dummy_form”.

So the "dummy-form" continued pointing to update the #prop_model field id (see below).


'update'=>'#prop_model',

While the id of the "activeDropDownlist" is prefixed with the model name. So the "update" property should have been as follows, in the "dummy subform":


'update'=>'#'.CHtml::activeId($model,'prop_model'),

Sometimes a stupid mistake like this can cost hours … well at least next time I will be more careful.

[b]

[Edit:][/b] By the way, can anybody tell me how to change the thread title in order to mark it as "solved"?

Read this

http://www.yiiframework.com/forum/index.php/topic/53082-solved-marking-topis-as-solved/page__p__244837__fromsearch__1#entry244837

Thanks, I missed the fact that I had to use the full editor in order to get access to the thread title.

But the following post advises against putting "Solved" in the thread name.

http://www.yiiframework.com/forum/index.php?/topic/14022-saving-passwords/page__view__findpost__p__69254

Nevertheless I changed the title to something more comprehensive.