Style columns in CGridView based on data in yii - php

Is it possible to style CGridView based on data?
For example these two cases:
Or I have to use other options?

Yes, you can specify css class by data. Use cssClassExpression option.
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider,
'columns'=>array(
// ...
array(
'name'=>'Delta',
'value' => $data->value,
'cssClassExpression' => '$data->delta > 0 ? "up" : "down"',
),
// ...
),
));

as clear from other answers that cssClassExpression can be used for this purpose. I think there would be many if statements so that you cant use inline if statements for cssClassExpression.
I would do it in this way.
1. First define a method in your model like
public function checkColour()
{
if('value'<10)
{
return 'green quarter'
}
if('value'>10)
{
return 'yellow half'
}
}
Basically this method is returning class names you have created and want to use for specific condition.
2. Then i would use it like
'columns'=>array(
array(
'name'=>'nozare',
'cssClassExpression' => '$data->checkColour()'
),
),

You can do that by using cssClassExpression
array(
'name' => 'status',
'value' => '$data->status0->title',
'cssClassExpression' => call a function or do by expression,
),
By that you can set different class for different row and write corresponding css for that

Related

Accessing value of indirectly related models

I am displaying a CGridView below CDetailView on view.php page for Company model. I have problem in displaying values in CGridView using company details. The company model has an array of CompanyAddresses which is used as CArrayDataProvider for CGridView.
$config = array();
$dataProvider = new CArrayDataProvider($rawData=$model->companyAddresses,$config);
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$dataProvider
, 'columns'=>array(
//'id',
array('header'=>'SN.',
//'value'=>'++$row', // may nt work with pagination but the below does work
'value'=>'$this->grid->dataProvider->pagination->currentPage * $this->grid->dataProvider->pagination->pageSize + ($row+1)',
),
'address',
array(
'name'=>'Tehsil',
//'value'=> Utility::getTehsilName(Tehsil::model()->findByPk('tehsil_id')),
'value'=> Utility::getTehsilName($this->loadModel('tehsil_id')),
//'value'=> Tehsil::model()->findByAttributes( array('id' => 'tehsil_id' ) )->name,
),
array(
'name'=>'address_tag_id',
'value'=>AddressTag::model()->findByPk('address_tag_id'),
),
)
));
I am not able to fetch Tehsil_Name from Tehsil Table which has its ID inside CompanyAddress table.
Your using value attribute is wrong, check this:
'value'=>function($data){
return Utility::getTehsilName($data->tehsil_id);
},
value is a php expression that is evaluated to produce the contents of the gridview cell as below
'value' => 'Utility::getTehsilName($this->grid->controller->loadModel($data->tehsil_id))'
If you had used relation chaining to solve this your expression would have been simplified to say:
'value' => '$data->model1->tehsil->name'
where model1 is the middle relation.

Create Custom Row in yii Cgridview

I had created a yii Cgridview but how to make custom row in the it. I want to make the custom row whose data is static not related to database?
the problem is similar to below
http://www.yiiframework.com/forum/index.php/topic/47751-insert-first-row-in-cgridview/
insert static first row in cgridview yii
Check this grid row
array(
'name'=>'some_name',
'value'=>'$data->getCountryNameOrStaticStringOrWhatever()',
),
In model
public function getCountryNameOrStaticStringOrWhatever(){
return 'my static content or whatever';
}
you can do it with javascript and jQuery:
add 'afterAjaxUpdate' => 'addStaticRaw', to CGrid config
and register js script:
function addStaticRaw(){
$('#party-ledger-grid tbody tr:first').before("<tr><td>Your static raw blah blah</td></tr>");
}
I was looking for a similar solution and came across this:
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'something',
'dataProvider'=>$provider,
'columns'=>array(
array(
'name' => 'name',
'header' => 'Name',
'footer' => 'name column for extra row',
),
array(
'name' => 'email',
'header' => 'e-Mail',
'footer' => 'email column for extra row'
),
)
)
Simply fill out the footer elements of each column with the data from you extra row.
It works like a charm!

Yii: TbEditableColumn how to pass $data->id

