CGridView: Use special variable $data in the htmlOptions of a column (i.e. evaluate htmlOptions attribute)

    For each column of the CGridView, we can specify name, value, htmlOptions, cssClassExpression etc. In the declarations of the attributes value and cssClassExpression we can use the "special" variable $data, for example like this:
'value'=>'$data->author->username',.
    Now we might want to use $data in the declaration of the htmlOptions attribute, which is normally not possible, to generate for example the tag <td id="3" class="name_3">, where 3 is the id of the data model for the current row, i.e. $data->id. That is, we want to be able to use:
'htmlOptions'=>array('id'=>'$data->id', 'class'=>'"name_{$data->id}"')
    Here's a way to accomplish this...

Extend the class CDataColumn

Under protected/components/ create the file DataColumn.php with the following content:

/**
 * DataColumn class file.
 * Extends {@link CDataColumn}
 */
class DataColumn extends CDataColumn
{
	/**
	 * @var boolean whether the htmlOptions values should be evaluated. 
	 */
	public $evaluateHtmlOptions = false;
	 
	 /**
	 * Renders a data cell.
	 * @param integer $row the row number (zero-based)
	 * Overrides the method 'renderDataCell()' of the abstract class CGridColumn
	 */
	public function renderDataCell($row)
	{
			$data=$this->grid->dataProvider->data[$row];
			if($this->evaluateHtmlOptions) {
				foreach($this->htmlOptions as $key=>$value) {
					$options[$key] = $this->evaluateExpression($value,array('row'=>$row,'data'=>$data));
				}
			}
			else $options=$this->htmlOptions;
			if($this->cssClassExpression!==null)
			{
					$class=$this->evaluateExpression($this->cssClassExpression,array('row'=>$row,'data'=>$data));
					if(isset($options['class']))
							$options['class'].=' '.$class;
					else
							$options['class']=$class;
			}
			echo CHtml::openTag('td',$options);
			$this->renderDataCellContent($row,$data);
			echo '</td>';
	}
}

First note what happens to the cssClassExpression attribute: if it is set, then it is treated as an expression and is evaluated before further use. During this evaluation, expressions like $data->id are replaced with their values.

Originally the htmlOptions attribute is used without any evalution, like this:

$options=$this->htmlOptions;
...
echo CHtml::openTag('td',$options);

What we do differently from the original is:

  1. We introduce the new boolean variable $evaluateHtmlOptions to control whether the evaluation of the htmlOptions attribute should be done, or everything should remain as in the original. It defaults to false, so if nothing is given, nothing changes.
  2. We evaluate the htmlOptions, if the $evaluateHtmlOptions is set to true.
Use the class CDataColumn

We can use this new class like this:

$this->widget('zii.widgets.grid.CGridView', array(
	'id'=>'article-grid',
	'dataProvider'=>$model->search(),
	'filter'=>$model,
	'columns'=>array(
		'id',
		'title',
		array(
			'name'=>'author',
			'value'=>'$data->author->username'
		),
		array(
			'class'=>'DataColumn',
			'name'=>'sortOrder',
			'evaluateHtmlOptions'=>true,
			'htmlOptions'=>array('id'=>'"ordering_{$data->id}"'),
		),
		array(
			'class'=>'CButtonColumn',
		),
	),
));