Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yii - CGridView - add own attribute

Tags:

php

yii

$this->widget('zii.widgets.grid.CGridView', array(
    'dataProvider'=>$dataProvider,
    'columns'=>array(
        'title',          // display the 'title' attribute
        'category.name',  // display the 'name' attribute of the 'category' relation
        'content:html',   // display the 'content' attribute as purified HTML
        array(            // display 'create_time' using an expression
            'name'=>'create_time',
            'value'=>'date("M j, Y", $data->create_time)',
        ),
        array(            // display 'author.username' using an expression
            'name'=>'authorName',
            'value'=>'$data->author->username',
//HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
              'htmlOptions'=>array('class'=>'$data->author->username', 'secondAttribute' => $data->author->id),
//HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        ),
        array(            // display a column with "view", "update" and "delete" buttons
            'class'=>'CButtonColumn',
        ),
    ),
));

In option value i can add variable from PHP, but for option htmlOptions this is not possible. Why?
How can i make attribute with PHP variable?

like image 529
Dirk Fograust Avatar asked Mar 27 '12 14:03

Dirk Fograust


3 Answers

When you add arrays in the columns collection without specifying a class property, the type of column being created is CDataColumn. The property CDataColumn::value is explicitly documented to be

a PHP expression that will be evaluated for every data cell and whose result will be rendered as the content of the data cells.

Therefore, value has the special property that it gets eval'ed for each row and that's why you can set it "dynamically". This is an exception however, and almost nothing else supports the same functionality.

However, you are in luck because the property cssClassExpression is another special exception that covers exactly this usage case. So you can do it like this:

array(
    'name'=>'authorName',
    'value'=>'$data->author->username',
    'cssClassExpression' => '$data->author->username',
),

Edit: I made a mistake while copy/pasting from your example and did not notice that you were trying to do the same thing for additional attributes inside htmlOptions (I have now deleted the relevant part of the code).

If you need to add more options for dynamic values you have no choice but to subclass CDataColumn and override the renderDataCell method (stock implementation is here).

like image 150
Jon Avatar answered Nov 17 '22 02:11

Jon


Don't know if this still applies or not (given that there is an accepted answer), but there is a slightly better solution in the form of "rowHtmlOptionsExpression". This specifies an expression that will be evaluated for every row. If the result of the eval() call is an array, it will be used as the htmlOptions for the <tr> tag. So you can basically now use something like this:

$this->widget('zii.widgets.grid.CGridView', array
(
   ...
   'rowHtmlOptionsExpression' => 'array("id" => $data->id)',
   ...

All your tags will have an id attribute with the records' PK. Just modify the jQuery slightly to obtain the id from that tag instead of an extra column and you should be set.

like image 5
Blizz Avatar answered Nov 17 '22 03:11

Blizz


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

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',
        ),
    ),
));
like image 2
nsv Avatar answered Nov 17 '22 03:11

nsv