In this tutorial we will be setting up a content type to be ordered by weight using the JUI Sortable plugin.
Note: This is probably not suitable for large data sets, as each model is updated on submission.
Tutorial Requirements
- Database table setup with at least the fields id, title, and weight.
- A content type created with the Yiic shell crud command.
Setting up the Model ¶
If you haven't done so already, we need to validate the weight, so add the following code to your rules() function:
public function rules()
{
return array(
array('weight', 'numerical'),
);
}
Setting up the Views ¶
First we need to set up the weight field as a drop down list to keep our bases covered when editing individual models, so modify the _form.php view as follows (changing YourClass accordingly):
<div class="row">
<?php echo CHtml::activeLabelEx($model, 'weight'); ?>
<?php
// Set the number of models to be the heaviest weight
// and format into a dropDownList-friendly array
$models = YourClass::model()->findAll();
for ($i = 0; $i < sizeof($models); $i++) { $weights[$i] = $i; }
echo CHtml::activeDropDownList($model, 'weight', $weights);
?>
<div class="hint">
Selecting a lighter weight (e.g. 0) will
place the model higher in the list.
</div>
<?php echo CHtml::error($model, 'weight'); ?>
</div>
Now we need to create the view in which we actually order the models, so go ahead and duplicate index.php and rename to order.php. Modify the page title and breadcrumbs and whatever else as needed, and replace the CListView widget with:
<?php
// Organize the dataProvider data into a Zii-friendly array
$items = CHtml::listData($dataProvider->getData(), 'id', 'title');
// Implement the JUI Sortable plugin
$this->widget('zii.widgets.jui.CJuiSortable', array(
'id' => 'orderList',
'items' => $items,
));
// Add a Submit button to send data to the controller
echo CHtml::ajaxButton('Submit Changes', '', array(
'type' => 'POST',
'data' => array(
// Turn the Javascript array into a PHP-friendly string
'Order' => 'js:$("ul.ui-sortable").sortable("toArray").toString()',
)
));
?>
At this point it would also be good to setup menu items in the rest of the views as needed, using this code for example: ~~~ [html]
<?php echo CHtml::link('Order Models', array('order')); ?> ~~~Setting up the Controller ¶
First we need to give a particular user(s) the permission to order these items. Modify the accessRules() function in your controller to have the action order. For example:
public function accessRules()
{
return array(
array('allow',
'actions' => array('order'),
'users' => array('admin'),
),
);
}
Now we need to create the action that will handle the ordering. Add the following code somewhere in your controller (changing YourClass accordingly).
/**
* Handles the ordering of models.
*/
public function actionOrder()
{
// Handle the POST request data submission
if (isset($_POST['Order']))
{
// Since we converted the Javascript array to a string,
// convert the string back to a PHP array
$models = explode(',', $_POST['Order']);
for ($i = 0; $i < sizeof($models); $i++)
{
if ($model = YourClass::model()->findbyPk($models[$i]))
{
// Use updateByPK to avoid running model validate
$model->updateByPk( $models[$i],array("weight"=>$i) );
}
}
}
// Handle the regular model order view
else
{
$dataProvider = new CActiveDataProvider('YourClass', array(
'pagination' => false,
'criteria' => array(
'order' => 'weight ASC, id DESC',
),
));
$this->render('order',array(
'dataProvider' => $dataProvider,
));
}
}
Implementation ¶
Now whenever you are using a dataProvider, just set the order criteria to:
'criteria' => array(
'order' => 'weight ASC, id DESC',
),
and you should be good to go!
This helped me out
Great tutorial, thank you!
Sorting on Drop of Item
To execute the sorting ajax on drop of item, use 'options' as follows:
$this->widget('zii.widgets.jui.CJuiSortable', array( 'id' => 'orderList', 'items' => $items, 'options' => array( 'update'=>'js:function(event,ui){ $.post("",{Order:$("ul#orderList").sortable("toArray").toString()},function(data){}); }' ), ));
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.