The CGridView widget is very useful and customizable, but sometimes you need a little more. One limit I found is to have only one row for headers; yes, you can write each column header in more than one row, but just inside the single cell. I was looking instead for the possibility to use more than one row, with different structure one from the others. This way you can write columns grouping headers, and obtain a nicer view.
Extending CGridView. ¶
First I was scared about the idea of extending a widget (I'm a newbie in Yii), but it's easier than I thought.
Below there is the code.
The core is the overriding of renderTableHeader()
function, but first there is a new parameter to insert in the class properties: addingHeaders
.
This parameter is an array in which each element represents a single header row and is, again, an array containing the single cells definition. Each cell has the text (key) to be viewed as header and the number (value) of columns to span across.
Clearly, the total width (summing up the values) of each header row, cannot be more than the real number of columns. Can be less... if you like it.
The "normal" header row, as defined in the usual column header attributes, is rendered after the added rows.
Configuring the application. ¶
The file, as usual, is to be saved in the components
folder, with CGridViewPlus
as name.
Finally you have to declare it in the configuration file main.php
, adding this row in the components
section:
'CGridViewPlus' => array('class' => 'components.CGridViewPlus',),
Using it. ¶
The use of this feature is very easy. The widget has to be called this way:
$this->widget('CGridViewPlus', array(
... and in the list of properties you can add the new parameter as explained before:
'addingHeaders' => array(
array('group A' => 2, 'group B' => 5), // first row
array('sub j' => 3, 'sub k' => 2, 'sub l' => 2), // second row
),
The code. ¶
<?php
Yii::import('zii.widgets.grid.CGridView');
class CGridViewPlus extends CGridView {
public $addingHeaders = array();
public function renderTableHeader() {
if (!empty($this->addingHeaders))
$this->multiRowHeader();
parent::renderTableHeader();
}
protected function multiRowHeader() {
echo CHtml::openTag('thead') . "\n";
foreach ($this->addingHeaders as $row) {
$this->addHeaderRow($row);
}
echo CHtml::closeTag('thead') . "\n";
}
protected function addHeaderRow($row) {
// add a single header row
echo CHtml::openTag('tr') . "\n";
// inherits header options from first column
$options = $this->columns[0]->headerHtmlOptions;
foreach ($row as $header => $width) {
$options['colspan'] = $width;
echo CHtml::openTag('th', $options);
echo $header;
echo CHtml::closeTag('th');
}
echo CHtml::closeTag('tr') . "\n";
}
}
?>
Sorry for my bad english.
Peppe
Tweaks
Greetings,
I have added some features to your component to enable passing htmlOptions for each header cell.
The updated component here:
<?php Yii::import('zii.widgets.grid.CGridView'); class CGridViewPlus extends CGridView { public $addingHeaders = array(); public function renderTableHeader() { if (!empty($this->addingHeaders)) $this->multiRowHeader(); parent::renderTableHeader(); } protected function multiRowHeader() { echo CHtml::openTag('thead') . "\n"; foreach ($this->addingHeaders as $row) { $this->addHeaderRow($row); } echo CHtml::closeTag('thead') . "\n"; } // each cell value expects array(array($text,$colspan,$options), array(...)) protected function addHeaderRow($row) { // add a single header row echo CHtml::openTag('tr') . "\n"; // inherits header options from first column $options = $this->columns[0]->headerHtmlOptions; foreach ($row as $header) { $options['colspan'] = $header['colspan']; $cellOptions=($header['options'] + $options); echo CHtml::openTag('th', $cellOptions); echo $header['text']; echo CHtml::closeTag('th'); } echo CHtml::closeTag('tr') . "\n"; } } ?>
Use it as follows in your view:
$dataProvider=$model->search(); $columns=array(); $columns[]= array( 'name' => 'id', 'value'=>'$data->id', 'type' => 'raw', 'htmlOptions'=>array('style'=>'width:90px;'), ); $columns[]= array( 'name' => 'id', 'value'=>'foo', 'type' => 'raw', 'htmlOptions'=>array('style'=>'width:90px;'), ); $this->widget('CGridViewPlus', array( 'id'=>'isolate-search', 'filter'=>$model, 'dataProvider'=>$dataProvider, 'columns'=>$columns, 'addingHeaders' => array( array( array('text'=>'cell 1','colspan'=>2,'options'=>array('class'=>'sample-header-class')), array('text'=>'cell 2','colspan'=>3,'options'=>array('class'=>'another-header-class')), array('text'=>'cell 3','colspan'=>4,'options'=>array('class'=>'yet-another-class')) ), ), ));
(where sample-header-class etc are css classes)
All the best and thanks for the lovely code.
missing zero column
Sometimes (don't know why yet) the columns[0] is not defined in the grid, so it produce an error.
To avoid this error you have to substitute this row:
$options = $this->columns[0]->headerHtmlOptions;
whit this code:
$fcol = 0; while (!isset($this->columns[$fcol])) { $fcol++; } $options = $this->columns[$fcol]->headerHtmlOptions;
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.