Using a custom grid cell to display ajax dropdown populated with xml data

This topic to explain how I 've managed to:

in a gridview, for each row (model item), display a dropdownList (created from a xml file), and update the given model item via an ajax call while changing the dropdown.

A custom CGridColumn class:

Note: ‘#rem$row’ id is the one to be updated in the gridview.




Yii::import('zii.widgets.grid.CGridColumn');

class DropDownColumn extends CGridColumn

{

	protected function renderDataCellContent($row,$data)

	{


//building the ajax link and parameters

		$ajax = array(

			'type'=>'POST',

			'url'=>'pdv/setRemorqueur',

			'data'=>array('id_rem'=>'js:this.value','id_vol'=>$data->id),

			"success"=> "function(responseText) {

				$('#rem$row').html(responseText);

			}"

		);

//building options for the dropdown 

		($data->remorqueur!=null)?

			$options=array('ajax'=>$ajax, 'class'=>'span2','id'=>'rem'.$row,'options'=>array($data->remorqueur=>array('selected'=>'selected')))

			:$options=array('ajax'=>$ajax, 'class'=>'span2','id'=>'rem'.$row,'prompt'=>'Select');

// display the dropdown

		echo CHtml::dropDownList('model', 'remorqueur', Vol::model()->getRemorqueurs(),$options);

	}

}



In the gridview, for my column:




		array(

			'class'=>'DropDownColumn',

			'header'=>'Remorqueur',

		),



In the controller:




	public function actionSetRemorqueur()

	{

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

		{

//making the change

			$id_vol=$_POST['id_vol'];

			$id_rem=$_POST['id_rem'];

			$model=$this->loadModel($id_vol);

			$model->remorqueur=$id_rem;

			$model->save();

//building the new dropdown from an xml file

			$html='';

			$aeronefs = simplexml_load_file('xml/aeronefs.xml');

			foreach($aeronefs as  $value)

			{

				if ((string) $value->remorqueur == '1' && $value->actif == '1') 

				{

					if($value->id_aeronef != $id_rem)

						{

							$html=$html.'<option value="'.$value->id_aeronef.'">'.$value->immat.'</option>';

						}

					else $html=$html.'<option value="'.$value->id_aeronef.'" selected="selected">'.$value->immat.'</option>';

				}

			}

// render the updated dropdown

			echo $html;

		}

	}



for a global use, I’ve imported my new DropDownColumn in the main config file in the “import” part.

All of this works fine, but I’m not sure if it fits the bests practices.

Next challenge: display the filter in the header to search through $model->remorqueur field … (help welcome ;-))

Thanks for your tip. Will give it a try someday.

For your challenge, you may look here.

@tellibus, the challenge isn’t here:

while modifying my column in the gridview like this:




		array(

			'class'=>'DropDownColumnColumn',

			'header'=>'Remorqueur',

			'filter'=>CHtml::activeDropDownList($model, 'remorqueur', CHtml::listData(Vol::model()->findAll(),'remorqueur','immat'),array('prompt'=>'','class'=>'span1')),

		),



I receive a "property DropDownColumn.filter is undefined".

Well ‘header’ property is in CGridColumn and this work as expected but ‘filter’ is defined in CGridView. I’ve tried to


Yii::import('zii.widgets.grid.CGridView');

in my custom cell code with no luck

I see. Have you tried to put your filter [font=“Courier New”]CHtml::activeDropDownList($model, ‘remorqueur’, CHtml::listData(Vol::model()->findAll(),‘remorqueur’,‘immat’),array(‘prompt’=>’’,‘class’=>‘span1’))[/font] in renderFilterCellContent() in your custom DropDownColumn?

Yes, this is what I have done, and the dropdown select is displayed. But the filter function (search) doesn’t work yet.

As far as I know you need a [font=“Courier New”]name[/font] attribute in your column item in order to search using the filter. I think you should declare a public property in your model and assign it to the ‘name’ attribute of your column, like that:


array(

  'header'=>'Remorqueur',

  'class'=>'DropDownColumnColumn',

  'name'=>'remorqueur_search',

)

In your model


public $remorqueur_search;

…

public function rules()

{

  return array(

  …

    array('…, remorqueur_search', 'safe', 'on'=>'search')

  );

}

…

public function search()

{

  $criteria=new CDbCriteria;

  $criteria->with = array('…', 'vol'); // 'vol' should be your relation name

  …

  $criteria->compare('vol.remorqueur', $this->remorqueur_search, true); // true for partial string comparison

  …

}



Anyway, I believe you already know how to do that. In any case, you may check this wiki.

Thanks for the help !

Because I’ve got other plans for this afternoon, I will check that this evening.

So Luc have you solved your issue?

@bennouna, thank you for taking care of my problems. Unfortunately, I’m really busy with my professionnal work (wich has nothing to do with coding ;))