DropDown for pageSize in CGridView


(Mh) #1

I found myself in the need for a dropDownList to select the page size on a CGridView. I was amazed that only a few lines of code where required. So i thought i’d share.

On top of my controller action for the gridview (if you used CRUD, this is actionAdmin() ) i added:


// page size drop down changed

if (isset($_GET['pageSize'])) {

    Yii::app()->user->setState('pageSize',(int)$_GET['pageSize']);

    unset($_GET['pageSize']);  // would interfere with pager and repetitive page size change

}



In the model (e.g. model/User.php) the data provider in search() is configured like:


return new CActiveDataProvider(get_class($this),array(

    'pagination'=>array(

        'pageSize'=> Yii::app()->user->getState('pageSize',Yii::app()->params['defaultPageSize']),

    ),

    'criteria'=>$criteria,

));



And finally the view (e.g. views/user/admin.php) :





<?php 

// put this somewhere on top

$pageSize=Yii::app()->user->getState('pageSize',Yii::app()->params['defaultPageSize']); ?>


<?php

// we use header of button column for the drop down

// so change the CButtonColumn in columns array like this:

...

array(

    'class'=>'CButtonColumn',

    'header'=>CHtml::dropDownList('pageSize',$pageSize,array(20=>20,50=>50,100=>100),array(

        // change 'user-grid' to the actual id of your grid!!

        'onchange'=>"$.fn.yiiGridView.update('user-grid',{ data:{pageSize: $(this).val() }})",

    )),

),



Et voilà, we have a page size selector that keeps it’s value in user state.

EDIT:

Forgot to mention the configuration in the application parameters:


// Accessable with Yii::app()->params['paramName']

'params'=>array (


    'defaultPageSize'=>20,



EDIT2:

Changed to match the CRUD generated code.


(Hamidych) #2

Hello Mike,

I have been trying to implement this code for 4 hours now…

Never used Yii before, trying it out for 3 days now.

So the problems that I am facing: I can’t figure out where to insert this part:


// page size drop down changed

if (isset($_GET['pageSize'])) {

    user()->setState('pageSize',(int)$_GET['pageSize']);

    unset($_GET['pageSize']);  // would interfere with pager and repetitive page size change

}

I think it should come into the controllers file of the model I am working on, am I correct? Into the:


	public function actionUpdate()

	{

		$model=$this->loadModel();



Once I insert all the code that you have provided, the page does not load properly. I figured out that if I replace user()->getState(‘pageSize’) with a static number, the page loads fine. I thought I forgot to add the default page size to the main configuration file, but this is not the case.

But even with the static number in pageSize the drop down list is not functional. I change the value to 50 or 100, but nothing happens.

I went to the page source and figured out that this:


'onchange'=>"$.fn.yiiGridView.update('tracker-grid',{ data:{pageSize: $(this).val() }})",

was replaced by this:


'onchange="$.fn.yiiGridView.update(& #039;tracker-grid&# 039;,{ data:{pageSize: $(this).val() }})",

Can you please help me deal with this?


(Mh) #3

You use the code generated through CRUD? I admit that my example was more general and thus maybe adressed to the advanced user. Nevertheless i tried with some fresh generated CRUD code now and adjusted the code accordingly.

Maybe you can give it another try and let me know if it still doesn’t work for you.


(Hamidych) #4

Thank you so much, Mike.

Yes, I used CRUD generated code.

I have implemented the modification you posted, now everything loads fine, just one problem remains.

The grid name inside of onchange() function is getting it’s single quotes replaced bu the HTML special characters.

So this:


'onchange'=>"$.fn.yiiGridView.update('mdl--std--student-details-grid',{ data:{pageSize: $(this).val() }})",

turns into this:


onchange="$.fn.yiiGridView.update(&#O39;mdl--std--student-details-grid&#O39;,{ data:{pageSize: $(this).val() }})" name="pageSize" id="pageSize"

Should I change it somewhere in php.ini?


(Mh) #5

Yeah, that’s happening for me, too. But did you try it? It works, the browser seems to interpret that string correctly. If you’re really concerned, you could connect the event handler with jQuery. Something i usually prefer anyway:


<?php

array(

    'class'=>'CButtonColumn',

    'header'=>CHtml::dropDownList('pageSize',$pageSize,array(20=>20,50=>50,100=>100),array(

        'id''=>'user-grid-pageSize'

    )),

),


// somewhere below:

Yii::app()->clientScript->registerScript('initPageSize','$("#user-grid-pageSize").change(function(){

    $.fn.yiiGridView.update('user-grid',{ data:{pageSize: $(this).val() }});

});',CClientScript::POS_READY);


(Hamidych) #6

Still no go…

The thing is, when I select something from the drop down list, a js error pops up. Just an empty alert with OK button.

I thought the problem is caused by single cote being replaced by &#O39;, but looks like I am wrong.

So whenever something is selected from the drop down list, i just receive a js alert.

By the way, the ajax function that we registered


Yii::app()->clientScript->registerScript('initPageSize'..................

should appear in the html source? Because it doesn’t for me.


(Mh) #7

Ok, here’s my tested view code for the grid. Please try again:


<?php $pageSize=Yii::app()->user->getState('pageSize',Yii::app()->params['defaultPageSize']); ?>

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

    'id'=>'user-grid',

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

    'filter'=>$model,

    'columns'=>array(

        'id',

        'username',

        'password',

        'email',

        array(

            'class'=>'CButtonColumn',

            'header'=>CHtml::dropDownList(

                'pageSize',

                $pageSize,

                array(5=>5,20=>20,50=>50,100=>100),

                array('class'=>'change-pagesize')

            ),

        ),

    ),

)); ?>

