how to change select options based on a choice made from another select using ajax in symfony 1.2 or higher

This article has moved to this location.


Say, we have two choice widgets, choice_1 and choice_2. When user change the value of choice_1, the options in choice_2 will change based on the selected value of choice_1. How we do that if using ajax?
In this post, i’ll try to explain the above method using ajax and sfJqueryReloadedPlugin.
Ok.. let create the simple example..

  1. Create the primary form.
    class myForm extends sfForm
    {
    	public function setup()
    	{
    		$items = array('' => '-- Your Choice --', '1' => 'Item 1', '2' => 'Item 2');
    		$this->setWidgets(array(
    			'choice_1' => new sfWidgetFormChoice(array('choices' => $items)),
    			'choice_2' => new sfWidgetFormChoice(array('choices' => array())),		
    		));
    		$this->setValidators(array(
    			'choice_1' => new sfValidatorChoice(array('choices' => array_keys($items))),		
    		));
    		$this->widgetSchema->setNameFormat('form1[%s]');
        $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
    	}
    }
    

    The updateChoices() function is a function to update the choice options based on the selected value of choice_1.

  2. Create another form that extends the form you want to ajaxify (in this post is myForm) and remove unused field(s).

    class myAjaxSelectForm extends myForm
    {
    	public function configure()
    	{
    		unset($this['choice_1']);		
    		$choices = $this->updateChoices(sfContext::getInstance()->getRequest()->getParameter('choice_1_id'));
    		$this->widgetSchema['choice_2'] = new sfWidgetFormChoice(array('choices' => $choices));
    		$this->validatorSchema['choice_2'] = new sfValidatorChoice(array('choices' => array_keys($choices)));
    	}
    	
    	protected function updateChoices($choice_1)
    	{
    		$choices = array();
    		switch ($choice_1)
    		{
    			case 1:
    				$choices = array('1' => 'Sub item 1 of Item 1', '2' => 'Sub item 2 of Item 1');
    				break;
    			case 2:
    				$choices = array('3' => 'Sub item 2 of Item 2', '4' => 'Sub item 2 of Item 2');
    				break;
    		}
    		return $choices;
    	}
    }
    
  3. In your actions.class.php, add the action to show your main form.

    public function executeTest_select(sfWebRequest $request)
    {
    	$this->form = new myForm();
    }
    

    and create the corrensponding template..

    <!-- test_selectSuccess -->
    <?php use_helper('jQuery') ?>
    
    <form action="<?php echo url_for('test/index') ?>" >
    <fieldset>
    <legend>Test Ajax</legend>
       <table cellspacing="0">
         <tbody>
           <tr>
    	  <td>Choice 1</td>
    	  <td>
    	     <?php echo $form['choice_1']->render(array(
    		'onchange'=>jq_remote_function(array(
      		  'update'=>'choice2', //dom id
      		  'url'=>'test/ajax_select', //the action to be called
      		  'method'=>'get',
      		  'with'=>"'choice_1_id=' + this.options[this.selectedIndex].value",
    		))
      	     )) ?>
      	  </td>       
             </tr>
             <tr>
    	    <td>Choice 2</td><td><div id="choice2"><?php echo $form['choice_2'] ?></div></td>       
             </tr>
        </tbody>
    	</table>
    </fieldset>
    </form>
    
  4. In your actions.class.php add an ajax action

    public function executeAjax_select(sfWebRequest $request)
    {
    	$this->forward404Unless($request->isXmlHttpRequest());
    	$form = new myAjaxSelectForm();
    	return $this->renderPartial('test/ajax_select', array('form'=>$form));
    }
    

    then create the partial template (in this post is _ajax_select.php)

    <?php echo $form['choice_2']->render() ?>
    

Simple right?. Symfony is really rock!!! 😀
Btw thanks you for visitng my blog and reading my post.
Happy coding my friends.. 😉

Advertisements

49 responses to “how to change select options based on a choice made from another select using ajax in symfony 1.2 or higher

  1. Skyblue April 7, 2011 at 1:01 pm

    Also, sfDependentSelectPlugin doesnt seem to work with me. Can you guide me?

    BTW, your blog is very very informative. Thanks.

  2. Timo September 2, 2011 at 2:41 am

    Hello!
    Thank you very much for that post!
    I almost “accidently” stumbled upon it while i was searching for a solution to my problems with the sfDepdendentSelectPlugin which was not sufficient for my needs due to the fact that i have to get my values from a database with multiple parameters. Luckily someone mentioned this plugin in the comments 🙂
    Namely, i tried to get my values from a custom DQL (doctrine with mysql) including an inner join and an additional condition to specify a date lying between to dates in the db.

    Now i dumped my old approach and tried yours but it still won’t work. I’m pretty sure i’m almost there but something is still not working.
    I tried to integrate it into an admin generator genereted environment. I put the onChange attribute with the jQuery function call into the generator.yml which worked (surprisingly) so far, according to the site’s source code. (Fields -> -> attributes -> onChange: …) Also the function to get the database values for the drop down to be updated works . Simply the drop down is not actualised, what means to me the jQuery function is not triggered… whysoever…

    I’m still not sure why to use an inherited form (your myAjaxSelectForm). Wouldn’t it be possible to use just one form (as i did, except the fact that the form i use already inherits from the admin generator generated form in the cache).
    I guess there’s my problem… could that be ? Thank you very much in advance!
    Greetz from Germany,
    Timo

    • nibsirahsieu September 11, 2011 at 7:06 pm

      Sorry for late reply..

      Yes of course, you can move the code from ‘myAjaxSelectForm’ into ‘myForm’ class. But you have to check the request first, if it is an ajax request
      for example:

      //myForm.class.php
      public function configure()
      {
          if (sfContext::getInstance()->getRequest()->isXmlHttpRequest()) {
             unset($this['choice_1']);
             $choices = $this->updateChoices(sfContext::getInstance()->getRequest()->getParameter('choice_1_id'));
             $this->widgetSchema['choice_2'] = new sfWidgetFormChoice(array('choices' => $choices));
             $this->validatorSchema['choice_2'] = new sfValidatorChoice(array('choices' => array_keys($choices)));
          }
      }
      

      and in the action class

      public function executeAjax_select(sfWebRequest $request)
      {
          $this->forward404Unless($request->isXmlHttpRequest());
          $form = new myForm();
          return $this->renderPartial('test_ajax_select/ajax_select', array('form'=>$form));
      }
      
  3. karentojin September 3, 2011 at 4:38 am

    Thanks for you’re code!
    Did you happen to check the sfDependentSelectPlugin?

  4. Carolina September 11, 2011 at 5:02 am

    I implemented the code,,, works great! thank you very much

  5. parisss October 23, 2012 at 9:42 pm

    thanks a lot!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: