[SOLVED] AJAX to hide form div based on dropdown

I want to hide or display a form element based on input from another form element. Can someone help with advice?

I tried to set a _form element css style=display:hidden or style=display:block depending on the value selected in another dropdown

on the same _form using AJAX .

I tried a bunch of things but not getting anywhere. At the moment, I am consistently getting the "Bad AJAX" alert from my _form .

Hope someone can help. here is my code:

model:




...

	// Perspective of:

	// defendant (creditor) or plaintiff (Trustee)

	// defaults to creditor.

	const PERSPECTIVE_CREDITOR=0;

	const PERSPECTIVE_TRUSTEE=1;

....




_form:




...

<?php 


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

	'id'=>'pcase-form',

	//'enableAjaxValidation'=>false,

    	'enableAjaxValidation'=>true,

    	'clientOptions'=>array(

            	'validateOnChange'=>true,

            	'validateOnSubmit'=>false,

            	'validateOnType'=>false,

        	),

   	

	

)); ?>


....


<div class="row">

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

		<?php echo 

                	$form->dropDownList(

                        	$model,

                        	'perspective_id',

                        	$model->getPerspectiveOptions(),

                        	array('onchange' => CHtml::ajax(array(

                   				'type'=>'POST',

                   				'url'=>CController::createUrl('pcase/perspectiveChanged'),

                   				//'datatype'=>'text',

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

                   				'success' => 'function(retval){$("#insider_div").attr("style",retval);}',

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

                   				//'update'=>'#insider_div',

           				)))

                    	

                	); 

            	?> 

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

	</div>

   

   <!-- insider_id is only applicable in from the creditor perspective -->

   <!-- need to figure out how to set the value to NO in the dropdown and hide the dropdown if not creditor -->

   <div id="insider_div">  

   <?php //if($model->perspective_id===PCase::PERSPECTIVE_CREDITOR): ?> 	

	<div class="row">

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

		<?php echo $form->dropDownList($model,'insider_id', $model->getInsiderOptions()); ?>

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

	</div>   	

  <?php //endif; ?>

  </div>  

  <!-- end of insider_div -->  


....



Controller:




...

public function accessRules()

	{

		return array(

			...

                    	array('allow', // allow authenticated user to perform AJAX validation actions, called from _form

				'actions'=>array('perspectiveChanged'),

				'users'=>array('@'),

			),

       	...

	}

...

public function actionPerspectiveChanged()

    	{

            	//Handler for _form updates when perspective_id is changed.

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

            	{

                	/* DID NOT WORK

                	echo '<div class="row">';

                	echo CHtml::activeLabelEx($model,'insider_id');

                	echo CHtml::activedropDownList($model,'insider_id', $model->getInsiderOptions());

                	echo '</div>';

                	*/

     				

                	// DID NOT WORK - Try again..

                	//pick off the parameter value

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

                	if($perspective_id === PCase::PERSPECTIVE_TRUSTEE)

                	{

                    	//we are going to hide the insider_id field on _form.

                    	//by changing the style attribute on the form block div.

                    	echo "display:none";

                    	Yii::app()->end();

                	}

                	else

                	{

                    	//display the insider_id field block on _form

                    	echo "display:block";

                    	Yii::app()->end();

                	}

                	

            	}

    	}




I have done this using custom functions of JS and calling them inside of success.

You can also do this

for example




        'success'=>'function(data){

           formElement(data);

           }

        '



on JS side




function formElement(data){

       // process the data as per requirement 

}



Thanks for the reply @PeRoChAk… but in my code the js is already set in the ‘success’ parameter like so:




	'success' => 'function(retval){$("#insider_div").attr("style",retval);}',

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




The problem seems to be that the success function never gets called, because the error function does get called.

When I looked at the Ajax call with Firebug, I get a 403 error, indicating that I don’t have permissions to access the callback.

But what I don’t understand is that I have already updated the accessRules to let me perform the action.




array('allow', // allow authenticated user to perform AJAX validation actions, called from _form

				'actions'=>array('perspectiveChanged,'),

				'users'=>array('@'),

			),



Here is the error output from the firebug Net console:





[u]Location & parameters:[/u]


http://localhost/pss/index.php?r=pcase/perspectiveChanged&perspective_id=1


[u]Resonse Header:[/u]


