Cgridview Filter On Hidden Field

It seems I want something odd as I am not able to find anything that matches…

Can I do this with CGridView filters:

  • filter on child.parent_id but I don’t want to display the parent_id column in the CGridView

I need to display a dropdown of parents and then related children in a CGridView.

[u]Alternate method (not preferred):

[/u]I could trigger/populate the CGridView from the onChange method of a CHtml::activeDropDown.

Can anyone point me in the right direction? How have you done this in your projects?

Thanks,

Derek

Hi,

try this




<?php

$this->widget('zii.widgets.grid.CGridView', array(

    'id' => 'utilisateur-grid',

    'dataProvider' => $model->search(),

    'filter' => $model,

    'columns' => array(

        'Login',

        'UserName',

        array('name' => 'RefGroupID',

            'value' => '$data->refGroup->NomGroupe',

            'filter' => CHtml::listData(Groupe::model()->findAll(),'GroupID','NomGroupe'),

        ),

        ...

    ),

));

?>



Have I missed something? How does this allow me to filter based on a column that is not displayed in the CGridView?

Hi.

If I understand you correctly, I would:

Have the user click on a record in the gridview.

Send the record’s id to the controller.

Let the controller get the FK of that record, and use it as a filter for the gridview.

If it makes sense, then try this wiki:

Dynamic Gridviews

@Gerhard: Thanks for the input.

I read your wiki during my research. You are using 2 CGridViews that interact. In a similar way I could use a dropdown for the parents and a CGridView for the kids. I already identified this in my ‘alternate’ method in my original post.

I am actually looking for CGridView filters to automagic the dropdown for me. Something like if the column has a filter value and display = false, then dont show the column but render a selector above the grid

Ya, that is quite difficult to do, because you might have to know beforehand in the controller what the gridview’s dataprovider will contain, and then act accordingly while still in the controller (that is why I created an identical dataprovider in the controller in the wiki).

What about using ajax to populate the dropdown only when it is clicked by the user. The ajax could read the gridview’s data first.

Or, what about reading through the dataprovider in the model’s search function (after the dataprovider was created and just before it is returned to the view). You might then be able to extract the data that needs to go in the dropdown and store it in an array in the model.

Dear DerekC

I have three approaches. I do not know which one fits your taste.

Let us assume two models. Item,Brand.

table item : id,name,b_id.

table brand : id,name.

Item.php




public function relations()

	{

		return array(

			'brand' => array(self::BELONGS_TO, 'Brand', 'b_id'),

		);

	}



1.In our first approach we can display the filter.But we are displaying the column without values.

But it is not nice looking.

views/item/admin.php




'columns'=>array(

		'id',

		'name',

		array(

		'name'=>'b_id',

		'value'=>'',

		'filter'=>CHtml::listData(Brand::model()->findAll(),'id','name'),

		),



2.In second approach we are going to modify the advanced search form in such a way that

it is going to contain only the element for b_id.

views/item/_search.




<div class="wide form">


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

	'action'=>Yii::app()->createUrl($this->route),

	'method'=>'get',

)); ?>

<?php

      /* Disable id and name.Display only field for b_id.

	<div class="row">

		<?php echo $form->label($model,'id'); ?>

		<?php echo $form->textField($model,'id'); ?>

	</div>


	<div class="row">

		<?php echo $form->label($model,'name'); ?>

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

	</div> */


?>

	<div class="row">

		<?php echo $form->label($model,'b_id'); ?>

		<?php echo $form->dropDownList($model,'b_id',CHtml::listData(Brand::model()->findAll(),'id','name')); ?>

	</div>


	<div class="row buttons">

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

	</div>


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


</div><!-- search-form -->







<?php

/* @var $this ItemController */

/* @var $model Item */


$this->breadcrumbs=array(

	'Items'=>array('index'),

	'Manage',

);


$this->menu=array(

	array('label'=>'List Item', 'url'=>array('index')),

	array('label'=>'Create Item', 'url'=>array('create')),

);


