Datatables Javascript files
The controller
app/javascript/controllers/datatables_controller.js
import { Controller } from "@hotwired/stimulus"
import '../src/datatables-bs5'
export default class extends Controller {
static values = {
simple: Boolean,
url: String
}
initialize() {
}
connect() {
let dtOptions = {}
this.compileOptions(dtOptions)
if (!this.simpleValue) {
this.setInputFields()
}
const table = $(this.element.querySelector('table'))
// prepare options, optional add remote processing (not yet implemented)
let dtable = $(table).DataTable(dtOptions)
// process search input
dtable.columns().eq(0).each((colIdx) => {
$('input[name=idx'+colIdx+']').on( 'keyup change', function() {
dtable.column(colIdx).search(this.value).draw()
})
})
} // connect
// search fields for each column
setInputFields() {
this.element.querySelectorAll("table tfoot th:not([class='nosearch'])")
.forEach((th, idx) => {
th.insertAdjacentHTML('afterbegin', this.searchField(idx))
})
}
// single search input field
searchField(idx) {
return `<input type="text" placeholder="search" name="idx${idx}" />`
}
// datatables options
compileOptions(options) {
// common options
options.pagingType = "full_numbers"
options.stateSave = false
options.lengthMenu = [ [10, 25, 100, 250, 1000], [10, 25, 100, 250, 1000] ]
options.columnDefs = [ { "targets": "nosort", "orderable": false },
{ "targets": "notvisible", "visible": false },
{ "targets": "actions", "className": "actions" } ]
// with or without buttons
if (this.simpleValue) {
this.simpleOptions(options)
} else {
this.buttonOptions(options)
}
// remote fetch via ajax or plain html data
if (this.hasUrlValue) {
this.remoteOptions(options)
}
}
simpleOptions(options) {
options.dom = "<'row'<'col-sm-12'tr>>" +
"<'row'<'col pt-2'l><'col'i><'col'p>>"
options.pagingType = "numbers"
}
buttonOptions(options) {
options.dom = "<'row'<'col'l><'col'B><'col'f>>" +
"<'row'<'col-sm-12'tr>>" +
"<'row'<'col'i><'col'p>>"
options.buttons = {
dom: {
button: {
tag: 'button',
className: 'btn btn-outline-secondary btn-sm'
}
},
buttons: [ { "extend": 'copy',
"exportOptions": {
"columns": ':visible',
"search": ':applied' } },
{ "extend": 'csv',
"exportOptions": { "search": ':applied' } },
{ "extend": 'excel',
"exportOptions": { "search": ':applied' } },
{ "extend": 'pdf',
"orientation": 'landscape',
"pageSize": 'A4',
"exportOptions": { "columns": ':visible',
"search": ':applied' } },
{ "extend": 'print'},
{ "extend": 'colvis', "columns": ':gt(0)' } ]
}
}
remoteOptions(options) {
options.searchDelay = 400
options.processing = true
options.serverSide = true
options.ajax = { "url": this.urlValue, "type": "POST" }
}
} // Controller
Helpers
jquery preloader
app/javascript/src/jquery.js
import jquery from 'jquery'
window.jQuery = jquery
window.$ = jquery
Datatables modules
app/javascript/src/datatables-bs5.js
import '../src/jquery.js'
// used for Excel button, CSV button doesn't need it
import JSZip from 'jszip'
window.JSZip = JSZip
// used for PDF button
import pdfMake from "pdfmake/build/pdfmake";
import pdfFonts from "pdfmake/build/vfs_fonts";
pdfMake.vfs = pdfFonts.pdfMake.vfs;
require('datatables.net-bs5')();
require('datatables.net-buttons-bs5')();
require('datatables.net-buttons/js/buttons.colVis.js' )();
require('datatables.net-buttons/js/buttons.html5.js' )();
require('datatables.net-buttons/js/buttons.print.js' )();
Troubleshooting
Remote processing and authentication
If you are receiving a 406 "not acceptable" error, have a look at your logfile. If it says
Can't verify CSRF token authenticity.
you need to add the CSRF-token to the POST request:
datatables-controller.js
...
remoteOptions(options) {
let token = document.head.querySelector('meta[name="csrf-token"]').getAttribute('content')
options.searchDelay = 400
options.processing = true
options.serverSide = true
options.ajax = {
'url': this.urlValue,
'type': 'POST',
'beforeSend': function(request) {
request.setRequestHeader("X-CSRF-Token", token)
}
}
}