I’m in this situation
I try to load my datatables with checkbox selected
I have 2 kind of urls: rows unselected and rows/checkbox selected
http://localhost:5000/?page=1&length=10
http://localhost:5000/?page=1&length=25&badge=ebooks
and
http://localhost:5000/?page=1&length=25&badge=ebooks&id=Il+Piccolo+%2314+settembre+2023
for example a checkbox is selected when you can see &id= inside url
But when I load table with &id=... table doesn’t return checkbox/rows state selection, it change url into something this
http://localhost:5000/?page=1&length=10&badge=ebooks
PROBLEM: The main problem seems to be related to how the URL is manipulated and how selected rows are handled when performing a search or changing URL parameters.
I am using the state of the DataTable to save the IDs of the selected rows. However, when the page is reloaded with a URL that contains the row IDs, the selected rows are not correctly restored
OK, my relevant code is this
initComplete: function() {
var api = this.api();
// Search bar management
api.columns().every(function() {
var that = this;
$('input', this.footer()).on('input', function() {
if (that.search() !== this.value) {
that.search(this.value).draw();
if (this.value != '') {
history.pushState(null, '', '/?search=' + encodeURIComponent(this.value));
} else {
history.pushState(null, '', '/');
}
}
});
});
// Highlight the selected rows
api.rows('.selected-row').nodes().to$().addClass('selected-row');
// Select rows based on URL parameters
var urlParams = new URLSearchParams(window.location.search);
var selectedRows = urlParams.getAll('id');
selectedRows.forEach(rowId => {
// Find the checkbox corresponding to the ID and simulate a click on it
var checkbox = $('input[name="id[]"][data-id="' + rowId + '"]');
checkbox.prop('checked', true).trigger('change');
checkbox.closest('tr').addClass('selected-row');
});
// If there are search parameters, apply them to the table
var searchParam = urlParams.get('search');
if (searchParam) {
api.search(searchParam).draw();
}
// Block to keep ID in URL
var currentUrl = new URL(window.location.href);
var idParam = urlParams.get('id');
if (idParam) {
currentUrl.searchParams.set('id', idParam);
}
history.replaceState(null, '', currentUrl);
}
and this
columnDefs: [
{
targets: 0,
visible: true,
searchable: false,
orderable: false,
render: function (data, type, row, meta) {
// Add the data-id attribute to the checkbox with the row ID value
return '<input type="checkbox" name="id[]" data-id="' + row.id + '" value="' + $('<div/>').text(data).html() + '">';
}
}
],
The solution I thought of was to simulate clicks, but maybe is not the best way
HERE is the complete javascript code that I use and here is python relevant part
class User(db.Model):
id = db.Column(db.String(80), primary_key=True)
badge = db.Column(db.String(80))
extra = db.Column(db.String(80))
username = db.Column(db.String(80)) # Added 'username' column
def to_dict(self, selected_rows):
return {
'id': self.id,
'badge': self.badge,
'extra': self.extra,
'username': self.username,
'selected': str(self.id) in selected_rows
}
and search function
@app.route('/search', methods=['POST'])
def search():
badge = request.form.get('badge') or request.args.get('badge')
start = int(request.form.get('start', 0))
length = int(request.form.get('length', 10))
searchTerm = request.form.get('search[value]')
# Access selectedRows from the prompt
selected_rows = request.form.getlist('selectedRows[]')
query = User.query
if badge:
query = query.filter(User.badge == badge)
if searchTerm:
query = query.filter((User.id.ilike(f"%{searchTerm}%")) |
(User.badge.ilike(f"%{searchTerm}%")) |
(User.extra.ilike(f"%{searchTerm}%")) |
(User.username.ilike(f"%{searchTerm}%")))
data = query.offset(start).limit(length).all()
# Pass selectedRows to the to_dict function
return jsonify({
'data': [user.to_dict(selected_rows) for user in data],
'recordsTotal': User.query.count(),
'recordsFiltered': query.count(),
})
Attempt to fix the problem: to avoid simulating the click I tried to modify the code also in this way so that the setting of the row and checkbox status occurs directly without having to simulate the change event. But nothing
selectedRows.forEach(rowId => {
// Find the checkbox corresponding to the ID
var checkbox = $('input[name="id[]"][data-id="' + rowId + '"]');
// Set the 'checked' property of the checkbox directly
checkbox.prop('checked', true);
// Add the 'selected-row' class to the closest row
checkbox.closest('tr').addClass('selected-row');
});
// Trigger the 'change' event for the checkboxes
$('input[name="id[]"]').trigger('change');
