Make Row of CGridView become a link

For better usability purpose, I intend to make the row of CGridView become a link, rather than using CLinkColumn. Is that possible to make the row become link, and how to do it?

Thanks before…

an option is extend CGridView and override renderTableRow, doing something with tr tag:

<tr onclick="…">

My answer in this thread might lead you to one possible solution.

/Tommy

@Flavio

I’ve read read renderTableRow() but I don’t know how to override it. Could you please provide a little example to me??

@Tri

From that thread, it seems like the code put a checkbox or a link into a column, while what I need is to make the row itself become a link, so not only the column. But thanks anyway :)

Overriding Yii object is really easy.

First of all you have to create a file like MyGridView.

Here we write this code:




class MyGridView estends CGridView

{

	/**

	 * Renders a table body row.

	 * @param integer the row number (zero-based).

	 */

	public function renderTableRow($row)

	{

		if($this->rowCssClassExpression!==null)

		{

			$data=$this->dataProvider->data[$row];

			echo '<tr class="'.$this->evaluateExpression($this->rowCssClassExpression,array('row'=>$row,'data'=>$data)).'">';

		}

		else if(is_array($this->rowCssClass) && ($n=count($this->rowCssClass))>0)

			echo '<tr class="'.$this->rowCssClass[$row%$n].'">';

		else

			echo '<tr>';

		foreach($this->columns as $column)

			$column->renderDataCell($row);

		echo "</tr>\n";

	}


}



The code of renderTableRow has been copied from CGridView (you can find it in your copy of the framework).

Now you have to change this code in order to fit your needs, in detail you can change all the <tr> tags and add the onClick.

Of corse your views should call MyGridView (place it in components) instead of CGridView

hello,

the easy way is to config your CGridView in the view file

inside the view file

<?php

$this->widget(‘zii.widgets.grid.CGridView’, array(

‘dataProvider’ =>$data,

‘columns’=>array(

		array('name'=&gt;'Name',


			  'type'=&gt;'raw',


			  'value'=&gt;'CHtml::encode(&#036;data-&gt;name)'),


		


		array('name'=&gt;'Surname',


			  'type'=&gt;'raw',


			  'value'=&gt;'CHtml::encode(&#036;data-&gt;surname)'),


		


		


		


		[size=&quot;5&quot;]array('name'=&gt;'Edit',


			  'type'=&gt;'raw',


			  'value'=&gt;'CHtml::link(&quot;&#036;data-&gt;id&quot;,&quot;index.php?r=admin/edit/id/&quot;.CHtml::encode(&#036;data-&gt;id))'[/size]


			  


		


		)),

?>

just use the CHtml::link method and insert the parameters

cheers

@binkabir this way only a column is clickable… the objective is become the entire row a link

@junxiong ´ll try here and let you know if i succeed

Problem is that by standards you cannot put an <a> (link) tag around <tr> (table row) tag.

So by using XHTML you can only make a link inside every column in a row, but that as you wrote above is not what you want…

So for your need you can use jQuery…

yeah you’re right. I understand that it will need a javascript or jquery code to achieve that. Just I don’t know how to put the script to CGridView’s <tr>

But zaccaria has provided the code to tell me how to override it. So I think, I will try it first.

I’ve done this for a table that had a CButtonColumn using a quick jquery hack like this:




$(".items tbody tr").live("click", function(){

  window.location.href = $(this).find(".view").attr("href");

});



If you can find some way to grab an ID or a URL from the TR that you click on, you can do something like this. Just my two cents… Also, FYI, this does not work on an iPad for whatever reason.

I’ve succeeded make row become link. Thanks to all’s replies.

I created a file named GGridView.php in components folder and here the codes.




<?php

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


class GGridView extends CGridView

{

        /**

         * Renders a table body row.

         * @param integer the row number (zero-based).

         */

        public function renderTableRow($row)

	{

                Yii::app()->clientScript->registerScriptFile(bu().'/js/main.js');//js file that contain showView() function

                $tmp = $this->dataProvider->data[$row];

                $link = "'".Yii::app()->createUrl(Yii::app()->controller->id."/view",array("id"=>$tmp->id))."'";


		if($this->rowCssClassExpression!==null)

		{

			$data=$this->dataProvider->data[$row];

			echo '<tr onclick="showView('.$link.')" class="'.$this->evaluateExpression($this->rowCssClassExpression,array('row'=>$row,'data'=>$data)).'">';

		}

		else if(is_array($this->rowCssClass) && ($n=count($this->rowCssClass))>0){

                        echo '<tr onclick="showView('.$link.')" class="'.$this->rowCssClass[$row%$n].'">';

                }else{

                        echo '<tr onclick="showView('.$link.')" >';

                }


		foreach($this->columns as $column)

			$column->renderDataCell($row);

		echo "</tr>\n";

	}


}

?>



Your solution is a good one too, Jaz. But do you mean using your way, there no need to override the CGridView? Coz I don’t understand how to put the URL in the TR without overriding it.

I liked most Jaz Manister solution:

In your grid rows make <a> id prefixed by "foo":




<a id="foo'.$data->id.'" >link</a>



anywhere in your view:




<script>

$(".items tbody tr").live("click", function(){

  window.location.href = $(this).find("a[id^='foo']").attr("href");

});

</script>



I see… yeah… that’s a good one.

So there is no need to extends the CGridView class

Hi,

Here is one more solution.




<?php $this->widget('zii.widgets.grid.CGridView', array(

    ...

    'htmlOptions'=>array(style=>'cursor: pointer;'),

    'selectionChanged'=>"function(id){window.location='" . Yii::app()->urlManager->createUrl('controller/action', array('id'=>'')) . "' + $.fn.yiiGridView.getSelection(id);}",

    ...

)); ?>



This is awesome, fast in both browser(firefox & IE) and iPhone! perfect for iPhone for saving space!

Is it possible to grab another value then the primary key?

[color="#FF0000"]This is the best solution! Awesome! Thanks Cyanide![/color]

There is one problem with this solution. After clicking a row, click back in your browser. The row will still be "selected". When you click the row now, getSelection() will return empty.

I’m using the following more robust solution. This will work for any grid view in the page that also has a column with a button .view.


Yii::app()->clientScript->registerScript('CGridView-ClickableRows', '

	$(".grid-view tbody > tr").on("click", function(e){

		var targetIsLink = $(e.target).closest("a").length;

		var $view = $(this).find(".view");

		if (!targetIsLink && $view) {

			window.location.href = $view.attr("href");

			return false;

		}

	});

');

Note: If you use the default ajaxUpdate behavior, use live delegation:


$("body").on("click", ".grid-view tbody > tr", function(e){

Also, add a css class like this:


.clickableGridView tbody > tr :hover {cursor: pointer;}


The solution with comments:


Yii::app()->clientScript->registerScript('CGridView-ClickableRows', '

	// target only the tr in the tbody, and use live delegation

	$(".grid-view tbody > tr").on("click", function(e){

		// are we not clicking any other link in the row? (for example, an update button)

		var targetIsLink = $(e.target).closest("a").length;


		// does this row have a view button? (for example, empty text row does not)

		var $view = $(this).find(".view");


		// if conditions are met, redirect now and prevent event bubbling

		if (!targetIsLink && $view) {

			window.location.href = $view.attr("href");

			return false;

		}

	});

');