Is It Possible To Force Cgridview To Load Data Via Ajax Only?

Is there a way to make a CGridView not load data on the initial rendering of the view it lives on, and instead make it load the first data page with a subsequent AJAX request after the initial page loads?

This is mostly for performance optimization. There is a data model that is rather slow behind that CGridView, and I would like to be able to have the page load in a snappy way, then have the data load up a few seconds later with an AJAX request.

yes you can achieve this !








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

	'id'=>'msg-grid',

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

	'filter'=>$model,

    'template'=> Yii::app()->request->getIsAjaxRequest()? '{items}': '',

	'columns'=>array(

		'id',

		'sender',

		'recipient',

		'sent',

		'read',

		'subject',

		/*

		'message',

		*/

		array(

			'class'=>'CButtonColumn',

		),

	),

)); ?>

<a href="javascript:;" onclick="lazyLoadGridView()">lazyLoadGridView</a>

    <script type="text/javascript">

        function lazyLoadGridView(){

            $.fn.yiiGridView.update('msg-grid');

        }

    </script>




the key point is this line :




    'template'=> Yii::app()->request->getIsAjaxRequest()? '{items}': '',



firstly if not ajax request just use a empty template to render a gridView (just render necessary js css file ) then you can use a timer or manually to load the data of that gridView . :lol:

I got this working for my view, but unfortunately the query is still executed before the view is loaded, and then with the ajax request the query executes another time. I would like the activedataprovider to not do anything until the page is loaded, does anyone have a solution?

the reason is that in CBaseListView::init method :





public function init()

	{

		if($this->dataProvider===null)

			throw new CException(Yii::t('zii','The "dataProvider" property cannot be empty.'));


		$this->dataProvider->getData();


		..

	}



this->dataProvider->getData() cause the sql executed!

the init method eager load the data !

and in the CBaseListView::run mehod :




public function run()

	{

		..

		$this->renderKeys();


                      ..

	}



$this->renderKeys(); do fetch the data again in CGridView you can track the method calling path .

may be this problem can be settled by extend the CGridView Or CListView and rewrite the init method and the run method (just do not invoke these two methods in the extended class when the request is in ajax mode)

and another solution i thought is that : use a fake dataProvider





if(Yii::app()->request->getIsAjaxRequest()){

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

        'id'=>'msg-grid',

        'dataProvider'=> CArrayDataProvider(....),

       ///  'filter'=>$model,

    'template'=> '',

        'columns'=>array(

                 ..

               

        ),

)); 


}else{


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

        'id'=>'msg-grid',

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

        'filter'=>$model,

    'template'=>'{items}',

        'columns'=>array(

                'id',

                'sender',

                'recipient',

                'sent',

                'read',

                'subject',

                /*

                'message',

                */

                array(

                        'class'=>'CButtonColumn',

                ),

        ),

)); 


}






use a CArrayDataProvider to faking ;D just my thought and have not tested it

Thanks to the helpful suggestions in this thread, on this stackoverflow thread, and from rawtaz in the IRC live chat, I got this working. Here’s my solution:




// Controller, after creating $dataProvider, before calling $this->render...

if (!Yii::app()->request->isAjaxRequest) {

    $dataProvider->criteria->addCondition('1 = 0');

}


// View

<script type="text/javascript">

$(window).load(function() {

    $('#id-of-grid').yiiGridView('update');

});

</script>



I wanted to put up my own loading spinner. I created one using this site, display it initially, and then hide it:




// View

$this->widget('bootstrap.widgets.TbGridView', array(

    ...

    'afterAjaxUpdate'=>'function(id, data) {

        'id'=>'id-of-grid',

        'afterAjaxUpdate'=>'function(id, data) {

        $(\'#floatingCirclesG\').hide();

    }',

    ...



I also wanted to change the “No results found.” text dynamically, too. Here’s how:




// View

$this->widget('bootstrap.widgets.TbGridView', array(

    ...

    'emptyText'=>Yii::app()->request->isAjaxRequest ? 'No forms awaiting completion.' : 'Loading...',

    ...



Lastly, fwit, note that I’m using a TbGridView from the bootstrap extension, and it works fine.

Hope this helps someone!




// Controller, after creating $dataProvider, before calling $this->render...

if (!Yii::app()->request->isAjaxRequest) {

    $dataProvider->criteria->addCondition('1 = 0');

}




above code still need to query the database at the first page loading (even it return empty result ) ! so the fake array dataProvider seems still the better one .