CGridView totals row under header

Hi guys,

I have a little problem. I can’t seem to figure out how to render an additional row in CGridView, which would show the totals of each column. Now, I know that this can be easily achieved by rendering it as a footer, but would like to know if there’s a way to make it show as the second row of the grid (just under the header)…?!

Thanks in advance :)

This is possible, although you may have to iterate through all of the rows twice to calculate the totals. The reason is that the rendering of the table header is finished before the table body rendering is started, and is during the table body rendering that you can calculate totals based on the values from each row that is rendered.

If this is okay (iterating twice), you can create a new class that you will put in your ‘components’ directory that extends from CGridView. In that file, copy the renderTableHeader() function from CGridView, and modify it to add an extra row in the <thead>. See CGridView::renderTableBody() and CGridView::renderTableRow() for ways to access the data from each row.

Make sure to add the line [font=“Lucida Console”]Yii::import(‘zii.widgets.grid.CGridView’);[/font] at the top of your extended class so that Yii can import the CGridView parent class.

For example, your file may be called CGridViewWithTotals.php and the code would be similar to:


<?php


Yii::import('zii.widgets.grid.CGridView');


class CGridViewWithTotals extends CGridView

{

	/**

	 * Renders the table header. Adds a 'totals' row.

	 */

	public function renderTableHeader()

	{

		[Your code here]

	}

}



An alternative way would be to calculate the totals in the table footer as before, and then use javascript to ‘yank’ the row from the footer and ‘re-place’ it into the header.

I appreciate your help charris66 :wink:

My issue is actually a little simpler. I already have the totals for each column, I was just inquiring whether there is a quick and easy way to just "move" the footer to the top, so that it appears just under the header (ie. I want the totals row to come right after the header row). Or do I need to extends the CGridView class or something…

Please let me know…

Thanks again!

No problem alexb :wink:

So what you can do is set the ‘footer’ property of the column to the calculated total. By default this will place the total at the end of the table.




<?php


$this->widget('CGridViewWithTotals', array(

	'id'=>'my-grid',

	'dataProvider'=>$model->search(),

	'emptyText'=>'No items found.',

	'ajaxUpdate'=>false,

	//'filter'=>$model,

	'columns'=>array(

		array(

			'name'=>'field1',

			'footer'=>$total,

		),

	),

));


?>



Now you will have to extend CGridView and modify renderTableHeader() as before. Although this is breaking the semantic properties by placing the footer in the header, we won’t worry about that for now.




	public function renderTableHeader()

	{

		if(!$this->hideHeader)

		{

			echo "<thead>\n";


			if($this->filterPosition===self::FILTER_POS_HEADER)

				$this->renderFilter();


			echo "<tr>\n";

			foreach($this->columns as $column)

				$column->renderHeaderCell();

			echo "</tr>\n";


			if($this->filterPosition===self::FILTER_POS_BODY)

				$this->renderFilter();

			 

			if($this->getHasFooter())

			{

				echo "<tr>\n";

				foreach($this->columns as $column)

					$column->renderFooterCell();

				echo "</tr>\n";

			}


			echo "</thead>\n";

		}

		else if($this->filter!==null && ($this->filterPosition===self::FILTER_POS_HEADER || $this->filterPosition===self::FILTER_POS_BODY))

		{

			echo "<thead>\n";

			$this->renderFilter();

			echo "</thead>\n";

		}

	}



You could also override CGridView::renderTableFooter() if you don’t want the totals to be displayed there as well.

Thanks, this is exactly what I wanted to achieve!

No probs. B)