<?php Yii::app()->clientScript->registerScript('initPageSize',<<<EOD

    $('.change-pagesize').live('change', function() {

        $.fn.yiiGridView.update('user-grid',{ data:{ pageSize: $(this).val() }})

    });

EOD

,CClientScript::POS_READY); ?>




(Hamidych) #8

Ok! Great!

The problem was not with the view, the problem was with controller.

I made a misstake by putting this:


if (isset($_GET['pageSize'])) {

    user()->setState('pageSize',(int)$_GET['pageSize']);

    unset($_GET['pageSize']);  // would interfere with pager and repetitive page size change

}

before the model is generated, not at the end of the function.

Now it shows no errors, BUT… :)

When I change the drop down list to any value, the processing image appears for a second, disappears and I am still having my default number of rows. It does not update the grid. Just like if I have chosen the default number.

And the drop down list changes value back to the default number.


(Mh) #9

So try do do some debugging. setState() should save the state persistently. Check if that works by e.g. putting


print user()->getState('pageSize'); 



on different places. Also check if the if($_GET[…]) condition is ever true…


(Wardjk) #10

I have the same problem as Filist with pageSize not persisted.

Has a solution been found yet?


(Mh) #11

@jward:

Same here: Try to debug what’s wrong. Try to find out where ‘pageSize’ is deleted from user state (by echoing it’s value on different places). Or use any other mechanism to store that value persistently.


(Wardjk) #12

It works for me after I changed


          user()->setState('pageSize',(int)$_GET['pageSize']);

to


Yii::app()->user->setState('pageSize',(int)$_GET['pageSize']);

Can anyone guess why it wouldn’t work originally?

Here’s a broader view of the change:


	public function actionAdmin() 	{

 		$model=new User('search');

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

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


                  // page size drop down changed

                 if (isset($_GET['pageSize'])) {

                      //user()->setState('pageSize',(int)$_GET['pageSize']);  //this doesn't work for me

                     Yii::app()->user->setState('pageSize',(int)$_GET['pageSize']);   //use Yii::app()->user

                     unset($_GET['pageSize']);  // would interfere with pager and repetitive page size change

                 }


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

 			'model'=>$model,

 		)); 

SEE MY UPDATE ON 2-Jun-2010


(Mh) #13

Hmm. That doesn’t make sense to me. Do you use another user() function? It should look like:


/**

 * This is the shortcut to Yii::app()->user.

 */

function user()

{

    return Yii::app()->user;

}




(Wardjk) #14

I’m trying the Yii blog tutorial which has a User class modeled from tbl_user. Might this be the cause of the problem?


(Mh) #15

It shouldn’t. In one of my projects i also have a class User and a shortcut function user(), which works fine. Did you try with another function name?


(Smooth Traveller) #16

Hi Mike,Filist and Jward. I’ve been very interested by this add-on as I might have to use it. So I Gii’ed and made the test too. After minor problems it all works.

You can see it in the "farm dropdown_pagesize".

I had that problem too. So I checked in the source code and I saw the JQuery code was perfectly present.And at that moment I saw my :blink: BBIIGG mistake in registerScript:

I had Id with value “user-grid” whereas you should change it accordingly, so in my case 'tbl-user-grid"

8) I hope it is of any use …


(Mh) #17

Oh, forgot to mention that. Thanks for pointing that out. Will change the top post.


(Wardjk) #18

I just realized what was meant by this. I thought this code was already generated with the rest of the blog tutorial scaffolding but it wasn’t and I didn’t look for it. I stumbled upon Home » Documentation » The Yii Cookbook » Use shortcut functions to reduce typing and realized it was related to this issue.

I added this code to the project and can now use the user() shortcut without needing to use Yii::app()->user.


(Mh) #19

Oh, sorry for that. I’ve got so used to these shortcuts. The example is now using Yii::app()->user again everywhere to not confuse anyone reading it.


(Antonio) #20

This is a really great post. There should be a place in the wiki where, separated by objects -or within the class reference information, related wiki articles should appear for the people to learn. This is a great tip Mike, and I will surely use it in my new project. This is actually a great tip for those who wish to create more complex filters to the data displayed.

If you don’t mind, I will like to post an article in my blog with this know-how.

Thanks!