Laravel Datatables: Position Re-Ordering with Drag/Drop
Povilas Korop
Founder of QuickAdminPanel
One of the features requested in our QuickAdminPanel, was drag’n’drop re-ordering of the entries in Datatables. For now, we decided to create a quick demo-project which would show you how to add this functionality.
Here’s the result of what we’ll be creating – in video format.
In this tutorial, we will assume that your Model has an integer field position.
Step 1. Setting the position for new entries
If you have app/Currency.php model and want to add a new currency, here’s the code to add:
class Currency extends Model
{
// ...
protected static function boot()
{
parent::boot();
Currency::creating(function ($model) {
$model->position = Currency::max('position') + 1;
});
}
}
Step 2. Reorder Method in Controller
In our Controller, we will add a special function that would save all the positions for all entries.
app/Http/Controllers/Admin/CurrenciesController.php:
class CurrenciesController extends Controller
{
// ...
public function reorder(Request $request)
{
foreach($request->input('rows', []) as $row)
{
Currency::find($row['id'])->update([
'position' => $row['position']
]);
}
return response()->noContent();
}
}
How do we call that method? In routes/web.php:
Route::post('currencies/reorder', 'CurrenciesController@reorder')->name('currencies.reorder');
Step 3. Blade & JavaScript: Hide Position and Reorder
In our QuickAdminPanel generator, we have datatables in resources/views/admin/currencies/index.blade.php, so here’s the JavaScript code for the datatables:
<table class=" table table-bordered table-striped table-hover datatable datatable-Currency">
...
</table>
@section('scripts')
@parent
<script>
$(function () {
let dtButtons = $.extend(true, [], $.fn.dataTable.defaults.buttons)
$.extend(true, $.fn.dataTable.defaults, {
order: [[ 2, 'asc' ]],
pageLength: 100,
columnDefs: [
...$.fn.dataTable.defaults.columnDefs,
{
visible: false,
searchable: false,
targets: 2
}
],
rowReorder: {
selector: 'tr td:not(:first-of-type,:last-of-type)',
dataSrc: '2'
},
});
let datatable = $('.datatable-Currency:not(.ajaxTable)').DataTable({ buttons: dtButtons })
datatable.on('row-reorder', function (e, details) {
if(details.length) {
let rows = [];
details.forEach(element => {
rows.push({
id: $(element.node).data('entry-id'),
position: element.newData
});
});
$.ajax({
headers: {'x-csrf-token': _token},
method: 'POST',
url: "{{ route('admin.currencies.reorder') }}",
data: { rows }
}).done(function () { location.reload() });
}
});
})
</script>
@endsection
In this case, we assume that position is column number 2 (which is third column, numbers start from 0), so we hide it visually, but make it a source of reordering.
Step 3b. AJAX Datatables
The code is a little bit different for AJAX Datatables module with server-side rendering. Here’s an example from a similar the same resources/views/admin/countries/index.blade.php from:
<table class=" table table-bordered table-striped table-hover ajaxTable datatable datatable-Country">
...
</table>
...
<script>
$(function () {
let dtButtons = $.extend(true, [], $.fn.dataTable.defaults.buttons)
let dtOverrideGlobals = {
buttons: dtButtons,
processing: true,
serverSide: true,
retrieve: true,
aaSorting: [],
ajax: "{{ route('admin.countries.index') }}",
columns: [
{ data: 'placeholder', name: 'placeholder' },
{ data: 'id', name: 'id' },
{ data: 'position', name: 'position', visible: false, searchable: false },
{ data: 'name', name: 'name' },
{ data: 'short_code', name: 'short_code' },
{ data: 'actions', name: '{{ trans('global.actions') }}' }
],
order: [[ 2, 'asc' ]],
pageLength: 100,
rowReorder: {
selector: 'tr td:not(:first-of-type,:last-of-type)',
dataSrc: 'position'
},
};
let datatable = $('.datatable-Country').DataTable(dtOverrideGlobals);
datatable.on('row-reorder', function (e, details) {
if(details.length) {
let rows = [];
details.forEach(element => {
rows.push({
id: datatable.row(element.node).data().id,
position: element.newData
});
});
$.ajax({
headers: {'x-csrf-token': _token},
method: 'POST',
url: "{{ route('admin.countries.reorder') }}",
data: { rows }
}).done(function () { datatable.ajax.reload() });
}
});
});
</script>
That’s it! Public repository is available here on Github.