Hi, habrasoobschestvo!
In this topic, I want to discuss the most appropriate use of the
CGridView component in Yii.
Below I will describe 3 ways that I personally see, and I will be glad to hear your ideas in the comments.
')
So, the
task :
A page with several blocks is required, one of which must have a table (grid).
Need the ability to sort and page-by-page navigation of the grid via ajax.
It sounds easy, is not it? Let's see what Yii offers us.
Method 1. Standard CRUD Generatror
The generated code contains 1 action in the controller and 1 view:
Controller:
public function actionAdmin() { $model=new Product('search'); $model->unsetAttributes();
index.php :
... <?php $this->widget('zii.widgets.grid.CGridView', array( 'id'=>'product-grid', 'dataProvider'=>$model->search(), 'filter'=>$model, ...
In general, everything works, but
every time you use ajax sorting or navigation in the grid, the server returns the full html-code of the page! From which only a small html-piece is used to update the grid. If the page contains several elements (for example, one more grid), then all of them on the server side are processed for nothing. Not the most optimal solution in my opinion.
Method 2. All through Ajax
To solve the problem of method 1, create a separate action and view to form a grid. They will work only through Ajax and return the content via the renderPartial () method, which will leave only the necessary html for the grid:
Controller:
public function actionGrid() { if(!Yii::app()->request->isAjaxRequest) throw new CHttpException('Url should be requested via ajax only'); $model=new Product('search'); $model->unsetAttributes();
_grid.php contains only the widget code:
... <?php $this->widget('zii.widgets.grid.CGridView', array( 'id'=>'product-grid', 'dataProvider'=>$model->search(), 'filter'=>$model, ...
and
index.php pulls up the grid when the page first loads:
<div id="grid-container"></div> yii::app()->clientScript->registerScript('load-grid', ' $("#grid-container").load("product/grid"); ');
It looks neat, but does not work :)
The renderPartial () method does not return the necessary JS and CSS files to the grid! Only Html.
But stop! RenderPartial () has an additional parameter, called “process output”, which allows you to return js and css.
Change
in the controller :
public function actionGrid() { if(!Yii::app()->request->isAjaxRequest) throw new CHttpException('Url should be requested via ajax only'); $model=new Product('search'); $model->unsetAttributes();
We
load the page and again we see bjaku:
jquery.js and the rest of the scripts start loading every time we update the grid via ajax!
Of course, they should be loaded once, but renderPartial () returns them regularly with each request.
How to disable reloading scripts? To do this, you can put a separate
extension , which, with ajax requests, cuts out the scripts already loaded on the page.
Voila, it works! But personally, I expect Yii to solve this problem by standard means, without extensions ...
Method 3. All through Ajax, except for the first time
And what if for the first time to load the grid with a regular request, and then update via ajax?
In the controller, everything remains almost unchanged, just remove the isAjaxRequest check and in the renderPartial without additional parameters:
public function actionGrid() { if(!Yii::app()->request->isAjaxRequest) throw new CHttpException('Url should be requested via ajax only'); $model=new Product('search'); $model->unsetAttributes();
In the main
index.php view, we directly call the actionGrid ():
<div id="grid-container"><?php $this->actionGrid(); ?></div>
and in
_grid.php we set the
ajaxUrl parameter for future update of the grid. Otherwise, ajaxUrl will be taken from the current url (for example, product / index):
$this->widget('zii.widgets.grid.CGridView', array( 'id'=>'product-grid', 'dataProvider'=>$model->search() , 'filter'=>$model, 'ajaxUrl' => array('product/grid'), ...
We look at the result:
initially the grid loads correctly, but navigation does not work!
Links from pages continue to point to product / index instead of product / grid. Studying the yii code showed that the
links in the pagination are not related to the ajaxUrl parameter and are taken from the current request . Which at the first boot is not the same, because we call another from one action. In my opinion, such a challenge is not even ideologically correct.
But nowhere to go, we fix it by setting the route parameter in the data provider pagination object:
_grid.php :
<?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($dataProvider->pagination->route), ...
Now almost everything is as it should. Grid is loading, sorting and navigation work.
But there was a fly in the ointment:
if the grid is somehow sorted and is not on the first page, and we trigger its update via js:
$("#product-grid").yiiGridView("update");
then it is reset to the first page with standard sorting. It's a shame, isn't it? This is because
ajaxUrl is explicitly specified and update always sends a request for it. But
if you do not specify ajaxUrl, then when updating the grid, it saves the current page and sorting ! Because inside the grid, the url for which it was obtained is stored (specifically, in the title attribute diva with keys). But it is also impossible not to specify ajaxUrl, since then requests will go to the source url of the grid, i.e. product / index.
The only solution that occurred to me is to change the very title during the first (non-ajax) grid formation. And do not specify ajaxUrl at all.
The final
_grid.php looks like this:
<?php $dataProvider = $model->search(); $dataProvider->pagination->route = 'product/grid'; $this->widget('zii.widgets.grid.CGridView', array( 'id'=>'product-grid', 'dataProvider'=>$dataProvider , 'filter'=>$model,
Now everything works as it should! Only embarrassed by the presence of the above crutches.
Conclusion
I would like to hear your ideas / comments on the methods above and on the use of grids in your yii projects.
Thanks for attention!