Laravel Datatables: Position Re-Ordering with Drag/Drop
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.