Difference between #2 and #1 of Creating a jQueryUI Sortable CGridView

unchanged
Title
Creating a jQueryUI Sortable CGridView
unchanged
Category
How-tos
unchanged
Tags
sortable, cgridview, jqueryui
changed
Content
I have had to do this a couple of times now so I figured I would share it with
the community.  I am going to keep this short because I really hope that you are
familiar with [jQueryUI's Sortable](http://jqueryui.com/demos/sortable/
"jQueryUI's Sortable") class before starting this tutorial.

Here are the basic steps to achieve this:

1. Make sure your database table has a 'sortOrder' field.
2. (Optional) Add the 'sortOrder' field to your Rules() function in
your model
3. Add the 'sort()' function to your controller to apply the sorting via ajax
4. Add jQuery UI to your view that has the CGridView
5. Setup the jQuery UI Code to work with the CGridView in question
6. (Optional) Apply the sorting to your model's search() function if need be

So lets get started!

**Step 1** is self-explanatory, just make sure that you have an INT field in
your database to store the sortOrder of each item ( for this article we will
call this field 'sortOrder' )


**Step 2:** AddThis step is optional but recommended.  Add
this line to the model who's items you are sorting.  Without this line your
item's sortOrder will never be saved:
~~~
[php]
array('sortOrder', 'numerical', 'integerOnly'=>true),
~~~


**Step 3:**  This is the part where we add the code to a controller that will
apply the new sorting order to the rows in your database. Note I will be using a
controller titled 'Project'.  You will see me link to this controller in the
jQueryUI Sortable javascript code.

* Note: Please make sure that the user who will be doing the sorting has access
to this action in your 'accessRules()' for the controller in question.

'Project' is the model that I am applying the ordering to.  You can add a
CDbCriteria in here if you need to sort just specific rows.
~~~
[php]
public function actionSort()
{
	if (isset($_POST['items']) && is_array($_POST['items'])) {
		$i = 0;
		foreach ($_POST['items'] as $item) {
			$project = Project::model()->findByPk($item);
			$project->sortOrder = $i;
			$project->save();
			$i++;
		}
	}
}
~~~


**Step 4:**  OK Here is the fun part.  We need to setup jQuery UI to link to the
CGridView w/o having to modify the source of the CGridView in any way.  By doing
this we don't have to modify any of the core files or extend CGridView in any
way.
~~~
[php]
<?php
	$str_js = "
		var fixHelper = function(e, ui) {
			ui.children().each(function() {
				$(this).width($(this).width());
			});
			return ui;
		};
				
		$('#project-grid table.items tbody').sortable({
			forcePlaceholderSize: true,
			forceHelperSize: true,
			items: 'tr',
			update : function () {
				serial = $('#project-grid table.items tbody').sortable('serialize', {key:
'items[]', attribute: 'class'});
				$.ajax({
					'url': '" . $this->createUrl('//project/sort') . "',
					'type': 'post',
					'data': serial,
					'success': function(data){
					},
					'error': function(request, status, error){
						alert('We are unable to set the sort order at this time.  Please try again
in a few minutes.');
					}
				});
			},
			helper: fixHelper
		}).disableSelection();
	";

	Yii::app()->clientScript->registerScript('sortable-project', $str_js);
?>
<?php $this->widget('zii.widgets.grid.CGridView', array(
	'id'=>'project-grid',
	'dataProvider'=>$model->search(),
	'filter'=>$model,
	'rowCssClassExpression'=>'"items[]_{$data->id}"',
	'columns'=>array(
		'id',
		'title',
		'categoryId',
		'sortOrder',
		array(
			'class'=>'CButtonColumn',
		),
	),
)); ?>
~~~


OK So first off we are setting up the jQueryUI Sortable object in javascript and
attaching it to our CGridView.  Things to note are:  'project-grid' is the 'id'
of our CGridView and will need to be switched to the ID of your CGridView. 
Also, the following line will need to be altered to point to your
//controller/action path where you added the 'actionSort()' function:
~~~
[javascript]
'url': '" . $this->createUrl('//project/sort') . "',
~~~

Once the javascript is setup we need to setup the CGridView.  The only two
things out of the ordinary are that we are explicitly setting the 'id' of the
CGridView and we are also setting the 'rowCssClassExpression' variable to work
with jQueryUI Sortable.
~~~
[javascript]
'id'=>'project-grid',
'rowCssClassExpression'=>'"items[]_{$data->id}"',
~~~


**Step 5:**  In your view file or controller that is displaying the CGridView
you will need to tell Yii to add jQueryUI to your page.
~~~
[php]
Yii::app()->clientScript->registerScriptFile('http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js');
~~~


**Step 6:** If you are planning on using your model::Search() function to setup
DataProviders for things like CListView and CGridView I recommend you add the
following line to the Search() function towards the bottom before the
CActiveDataProvider is created:
~~~
[php]
$criteria->order = 'sortOrder ASC';
~~~

I hope this helps some people out!  If you are having any problems please go
through this write-up again to make sure you didn't miss anything.