This forum has moved to a new location and is in read-only mode. Please visit talk.octobercms.com to access the new location.
Hi there,
I'm aware of the baked-in Sortable trait, and have used it extensively with "top-level" models as well as nested sets.
However, I'd like to be able to extend this behavior to child items. For example in a many-to-many relationship between Products and Categories. My solution for now is to have the relation manager pop up a form to edit the sort_order (stored as pivot data in the "category has product" link table) manually for the Products in a Category, which works, but is a bit clunky and could mean a lot of editing of records if you want to insert a new item.
Does anyone know of any examples of drag-and-drop reordering either directly in the relation manager, or through some other solution? Any other ideas on how to make this a little more user-friendly?
Thanks for any input!
Scott have wrote a plugin where he make a list sortable. Maybe you can take a look at this:
Thanks for the reply Crazymodder! You set me on the right path for sure. I managed to get this working for Relation lists, though it did require a bit of fiddling. If anyone is going to try this I'd recommend trying out the draganddrop plugin on a non-relation list first to get familiar with it.
Here's the steps I took, using my setup of a Product
hasMany Variants
1) Add the hidden input as per usual with the draganddrop plugin (see the example model in the plugin) -- this just adds the object id to each row of the list so that it can be accessed via javascript when the "Reorder" button is clicked.
2) Set up the toolbar partial to add the button to the relation list toolbar. Create the toolbarPartial
under the 'view' section of the $relationConfig
file. You'll have to copy the existing buttons you want to keep from their source files, eg check here: https://github.com/octobercms/october/tree/master/modules/backend/behaviors/relationcontroller/partials
3) Add the reorder button (similar to the usual way of doing things, but note the extra model_id parameter being sent
here's my reorder button:
<button
id="updatePosition"
class="btn btn-reorder oc-icon-list-ol"
disabled="disabled"
onclick="$(this).data('request-data', {
checked: $('.index_reposition').map(function(){ return $(this).val() }).get(), model_id: <?php echo $this->formGetModel()->id; ?> })"
data-request-success="initializeSorting();"
data-request="onUpdateVariantPosition"
data-stripe-load-indicator>
Update Order
</button>
4) Set up the handler in the controller.
Here's mine:
public function update_onUpdateVariantPosition()
{
$moved = [];
$position = 0;
if (($reorderIds = post('checked')) && is_array($reorderIds) && count($reorderIds)) {
foreach ($reorderIds as $id) {
if (in_array($id, $moved) || !$record = Variant::find($id))
continue;
$record->sort_order = $position;
$record->save();
$moved[] = $id;
$position++;
}
Flash::success('Successfully re-ordered variants.');
}
$model = Product::find(post('model_id'));
$this->initForm($model);
$this->initRelation($model, 'variants');
return $this->relationRefresh('variants');
}
The last 4 lines of code are needed to re-initalize the relation in the context of the controller before the updated list can be returned to the browser. See discussion about this behaviour here: https://octobercms.com/forum/post/problem-with-relationrefresh
Edit: Some changes were needed to be made to scottbedard's plugin, which he's now merged. Here are the changes from the pull request: https://github.com/scottbedard/draganddrop/pull/1/commits/7f5fec6945b8eac649f11ef5b97443b2ec918e80
Hope this helps someone. Cheers.
Last updated
Thanks vanchuck. How did you implement the js files into the relation list? My js files wont load with $this->addJs() in __construct().
vanchuck said:
Thanks for the reply Crazymodder! You set me on the right path for sure. I managed to get this working for Relation lists, though it did require a bit of fiddling. If anyone is going to try this I'd recommend trying out the draganddrop plugin on a non-relation list first to get familiar with it.
Here's the steps I took, using my setup of a
Product
hasManyVariants
1) Add the hidden input as per usual with the draganddrop plugin (see the example model in the plugin) -- this just adds the object id to each row of the list so that it can be accessed via javascript when the "Reorder" button is clicked.
2) Set up the toolbar partial to add the button to the relation list toolbar. Create the
toolbarPartial
under the 'view' section of the$relationConfig
file. You'll have to copy the existing buttons you want to keep from their source files, eg check here: https://github.com/octobercms/october/tree/master/modules/backend/behaviors/relationcontroller/partials3) Add the reorder button (similar to the usual way of doing things, but note the extra model_id parameter being sent
here's my reorder button:
<button id="updatePosition" class="btn btn-reorder oc-icon-list-ol" disabled="disabled" onclick="$(this).data('request-data', { checked: $('.index_reposition').map(function(){ return $(this).val() }).get(), model_id: <?php echo $this->formGetModel()->id; ?> })" data-request-success="initializeSorting();" data-request="onUpdateVariantPosition" data-stripe-load-indicator> Update Order
4) Set up the handler in the controller.
Here's mine:
public function update_onUpdateVariantPosition() { $moved = []; $position = 0; if (($reorderIds = post('checked')) && is_array($reorderIds) && count($reorderIds)) { foreach ($reorderIds as $id) { if (in_array($id, $moved) || !$record = Variant::find($id)) continue; $record->sort_order = $position; $record->save(); $moved[] = $id; $position++; } Flash::success('Successfully re-ordered variants.'); }
$model = Product::find(post('model_id')); $this->initForm($model); $this->initRelation($model, 'variants'); return $this->relationRefresh('variants');
}
The last 4 lines of code are needed to re-initalize the relation in the context of the controller before the updated list can be returned to the browser. See discussion about this behaviour here: https://octobercms.com/forum/post/problem-with-relationrefresh
Edit: Some changes were needed to be made to scottbedard's plugin, which he's now merged. Here are the changes from the pull request: https://github.com/scottbedard/draganddrop/pull/1/commits/7f5fec6945b8eac649f11ef5b97443b2ec918e80
Hope this helps someone. Cheers.
Thank you for your efforts. It really helps. Many thanks.
vanchuck said:
Thanks for the reply Crazymodder! You set me on the right path for sure. I managed to get this working for Relation lists, though it did require a bit of fiddling. If anyone is going to try this I'd recommend trying out the draganddrop plugin on a non-relation list first to get familiar with it.
Here's the steps I took, using my setup of a
Product
hasManyVariants
1) Add the hidden input as per usual with the draganddrop plugin (see the example model in the plugin) -- this just adds the object id to each row of the list so that it can be accessed via javascript when the "Reorder" button is clicked.
2) Set up the toolbar partial to add the button to the relation list toolbar. Create the
toolbarPartial
under the 'view' section of the$relationConfig
file. You'll have to copy the existing buttons you want to keep from their source files, eg check here: https://github.com/octobercms/october/tree/master/modules/backend/behaviors/relationcontroller/partials3) Add the reorder button (similar to the usual way of doing things, but note the extra model_id parameter being sent
here's my reorder button:
<button id="updatePosition" class="btn btn-reorder oc-icon-list-ol" disabled="disabled" onclick="$(this).data('request-data', { checked: $('.index_reposition').map(function(){ return $(this).val() }).get(), model_id: <?php echo $this->formGetModel()->id; ?> })" data-request-success="initializeSorting();" data-request="onUpdateVariantPosition" data-stripe-load-indicator> Update Order
4) Set up the handler in the controller.
Here's mine:
public function update_onUpdateVariantPosition() { $moved = []; $position = 0; if (($reorderIds = post('checked')) && is_array($reorderIds) && count($reorderIds)) { foreach ($reorderIds as $id) { if (in_array($id, $moved) || !$record = Variant::find($id)) continue; $record->sort_order = $position; $record->save(); $moved[] = $id; $position++; } Flash::success('Successfully re-ordered variants.'); }
$model = Product::find(post('model_id')); $this->initForm($model); $this->initRelation($model, 'variants'); return $this->relationRefresh('variants');
}
The last 4 lines of code are needed to re-initalize the relation in the context of the controller before the updated list can be returned to the browser. See discussion about this behaviour here: https://octobercms.com/forum/post/problem-with-relationrefresh
Edit: Some changes were needed to be made to scottbedard's plugin, which he's now merged. Here are the changes from the pull request: https://github.com/scottbedard/draganddrop/pull/1/commits/7f5fec6945b8eac649f11ef5b97443b2ec918e80
Hope this helps someone. Cheers.
how to use sort_order instead of position variable and error comes from model $record not found
Last updated
vanchuck said:
Thanks for the reply Crazymodder! You set me on the right path for sure. I managed to get this working for Relation lists, though it did require a bit of fiddling. If anyone is going to try this I'd recommend trying out the draganddrop plugin on a non-relation list first to get familiar with it.
Here's the steps I took, using my setup of a
Product
hasManyVariants
1) Add the hidden input as per usual with the draganddrop plugin (see the example model in the plugin) -- this just adds the object id to each row of the list so that it can be accessed via javascript when the "Reorder" button is clicked.
2) Set up the toolbar partial to add the button to the relation list toolbar. Create the
toolbarPartial
under the 'view' section of the$relationConfig
file. You'll have to copy the existing buttons you want to keep from their source files, eg check here: https://github.com/octobercms/october/tree/master/modules/backend/behaviors/relationcontroller/partials3) Add the reorder button (similar to the usual way of doing things, but note the extra model_id parameter being sent
here's my reorder button:
<button id="updatePosition" class="btn btn-reorder oc-icon-list-ol" disabled="disabled" onclick="$(this).data('request-data', { checked: $('.index_reposition').map(function(){ return $(this).val() }).get(), model_id: <?php echo $this->formGetModel()->id; ?> })" data-request-success="initializeSorting();" data-request="onUpdateVariantPosition" data-stripe-load-indicator> Update Order
4) Set up the handler in the controller.
Here's mine:
public function update_onUpdateVariantPosition() { $moved = []; $position = 0; if (($reorderIds = post('checked')) && is_array($reorderIds) && count($reorderIds)) { foreach ($reorderIds as $id) { if (in_array($id, $moved) || !$record = Variant::find($id)) continue; $record->sort_order = $position; $record->save(); $moved[] = $id; $position++; } Flash::success('Successfully re-ordered variants.'); }
$model = Product::find(post('model_id')); $this->initForm($model); $this->initRelation($model, 'variants'); return $this->relationRefresh('variants');
}
The last 4 lines of code are needed to re-initalize the relation in the context of the controller before the updated list can be returned to the browser. See discussion about this behaviour here: https://octobercms.com/forum/post/problem-with-relationrefresh
Edit: Some changes were needed to be made to scottbedard's plugin, which he's now merged. Here are the changes from the pull request: https://github.com/scottbedard/draganddrop/pull/1/commits/7f5fec6945b8eac649f11ef5b97443b2ec918e80
Hope this helps someone. Cheers.
I'm do some changes for universal usage (willn't change code for different relations). Button in toolbar:
<button
id="updatePosition"
class="btn btn-reorder oc-icon-list-ol"
disabled="disabled"
onclick="$(this).data('request-data', {
checked: $('.index_reposition').map(function(){ return $(this).val() }).get(), model_id: formGetModel()->id; ?> , relationName: "= $relationField ?>"})"
data-request-success="initializeSorting();"
data-request="onUpdateRelationItems"
data-stripe-load-indicator>
Update Order
</button>
controller action:
public function update_onUpdateRelationItems()
{
$main_model = $this->formCreateModelObject();
$relationName = post('_relation_field');
$relationModel = $main_model->getRelationDefinition($relationName)[0];
$moved = [];
$position = 0;
if (($reorderIds = post('checked')) && is_array($reorderIds) && count($reorderIds)) {
foreach ($reorderIds as $id) {
if (in_array($id, $moved) || !$record = $relationModel::find($id))
continue;
$record->sort_order = $position;
$record->save();
$moved[] = $id;
$position++;
}
Flash::success('Successfully re-ordered variants.');
}
$model = $main_model::find(post('model_id'));
$this->initForm($model);
$this->initRelation($model, $relationName);
return $this->relationRefresh($relationName);
}
Thank you for working decision!
Last updated
1-9 of 9