How to Add Mass Actions to Datatable

In QuickAdminPanel tables, you can tick the checkbox on every row, and then click Delete Selected:

That's the only "mass action" available. But you can create more, pretty easily.

You just need to repeat a block of code from index.blade.php file.

How it Works Now: Delete Selected

Currently, in resources/views/admin/courses/index.blade.php we have this JavaScript code for Delete selected button:

@can('course_delete')
  let deleteButtonTrans = '{{ trans('global.datatables.delete') }}'
  let deleteButton = {
    text: deleteButtonTrans,
    url: "{{ route('admin.courses.massDestroy') }}",
    className: 'btn-danger',
    action: function (e, dt, node, config) {
      var ids = $.map(dt.rows({ selected: true }).nodes(), function (entry) {
          return $(entry).data('entry-id')
      });

      if (ids.length === 0) {
        alert('{{ trans('global.datatables.zero_selected') }}')

        return
      }

      if (confirm('{{ trans('global.areYouSure') }}')) {
        $.ajax({
          headers: {'x-csrf-token': _token},
          method: 'POST',
          url: config.url,
          data: { ids: ids, _method: 'DELETE' }})
          .done(function () { location.reload() })
      }
    }
  }
  dtButtons.push(deleteButton)
@endcan

Let's break it down - what is happening here:

  1. Checking @can('course_delete') for permission for this button - read more about roles/permissions here.

  2. Button label comes from translations - see trans() method

  3. We need to assign the URL - what should happen after the click, so we specify route('admin.courses.massDestroy')

  4. We choose button class - btn-danger

  5. We specify the action: first we get the list of record IDs (every row has <tr data-entry-id="xxx">), if that list is empty - we throw error alert that no rows are selected

  6. We ask for confirmation - do you want to delete selected record?

  7. If it's confirmed, we're making AJAX request to the URL we specified in Step 3, and then reload the whole page

That URL is specified in routes/web.php:

Route::delete('courses/destroy', 'CoursesController@massDestroy')
    ->name('courses.massDestroy');

Finally, here's how it works in app/Http/Controllers/Admin/CoursesController.php:

public function massDestroy(MassDestroyCourseRequest $request)
{
    Course::whereIn('id', request('ids'))->delete();

    return response(null, Response::HTTP_NO_CONTENT);
}

Adding Another Mass-Action: Publish

For example, let's add another button Publish which will mass-publish the Courses from the table above.

We almost copy-paste the index.blade.php block to a new one, just below the old one:

let publishButtonTrans = 'Publish'
let publishButton = {
    text: publishButtonTrans,
    url: "{{ route('admin.courses.massPublish') }}",
    className: 'btn-warning',
    action: function (e, dt, node, config) {
        var ids = $.map(dt.rows({ selected: true }).nodes(), function (entry) {
            return $(entry).data('entry-id')
        });

        if (ids.length === 0) {
            alert('{{ trans('global.datatables.zero_selected') }}')

            return
        }

        if (confirm('{{ trans('global.areYouSure') }}')) {
            $.ajax({
                headers: {'x-csrf-token': _token},
                method: 'POST',
                url: config.url,
                data: { ids: ids }})
                .done(function () { location.reload() })
        }
    }
}
dtButtons.push(publishButton)

What I've changed here:

  • Button Label: publishButtonTrans = 'Publish' (or you can use translations, too)

  • Different URL: route('admin.courses.massPublish') - we will create it in a minute

  • Button Class: instead of btn-danger, I specified btn-warning

  • AJAX Method: instead of 'DELETE' I use simple 'POST'

Notice: if you're using AJAX Datatables module, you need to populate the ids array a bit differently:

var ids = $.map(dt.rows({ selected: true }).nodes(), function (entry) {
    return entry.id   // instead of return $(entry).data('entry-id')
});

And, that's it! We have a button:

To make that button work, we specify the URL in routes/web.php:

Route::post('courses/publish', 'CoursesController@massPublish')
    ->name('courses.massPublish');

Notice: that Route should come before the resource line of Route::resource() for the same Controller, otherwise it may conflict with Resourceful methods and be overridden.

Finally, we implement that massPublish in app/Http/Controllers/Admin/CoursesController.php - almost identical to massDestroy above:

public function massPublish(Request $request)
{
    Course::whereIn('id', request('ids'))->update(['is_published' => 1]);

    return response(null, Response::HTTP_NO_CONTENT);
}

That's it, you have you mass-action!

Last updated