Yii 1.1: Insert a multirow header in CGridView

5 followers

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

Total 2 comments

#14619 report it
Peppe at 2013/08/29 07:03am
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;
#14228 report it
glyph at 2013/07/28 11:42am
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.

Leave a comment

Please to leave your comment.

Write new article
  • Written by: Peppe
  • Category: How-tos
  • Yii Version: 1.1
  • Votes: +6
  • Viewed: 10,295 times
  • Created on: Jul 9, 2013
  • Last updated: Sep 4, 2014
  • Tags: CGridView, extending