CGridView with Ajax: best practice?

Hi everybody

I’d like to discuss with you the most right way of using CGridView with ajax.

May be it looks like article (too many letters below)), but I assume it can be intresting for you and I’d like to get your ideas.

So I will describe 3 approaches that I see for using cgridview.

But unfortunatly each has some problems(

I want to underdstand what is the best one.

The task is very common:

[i]I need page with several sections, and one section should contain grid.

I want to be able to use sorting and pagination via ajax. Also I want to refresh grid from JS code. [/i]

[color="#006400"]Approach 1 - "Solution by CRUD Generator":[/color]

Standart crud generator creates one action in admin controller and one view.

In controller:




	public function actionAdmin()

	{

		$model=new Product('search');

		$model->unsetAttributes();  // clear any default values

		if(isset($_GET['Product']))

			$model->attributes=$_GET['Product'];


		$this->render('admin',array(

			'model'=>$model,

		));

	}



view admin.php:




...

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

	'id'=>'product-grid',

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

	'filter'=>$model,

...



[color="#FF0000"]Problem[/color]:

Every time you click on sorting or pagination you are getting whole html of your page! And only little piece of html for gridview is used! Not optimal I think…

[color="#006400"]Approach 2 - "Everything via Ajax":[/color]

to solve the problem above let’s create a specific action that will return only gridview

(use renderPartial() instead of render()):




	public function actionGrid()

	{

             if(!Yii::app()->request->isAjaxRequest) throw new CHttpException('Url should be requested via ajax only');

		$model=new Product('search');

		$model->unsetAttributes();  // clear any default values

		if(isset($_GET['Product']))

			$model->attributes=$_GET['Product'];


		$this->renderPartial('_grid',array(

			'model'=>$model,

		));

	}



And in main view (e.g. admin.php) I create div and make ajax for gridview on page load.

admin.php:




...

  <div id="grid-container"></div>


  yii::app()->clientScript->registerScript('load-grid', ' 

      $("#grid-container").load("product/grid");

  ');  

...



Looks pretty but not works! :)

[color="#FF0000"]Problem[/color]:

renderPartial does not return CSS and JS files required for grid, only html!

Ok. lets use it with additional params called "process output":




$this->renderPartial('[color="#FF0000"]_grid[/color]',array(

			'model'=>$model,

		), false, true);



Seems good. But lets look in firebug: ohh, every time I use sorting or pagination of my grid JQuery and other js files are loaded!

To prevent it I need to load all js files once. There is an extension for this. It works fine, but I am expecting from Yii to solve it with standart functionality…

[color="#006400"]Approach 3 - "Everything via Ajax except first":[/color]

In this case first time grid is loaded from normal GET request and all other times via ajax.

Action in controller nearly the same but without check for ajax only request:




	public function actionGrid()

	{

                $model=new Product('search');

		$model->unsetAttributes();  // clear any default values

		if(isset($_GET['Product']))

			$model->attributes=$_GET['Product'];


		$this->renderPartial('_grid',array(

			'model'=>$model,

		));

	}



in main view admin.php directly call actionGrid:




...

  <div id="grid-container"><?php $this->actionGrid(); ?></div>

...



in _grid.php ajaxUrl should be defined. Also route for pagination should be set manually (otherwise pages will have wrong url):




...

<?php 

   $dataProvider = $model->search();

   $dataProvider->pagination->route = 'product/grid';


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

	'id'=>'product-grid',

	'dataProvider'=>dataProvider ,

	'filter'=>$model,

        'ajaxUrl' => array('product/grid'),

...



[color="#FF0000"]Problem:[/color]

  1. Seems non standart and ugly(

  2. if you call from JS: yiiGridview.update() - you will always get the 1st page of unsorted grid!

Thats it! No ideal solution from my curent view…

Wich approach do you prefer in you projects?

Your comments and ideas are really appreciated!

I’m working on a similar situation as your approach 2.

But my renderPartial works fine (my grid has CSS and paging etc.) because I’m not rendering the grid directly but a separate view which contains the grid.

But looking at your code, you are doing the same (except if your _grid is not a separate view). So why would your approach 2 not work?

For those interested, there is a working example here:

http://www.yiiframework.com/wiki/323/dynamic-parent-and-child-cgridciew-on-single-view-using-ajax-to-update-child-gridview-via-controller-with-many_many-relation-after-row-in-parent-gridview-was-clicked/

what’s the beneficial you use Yii API to do Ajax stuff over pure jQuery ajax calling?