CGridView sorting with CArrayDataProvider

Hello, I am using CArrayDataProvider as the data provider for a CGridView, and everything works fine, except the sorting.

The "sorting links" are already in the column headers, but when I click any of them, the table gets empty.

Basically, this is what I’m doing:

In the model:




$command = Yii::app()->db->createCommand();

$command->select('*');

$command->from('example');

$rawData = $command->queryAll();

$dataProvider=new CArrayDataProvider($rawData, array(

    'sort'=>array(

	'attributes'=>array(

	     'field1', 'field2'

	),

    ),

    'pagination'=>array(

	'pageSize'=>20,

    ),

));



In the view:




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

    'dataProvider'=>$dataProvider,

        'columns'=>array(

                array(

                        'name'=>'field1',

                        'header'=>' My Field 1',

                ),

                array(

                        'name'=>'field2',

                        'header'=>' My Field 2',

                ),

        ),

));



Am I missing something? I will appreciate any ideas to make the sorting work.

Thanks in advance!

Try with


'enableSorting'=>true,

in a GridView.Might be this is missing thing.

Thank you jayant, but it is not having any effect.

I will appreciate further ideas. Thank you.

Edit:

Ok I think I know where the problem is.

For this view I’m receiving a couple of parameters using “POST” method, so those parameters are lost when I click on the “sort link” in any column header, even though the sorting seems to use AJAX (the page is not fully reloaded and the ‘spin’ animation is shown for a moment). Without those parameters, the grid doesn’t show anything because they are required to find the data to be displayed. I know this is the problem because I set those parameters to be constant in the controller, and now the grid is sorting just fine.

Is there any way to preserve the parameters? Be it passing the parameters again when sorting, or somehow preserve them when sorting through AJAX. I am a newbie in AJAX, so I thought that since the page is not fully reloaded, the parameters were to stay there, but it seems that’s not true.

Thanks in advance!

try likethis in controller file


    $criteria->params=array(':status'=>'Publish',':cityId'=>$cityId,':sdate'=>$sdate);

and let me know if it works…

Here i am putting my a bit complex search filter code from controller file. i hope this will help you a lot.Since its work like a charm for me…





	public function actionUpcoming()

	{


		$this->layout = "inner";

		$model = new Event();


		$cityList = CHtml::listData(City::model()->findAll(array('order'=>'cityname ASC')), 'id', 'cityname');


		$criteria 			 =	new CDbCriteria();

		$criteria->condition = 'status=:status AND city_id =:cityId AND start_date >= :sdate';


		if(isset($_GET['keyword']) && $_GET['keyword']!='Search Event'){

			$keyword = $_GET['keyword'];

			$criteria->addCondition('event_name LIKE "%'.$keyword.'%"');

		}


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

			$cityId = $_GET['city'];

			$sdate = date('Y-m-d');

			if(isset($_GET['music_genre']) && $_GET['music_genre'] !='' && isset($_GET['date']) && $_GET['date'] !='Calender'){

				$sdate = $_GET['date'];

				$music_genre = $_GET['music_genre'];

				$criteria->addCondition('music_genre ="'.$music_genre.'"');

				$criteria->addCondition('start_date ="'.$sdate.'"');

			}elseif(isset($_GET['music_genre']) && $_GET['music_genre'] !=''){

				$music_genre = $_GET['music_genre'];

				$criteria->addCondition('music_genre ="'.$music_genre.'"');

			}elseif(isset($_GET['date']) && $_GET['date'] !='Calender'){

				$sdate = $_GET['date'];

				$criteria->addCondition('start_date ="'.$sdate.'"');

			}else{

				$sdate = date('Y-m-d');

			}

		}else{

			$cityId=Yii::app()->session->get('currentcity');

			if(isset($cityId) && !empty($cityId) ){

		    	$cityId = $cityId;

		    }else{

		    	$cityId = 1;

		    }

		    $sdate = date('Y-m-d');

		}


		$cityName = City::model()->cityName($cityId);


		$criteria->params=array(':status'=>'Publish',':cityId'=>$cityId,':sdate'=>$sdate);

		$dataProvider = new CActiveDataProvider('Event', array(

                                'pagination'=>array(

                                'pageSize'=>15,

                                //'params' => array('city' => $cityId,'sortby'=>$sortBy),

                                ),

                                'criteria'=>$criteria,


		));


		$this->render('upcoming',array('dataProvider'=>$dataProvider,'cityList'=>$cityList,'cityId'=>$cityId,'cityName'=>$cityName));

	}




Just wanted to share my solution sorting a column value involving relations. Trick is to make the grid column header a link so that it will sort via query. Am welcoming improvements/suggestions.

Model:




public $sort_user_profile_url="";

public $default_order=array();



Controller:




$criteria = new CDbCriteria;


$model->sort_user_profile_url = Yii::app()->baseUrl."/controller_name/action_name/sort/userProfile/asc";


        if( isset($_REQUEST["sort"]) )

        {

            if( $_REQUEST["sort"] == "userProfile" && (boolean)array_key_exists("asc", $_REQUEST) )

            {

                $model->sort_user_profile_url = Yii::app()->baseUrl."/controller_name/action_name/sort/userProfile/desc";

                $criteria->order='profile.firstname ASC';

            }

            elseif( $_REQUEST["sort"] == "userProfile" && (boolean)array_key_exists("desc", $_REQUEST) )

            {

                $criteria->order='profile.firstname DESC';

            }

        }

        else

        {

            $model->default_order=array('id' => true);      // reset default order by id

        }