Date: Wed, 02 Nov 2011 10:51:32 GMT

Server: Apache/2.2.21 (Win32) mod_ssl/2.2.21 OpenSSL/1.0.0e PHP/5.3.8 mod_perl/2.0.4 Perl/v5.10.1

X-Powered-By: PHP/5.3.8

Expires: Thu, 19 Nov 1981 08:52:00 GMT

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0

Pragma: no-cache

Content-Length: 1363

Connection: close

Content-Type: text/html


[u]Response Body:[/u]


<h1>CHttpException</h1>

<p>You are not authorized to perform this action. (D:\yii\yii-1.1.8.r3324\framework\web\auth\CAccessControlFilter.php:158)</p><pre>#0 D:\yii\yii-1.1.8.r3324\framework\web\auth\CAccessControlFilter.php(120): CAccessControlFilter->accessDenied(Object(CWebUser), 'You are not aut...')

#1 D:\yii\yii-1.1.8.r3324\framework\web\filters\CFilter.php(39): CAccessControlFilter->preFilter(Object(CFilterChain))

...

#8 D:\yii\yii-1.1.8.r3324\framework\web\CWebApplication.php(136): CWebApplication->runController('pcase/perspecti...')

#9 D:\yii\yii-1.1.8.r3324\framework\base\CApplication.php(158): CWebApplication->processRequest()

#10 D:\yii\pss\index.php(13): CApplication->run()

#11 {main}</pre>




Ok. Got the ajax callback to work I had a typo (trailing comma) in the ‘actions’ parameter.

Now I just need to fix the logic. what I want is for it to update the style attribute so that it will hide the target dropdown.

The callback is working , it is passing in the correct parameters [‘perspective_id’ = 0] or [‘perspective_id’ = 1] when the dropdown is changed - and the style attribute on the form is getting updated … but it is now consistently returning the string “display:block” :angry:

  • which seems to indicate a flaw in my controller code.

here is the bad code.





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

                	if($perspective_id === PCase::PERSPECTIVE_TRUSTEE)

                	{

                    	//we are going to hide the insider_id field on _form.

                    	//by changing the style attribute on the form block div.

                    	echo "display:none";

                    	Yii::app()->end();

                	}

                	else

                	{

                    	//display the insider_id field block on _form

                    	echo "display:block";

                    	Yii::app()->end();

                	}




It appears that I made the most basic mistake, using the === comparison operator instead of ==. In reviewing the PHP documentation it shows this:

$a == $b Equal TRUE if $a is equal to $b after type juggling.

$a === $b Identical TRUE if $a is equal to $b, and they are of the same type. (introduced in PHP 4)

Here is the final working version of my _form code.




<div class="row">

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

		<?php echo 

                	$form->dropDownList(

                        	$model,

                        	'perspective_id',

                        	$model->getPerspectiveOptions(),

                	

                        	array('ajax'=>array(

           						'type'=>'POST',

           						'url'=>CController::createUrl('pcase/perspectiveChanged'),

           						

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

           						'success' => 'function(retval){$("#insider_div").attr("style",retval);}',

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

           						'update'=>'#insider_div',

   						))

                    	

                	); 

            	?> 

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

	</div>

   

   <!-- insider_id is only applicable in from the creditor perspective -->

 

   <div id="insider_div">  

   	

	<div class="row">

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

		<?php echo $form->dropDownList($model,'insider_id', $model->getInsiderOptions()); ?>

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

	</div>   	

</div>




and here is the final working version of the controller…




public function actionPerspectiveChanged()

    	{

            	//Handler for _form updates when perspective_id is changed.

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

            	{

                	

                	//pick off the parameter value

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

                	if($perspective_id == PCase::PERSPECTIVE_TRUSTEE)

                	{

                    	//we are going to hide the insider_div block on _form.

                    	//by changing the style attribute on the form block div.

                    	echo "display:none";

                    	Yii::app()->end();

                	}

                	else

                	{

                    	//display the insider_div  block on _form

                    	echo "display:block";

                    	Yii::app()->end();

                	}

                	

            	}

    	}



I’m guessing that the datatype parameter in the ajax array might be able to allow me to work with the === operator ???

Hi Windsor,

Thanks a million for this detailed explanation.

I had to implement a similar feature (i.e. selected value from dropdown should toggle fields). You made me win a lot of time.

Cheers