I am trying to use the TbEditableColumn and the type select to have a pulldown menu.
The pulldown menu I need is filled by a function that I call.
That is working for basic cases. But for a another column, the pulldown values are dependent from the row in which it is (grid-view).
So for example the function I want to call to fill the pulldown and pass the id of the current data is:
$model->getPulldownValues($data->id)
But that throws an error that the variable $data is not defined. The funny part is that outside the editable array, I can use $data as expected.
See example below:
Any ideas?
$this->widget('bootstrap.widgets.TbExtendedGridView', array(
'type' => 'striped bordered',
'id'=>'order-image-grid',
'dataProvider'=>$model->search(),
'ajaxUpdate'=>true,
'template' => "{items}\n{extendedSummary}",
'rowCssClassExpression'=>'"FMDBGridColumn".$data->order_error',
'columns'=>array(
array(
'class' => 'bootstrap.widgets.TbEditableColumn',
'name' => 'streets',
'htmlOptions'=>array('width'=>'150'),
'value' => 'CHtml::value($data, "street")',
'editable' => array(
'type' => 'select',
'source' => CHtml::listData($model->availableStreets($data->id), 'id', 'street'),
'url' => $this->createUrl('cities/editable'),
'placement' => 'right',
)
),
),
));
Try to change method "availableStreets" into getter, e.g.:
public function getAvailableStreets()
{
// we don't need to send id as parameter of method,
// we can get it directly from model
// e.g.: $id = $this->id;
//
// put your code here
}
then, in widget, use property
$model->availableStreets
instead of method
$model->availableStreets($id)
Also you can put
CHtml::listData() into your getter and use
'source' => 'availableStreets',
instead of
'source' => CHtml::listData($model->availableStreets($data->id), 'id', 'street'),
you have to consider that $data in 'value' => 'CHtml::value($data, "street")', is referring to a model object which $model->search() is providing, but $data outside of the grid is different(You haven't shared what that is).

Data isn't displaying from another table in CGridView Widget

I have two table Event and EventCategory. I am using zii.widgets.grid.CGridView widget to display all the events in the admin section.
I have created the following relations between tables.
Relation in EventCategory model:
'event' => array(self::HAS_MANY, 'Event', 'category_id'),
Relation in Event model:
'category' => array(self::BELONGS_TO, 'EventCategory', 'category_id'),
The following code I am using to display the Events:
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'event-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'summaryText'=> '',
'columns'=>array(
array('header'=>'Id','name'=>'event_id','filter'=>''),
'event_code',
'category.evntcatm_name',
'event_name',
array(
'class'=>'CButtonColumn',
'htmlOptions'=>array('class'=>'actions aligncenter'),
'deleteButtonImageUrl'=>false,
'updateButtonImageUrl'=>false,
'viewButtonImageUrl'=>false
),
),
)); ?>
'category.evntcatm_name' doesn't display anything. It is just creating the blank column with NO ERROR. What I am missing here.
Please try something like it
$data->category->evntcatm_name
You should use code like this:
'columns' = array(
/*YOUR DATA*/
array(
'name' => 'category_id',
'value' => function($data) {
return !empty($data->category) ? $data->category->evntcatm_name : null;
}),
)
This way can solve your problem with "Trying to get property of non-object". If you see blank cell in grid that means you miss relation (or it doesnt exist, in this way you should check relation condition or database)
Here is a few wild guesses:
Is category.evntcatm_name correctly spelled?
Is there actually data in the evntcatm_name field to begin with?
I know it might sound too simple to miss, but the error almost has to be on that level.
Try finding a category using the primary key and output it's evntcatm_name.
$cat = EventCategory::model()->findByPk(1);
echo $cat->evntcatm_name;
Maybe if you could share your schema for those two tables?
You can use
array(
'header' => 'Category Title',
'value' => '$data->category->evntcatm_name'
),
instead of 'category.evntcatm_name'
The model instance is not object now in the Cgidview:
Try
$data['category']['evntcatm_name'];

Yii - CGridView - add own attribute

$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?
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).
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.
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',
),
),
));

Categories