$data=controller_name::model()->resetScope()->with( array( 'profile'=>array('together'=>true, 'joinType'=>'INNER JOIN') ) )->findAll($criteria);



View:




$dataProvider = new CArrayDataProvider($data, array(

        'sort'=>array(

            'attributes'=>array('id'),

            'defaultOrder'=>$model->default_order,

        ),

        'pagination'=>array(

            'pageSize'=>20,

        ),

    ));


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

        'id'=>'grid-id',

        'dataProvider'=>$dataProvider,

        'columns'=>array(

            array('name'=>'id', 'header'=>Yii::t('app', $model->getAttributeLabel('id'))),

            array('name'=>'profile.name', 'header'=>CHtml::link( Yii::t('app', $model->getAttributeLabel('profile.name')), '#', array('onclick'=>'js:window.location="'.$model->sort_user_profile_url.'";')),    

                'value'=>'$data->profile->firstname." ".$data->profile->lastname'),

            

        ),

    ));



I ended up doing something pretty similar, but just used the Yii automagic incoming variable setting:

in my controller:




 public function actionReports($sort = 'title') // later my &sort=title link param will end up with $sort=title

 {

            //populate up an array i want to display

            $rd = new ArrayReportDocumentor();

            $reports = $rd->processAllReports();

            

            $dataProvider=new CArrayDataProvider($reports, array(

                'id'=>'id',

                'sort'=>array(

                    'defaultOrder'=> $sort.' ASC',

                    'attributes'=>array(

                        'title', 'report_type', 'filename'

                    ),

                ),

                'pagination'=> false, //array(

                    //'pageSize'=>15,

                //),

            ));

            

            $sort_url = $this->createAbsoluteUrl($this->action->id);

            

            $this->render('list_reports', array('reportsProvider' => $dataProvider, 'sort_url' => $sort_url));

        }



in my view:





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

	'dataProvider' => $reportsProvider,

	'columns' => array(


		array(

			'name' => 'Title',

			'type' => 'raw',

                        'header' => CHtml::link('Title','#',array('onclick'=>'js:window.location="'.$sort_url.'&sort=title";')),

			'value' => 'CHtml::encode($data["title"])'

		),

                array(

			'name' => 'Description',

			'type' => 'raw',

			'value' => 'CHtml::encode($data["description"])'

		),

		array(

			'name' => 'Type',

			'type' => 'raw',

                        'header' => CHtml::link('Type','#',array('onclick'=>'js:window.location="'.$sort_url.'&sort=report_type";')),

			'value' => 'CHtml::encode($data["report_type"])'

		),

		array(

			'name' => 'Actual File',

			'type' => 'raw',

                        'header' => CHtml::link('Filename','#',array('onclick'=>'js:window.location="'.$sort_url.'&sort=filename";')),                    

			'value' => 'CHtml::encode($data["filename"])'

		),

                array(

			'name' => 'Params',

			'type' => 'raw',

			'value' => 'implode("<br/>",$data["params"])'

		),

                


	),

));



Not sure if this is the best way, really, but it works!

I think it’s more flexible/powerful if we do it via Yii’s inbuilt search() that way we could use a dropdownlist to filter results and sort at the same time. That is, we are not using CArrayDataProvider, but CActiveProvider. Note: I had a problem with the ajax search function when I included <form enctype=“multipart/form-data”>.

For example,

Model:




public $titles_name="";


return array(

			array('titles_name', 'safe', 'on'=>'search'),

		);


public function relations()

	{

		return array(

            'titles'=>array(self::BELONGS_TO, 'Titles', 'title_id' ),

		);

	}




public function search()

	{

		$criteria=new CDbCriteria;

		

	    $criteria->with = array(

	        'titles' => array(

	            'condition' => 'titles.item_type = :item_type',

	            'params' => array(':item_type' => 1),

	        ),

	    );

	    $criteria->together = true;


	    $criteria->compare('titles.name', $this->titles_name, true);


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

			'sort'=>array(

			    'attributes'=>array(

			        'titles_name'=>array(

			            'asc'=>'titles.name',

			            'desc'=>'titles.name DESC',

			        ),

			    ),

			),

		));

	}



Controller:




$model=new ControllerName('search');


        $model = new ItemPurchases('search');

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

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

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




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

			'model'=>$model,

		));



View:




<div class="search-form" style="display:none"></div>


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

	'id'=>'grid-id',

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

	'filter'=>$model,

        'columns'=>array(

		array('name'=>'titles_name', 'header'=>Yii::t('app', $model->getAttributeLabel('title_id')), 'value'=>'$data->titles->name', 'filter' => CHtml::listData(ControllerName2::model()->resetScope()->with( array('titles'=>array('joinType'=>'INNER JOIN')) )->findAll(), 'titles.name', 'titles.name'), 'type'=>'raw'),

		array('name'=>'id', 'header'=>Yii::t('app', $model->getAttributeLabel('id'))),


	),

));