Yii::app()->clientScript->registerScript('search', "

$('.search-button').click(function(){

	$('.search-form').toggle();

	return false;

});

$('.search-form form').submit(function(){

	$.fn.yiiGridView.update('item-grid', {

		data: $(this).serialize()

	});

	return false;

});

");

?>


<h1>Manage Items</h1>


<p>

You may optionally enter a comparison operator (<b>&lt;</b>, <b>&lt;=</b>, <b>&gt;</b>, <b>&gt;=</b>, <b>&lt;&gt;</b>

or <b>=</b>) at the beginning of each of your search values to specify how the comparison should be done.

</p>


<? //change the display to block.

php echo CHtml::link('Advanced Search','#',array('class'=>'search-button')); ?>

<div class="search-form" style="display:block">

<?php $this->renderPartial('_search',array(

	'model'=>$model,

)); ?>

</div><!-- search-form -->


<?php $this->widget('zii.widgets.grid.CGridView', array(

	'id'=>'item-grid',

	'dataProvider'=>$model->search(),

	'filter'=>$model,

	'columns'=>array(

		'id',

		'name',

		array(

			'class'=>'CButtonColumn',

		),

	),

)); ?>



3.In third approach if we do not want to disturb the the alredy existing advanced search

we can do the following.

views/item/admin.php




<?php

/* @var $this ItemController */

/* @var $model Item */


$this->breadcrumbs=array(

	'Items'=>array('index'),

	'Manage',

);


$this->menu=array(

	array('label'=>'List Item', 'url'=>array('index')),

	array('label'=>'Create Item', 'url'=>array('create')),

);


Yii::app()->clientScript->registerScript('search', "

$('.search-button').click(function(){

	$('.search-form').toggle();

	return false;

});

$('.search-form form').submit(function(){

	$.fn.yiiGridView.update('item-grid', {

		data: $(this).serialize()

	});

	return false;

});


$('#subForm form').submit(function(){

	$.fn.yiiGridView.update('item-grid', {

	data:{'Item[b_id]':$('#subForm #Item_b_id').val()}

	});

	return false;

	

});

");

?>


<h1>Manage Items</h1>


<p>

You may optionally enter a comparison operator (<b>&lt;</b>, <b>&lt;=</b>, <b>&gt;</b>, <b>&gt;=</b>, <b>&lt;&gt;</b>

or <b>=</b>) at the beginning of each of your search values to specify how the comparison should be done.

</p>


<?php echo CHtml::link('Advanced Search','#',array('class'=>'search-button')); ?>

<div class="search-form" style="display:none">

<?php $this->renderPartial('_search',array(

	'model'=>$model,

)); ?>

</div><!-- search-form -->


<div id="subForm" style="margin-top:10px;">

<form>

    <div class="row">

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

		<div><?php echo CHtml::activeDropDownList($model,'b_id',CHtml::listData(Brand::model()->findAll(),'id','name')); ?></div>

	</div>


	<div class="row buttons">

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

	</div>

</form>

</div><!-- subForm -->


<?php $this->widget('zii.widgets.grid.CGridView', array(

	'id'=>'item-grid',

	'dataProvider'=>$model->search(),

	'filter'=>$model,

	'columns'=>array(

		'id',

		'name',

		array(

			'class'=>'CButtonColumn',

		),

	),

)); ?>




in third approach essentially we have added a form inside the admin.php and also registered a script to get the value from the form and to update the grid by ajax.

I hope I helped a bit.

Regards.

@seenivasan - thanks for sharing! Your input supports that I have to implement this manually.

Rgds,

Derek

Hi DerekC,

why not create your own GridColumn ?

There you can define your own filter with "renderFilterCell()" (your dropdown) and the cell content with "renderFilterCellContent()" (the childs list).

@luc

So far this is the most interesting recommendation… from my perspective. Thanks!

yeah it’a pretty cool feature:

in gridView array ‘columns’ :




		array(

			'class'=>TestColumn',

			'htmlOptions'=>array('class'=>'span2'),

		),

in protected/extension/TestColumn.php




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

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

class TestColumn extends CGridColumn

{

	public function init()

	{

		parent::init();

	}

	public $filter;

	/**

	* Renders the filter cell.

	* @since 1.1.1

	*/

	public function renderFilterCell()

	{

		echo "<td>";

		$this->renderFilterCellContent();

		echo "</td>";

	}

	

	protected function renderFilterCellContent()

	{

		echo CHtml::dropDownList('Vol[remorqueur]','remorqueur',Vol::model()->getRemorqueurs(),array(

		'prompt'=>'Avion',

		'style'=>'margin-right:10px',

		'class'=>'span2',

	));

	}

	

	protected function renderDataCellContent($row,$data)

	{

		$ajax = array(

			'type'=>'POST',

			'url'=>'setRemorqueur',

                       // here set some usefull data

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

			"success"=> "function(responseText) {

                      // update the cell content tagged with rem$row id

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

			}"

		);

                     // build the ajax for the dropdown options 'id'=>'rem'.$row, ;-)

		($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');

                    // return html

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

	}

}



Vol::model()->getRemorqueurs() : return an array of ‘id’=> ‘value’=> as CHtml::listData for the dropDownList

in controller (called by ajax request on grid cell dropdown):




	public function actionSetRemorqueur()

	{

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

		{

			// data send from ajax  'data' in renderDataCellContent($row,$data)

			$id_vol=$_POST['id_vol'];

			$id_rem=$_POST['id_rem'];

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

                        // change state from sended data

			$model->remorqueur=$id_rem;

			$model->save();

			/* 

			* here I do some some some xml search because I fetch

			* $value->immat from there

			*/

			$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>';

				}

			}

			// returns the html to update 

			echo $html;

		}

	}



CGridColumn allows you to "easily" custom CGridView !