How to update data after ajax reload using initComplete callback for DataTables when using ajax source data? - datatables

I’m using a select object to trigger an ajax reload for a DataTable.
I need to add individual column searching with select inputs for a given column (not for every column) but the select is filled with the previous ajax response.
How can I update the data that the initCompleteFunction callback uses to fill the select input in the individual column searching?
// this is the select that triggers the ajax.reload
$('#proveedor').on('change', function () {
$datatable
.DataTable()
.ajax
.reload(initCompleteFunction, false);
});
// this is my initCompleteFunction callback
function initCompleteFunction(settings, json){
var api = new $.fn.dataTable.Api( settings );
api.columns().every( function () {
var column = this;
if ($(column.header()).hasClass('select')) {
var select = $('<select><option value="">' + $(column.header()).html() + '</option></select>')
.appendTo( $(column.footer()).empty() )
.on( 'change', function () {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column
.search( val ? '^'+val+'$' : '', true, false )
.draw();
return false;
} );
//this is the part that keeps previous data insted of the new one from the ajax reload
column.data().unique().sort().each( function ( d, j ) {
select.append( '<option value="'+d+'">'+d+'</option>' );
} );
}
});
}
// and this is how I’m setting the DataTable
var $datatable = $('#table_materiales');
$datatable
.on('xhr.dt', function ( e, settings, json, xhr ) {
initCompleteFunction(settings, json);
})
.DataTable({
"ajax": {
"url": "http://my_endpoint",
"dataSrc": "",
"type": "POST",
"data": {
id_proveedor: function () {
return $('#proveedor').val(); // to get the value in the provider’s filter (select)
}
}
},
"columns": [
{
data: 'row_num'
},{
className: "select",
data: 'material'
},
// here goes the rest of the column definitions
],
"paging": false,
'columnDefs': [
{
'targets': 0,
'checkboxes': {
'selectRow': true
}
}
],
'select': {
'style': 'multi'
},
'order': [
[3, 'asc']
],
"createdRow": function (row, data, dataIndex) {
$(row).attr('data-id-material', data.id_material);
$(row).attr('data-pedido_sugerido', data.pedido_sugerido);
$(row).attr('id', 'id_' + data.row_num);
if(data['status_de_tiempo']=='FUERA'){
$(row).addClass('redClass');
}
},
});

During research I found that the xhr.dt event is triggered before the ajax.reload() is completed so the data keeps outdated when the select for the individual column search is populated. See this reference
User grozni posted this on April, 2019:
I have used console logs and was able to confirm that the event fires before the XHR event concludes, and does not pull the latest JSON. I used XHR tracking where I could to get around it but it's still really inconvenient and complicating matters alot. I need to be able to do certain things after the data is loaded and drawn. Perhaps it's worthy of a bug report
I found this post (See here) where user conangithub needed to
count DataTables item after I reload DataTable successfully
User lovecoding-git suggested this approach:
table= $('#example').DataTable();
$('#example').on('draw.dt', function() {
console.log(table.ajax.json().recordsTotal);
});
So, for my own issue, instead of
.on('xhr.dt', function ( e, settings, json, xhr ) {
initCompleteFunction(settings, json);
})
I wrote
.on('draw.dt', function ( e, settings, json, xhr ) {
initCompleteFunction(settings, json);
})
Et voilà.
I got the needed solution.

Related

How do I return valid data from ajax call to DataTables child table?

I am returning data in json format from an ajax call to populate a child table that sits below the parent table. I get the following "DataTables warning: table id=child - Requested unknown parameter '1' for row 0, column 1. For more information about this error, please see http://datatables.net/tn/4". I have read the suggested information but unfortunately cannot relate it to my data. Any pointers in the right direction would be great please. The relevant code is:-
jQuery('#parent tbody').on( 'click', 'tr', function () {
var drno = (parentTable.row( this ).data()[4]);
jQuery.get("ajaxchild.php", {drno: drno}, function(data){
dataset = data;
//console.log(dataset) returns
/*
[["INV1","","2014-06-03","18.00","2.70"],["CRN6","","2014-10-20","6.00","0.90"],["REC4","","2014-06-20","13.80","0.00"],["REC5","","2014-10-24","5.00","0.00"],["P_C1","","2014-10-24","5.00","0.00"],["INV24","","2014-11-21","109.86","16.48"],["REC29","","2014-11-29","100.00","0.00"],["INV30","","2014-12-04","21.75","3.26"],["REC30","","2014-12-04","25.01","0.00"],["CRN23","","2014-12-04","21.75","3.26"],["REC34","","2014-12-20","1.16","0.17"],["REC40","","2015-01-30","200.00","0.00"],["REC44","","2017-02-15","5.00","0.00"],["REC45","","2017-02-15","10.00","0.00"]]
*/
var childTable = $('#child').DataTable( {
data: dataset,
columns: [
{ "title": "Reference" },
{ "title": "Our Ref." },
{ "title": "Date" },
{ "title": "Value" },
{ "title": "Tax" }
]
})
});
});
// Reload the child table when selecting parent row
// This will load the child table with the corresponding data
parentTable.on( 'select', function () {
childTable.ajax.reload();
} );
// Reload the child table when deselecting row
// The child script should return zero
// records to clear the table
parentTable.on( 'deselect', function () {
childTable.ajax.reload();
} );
Many thanks
Murray

JQuery DataTable data not available even data is received from server

I want to draw a table to show users data from my server.
First I am using Ajex to get the users data:
var usersList = {};
usersList.users = ["Afthieleanmah", "Hadulmahsanran","tabletest1"];
var dataSet1=[];
var i;
$.ajax({
url: '../users',
type: 'POST',
contentType: 'application/json',
cache: false,
data: JSON.stringify(usersList),
success:function(response, text){
if(response.users !== undefined){
dataSet1 = response.users;
}
}
});
I can successfully get the users data and save the data in dataSet1 as a JSON array contains Objects. Its format is like this:
[
{
username: "Tiger Nixon",
job_title: "System Architect",
city: "Edinburgh",
extn: "5421"
},
{
username: "Tiger Nixon2",
job_title: "System Architect",
city: "Edinburgh",
extn: "5421"
}
]
Then I create a table and pass in configuration:
// table confirgurations
var tableConfig={
pageLength: 5,
bLengthChange: false,
columns:[
{data: "username", title: "Name"},
{data: "job_title", title: "Position"},
{data: "city", title: "City"}
],
data:dataSet1
};
// create table
var userTable=$('#table-id').DataTable(tableConfig);
I am sure that I can get users data from API "/users" and save it into dataSet1. But everytime I load the page containing the table, the table always shows "No data available in table". I set a breakpoint on this line :
var tableConfig={
and let it continue to run. The weird things happen. The Table shows the data.............. No idea why
You should initialize your table after you receive response from the server in the success function. Also use destroy in case you're performin your Ajax request multiple times.
For example:
$.ajax({
// ... skipped ...
success:function(response, text){
if(response.users !== undefined){
dataSet1 = response.users;
}
// table confirgurations
var tableConfig={
// ... skippped ...
destroy: true
};
// ... skippped ...
var userTable=$('#table-id').DataTable(tableConfig);
}
});
However ideally you should let jQuery DataTables do the Ajax request using ajax option.

Column Visibility is not restored from a saved state via stateLoadCallback

I have added the Column Visibility button to choose to show or hide certain columns. I'm saving the state in a database, I call the stateSaveCallback function via a click on a button.
I cant find documentation about retrieving data this way, so I just link to the page and pass variables to get the data back from the database, and then load that using stateLoadCallback.
Now all this works fine, EXCEPT the column visibility is not restored. It is in the JSON data being returned though.
Here is my full code:
$(document).ready(function() {
$.extend( jQuery.fn.dataTableExt.oSort, {
"date-uk-pre": function (a){
return parseInt(moment(a, "DD/MM/YYYY").format("X"), 10);
},
"date-uk-asc": function (a, b) {
return a - b;
},
"date-uk-desc": function (a, b) {
return b - a;
}
});
var edit_date_col_num = $('th:contains("Edit Date")').index();
var entry_date_col_num = $('th:contains("Entry Date")').index();
var table = $('.mainTable').DataTable( {
pageLength: 50,
colReorder: true,
stateSave: true,
columnDefs: [
{ "type": "date-uk", targets: [ edit_date_col_num, entry_date_col_num ] }
],
dom: 'Blfrtip',
buttons: [
'copy', 'csv', 'excel', 'print',
{
extend: 'colvis',
collectionLayout: 'fixed four-column',
postfixButtons: [ 'colvisRestore' ]
}
],
<?php
$id = $this->input->get('id');
$action = $this->input->get('action');
if(isset($action) && $action == 'load' && isset($id) && $id != '') :
?>
"stateLoadCallback": function (settings) {
var o;
// Send an Ajax request to the server to get the data. Note that
// this is a synchronous request since the data is expected back from the
// function
$.ajax( {
"url": EE.BASE + "&C=addons_modules&M=show_module_cp&module=ion&method=state_save&action=load&id=<?php echo $id;?>",
"async": false,
"dataType": "json",
"success": function (response) {
response = JSON.parse(response);
o = response;
}
});
return o;
},
<?php
endif;
?>
initComplete: function (settings) {
this.api().columns().every( function () {
var column = this;
var select = $('<select><option value=""></option></select>')
.appendTo( $(column.footer()).empty() )
.on( 'change', function () {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column
.search( val ? '^'+val+'$' : '', true, false )
.draw();
} );
column.data().unique().sort().each( function ( d, j ) {
select.append( '<option value="'+d+'">'+d+'</option>' )
} );
} );
// Need to re-apply the selection to the select dropdowns
var cols = settings.aoPreSearchCols;
for (var i = 0; i < cols.length; i++)
{
var value = cols[i].sSearch;
if (value.length > 0)
{
value = value.replace("^", "").replace("$","");
console.log(value);
$("tfoot select").eq(i).val(value);
}
}
},
} );
// Save a datatables state by clicking the save button
$( ".save_state" ).click(function(e) {
e.preventDefault();
table.destroy();
$('.mainTable').DataTable( {
colReorder: true,
stateSave: true,
"stateSaveCallback": function (settings, data) {
var save_name = $('.save_name').val();
// Send an Ajax request to the server with the state object
$.ajax( {
"url": EE.BASE + "&C=addons_modules&M=show_module_cp&module=ion&method=state_save&action=save&save_name="+save_name,
"data": data,
"dataType": "json",
"type": "POST",
"success": function (response)
{
//console.log(response);
}
} );
},
});
//table.state.save();
window.location.replace(EE.BASE + "&C=addons_modules&M=show_module_cp&module=ion&method=applications");
});
$( ".clear_state" ).click(function(e) {
e.preventDefault();
table.state.clear();
window.location.replace(EE.BASE + "&C=addons_modules&M=show_module_cp&module=ion&method=applications");
});
} );
Here is the saved JSON with several visible false in the beginning (which are visible once loaded):
{"time":"1449338856556","start":"0","length":"50","order":[["0","asc"]],"search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"},"columns":[{"visible":"false","search":{"search":"","smart":"false","regex":"true","caseInsensitive":"true"}},{"visible":"false","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"false","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"false","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"false","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}},{"visible":"true","search":{"search":"","smart":"true","regex":"false","caseInsensitive":"true"}}],"ColReorder":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59","60","61","62","63","64","65","66","67","68","69","70"]}
Thanks
In my case datatables rejects old data according to "stateDuration" and "time" properties..
Solution: ignore state duration
"stateSave": true,
"stateDuration": -1,
Above case:
"visible":"false" may should be "visible":false
After a while of debugging this myself here's what worked for me..
This issue is that all the values in your JSON are strings and they need to be of correct datatypes for the datatables plugin.
Within the "stateSaveCallback" ajax request to save your state I did the following to the json string and then it saved all the values properly which then loaded the state as it should.
"stateSaveCallback": function (settings, data) {
var save_name = $('.save_name').val();
// Send an Ajax request to the server with the state object
$.ajax( {
"url": EE.BASE + "&C=addons_modules&M=show_module_cp&module=ion&method=state_save&action=save&save_name="+save_name,
//"data": data,
"data": JSON.stringify(data), // change to this..
"dataType": "json",
"type": "POST",
"success": function (response)
{
//console.log(response);
}
} );
},

Jquery Datatables expand row and get detail via Ajax

Is it possible to get the detail for each row through Ajax?
I found a starting point here:
http://datatables.net/release-datatables/examples/api/row_details.html
but it doesn't use ajax.
I'm thinking about modifying fnFormatDetails() function and place the ajax call there.
But i'm looking for another better answer.
Thanks.
It's very simple. All you have to do is put your details in a separate field within the "data" array:
E.g. your JSON might look like as follows:
{
"draw": "${drawId}",
"recordsTotal": "${totalRecords}",
"recordsFiltered": "${filteredRecords}",
"data": [
{
"empName": "${employee.name}",
"empNumber": "${employee.number}",
"empEmail": "${employee.email}",
"extraDetails" : [
["${employee.salary}", "${employee.title}"]
]
}
]
}
Then in your javascript, you can simply access this extra details by using JavaScript arrays. E.g.
var row = employeeTable.row( tr );
var rowData = row.data();
alert(rowData.extraDetails[0][0]);
alert(rowData.extraDetails[0][1]);
You need not to go for ajax if you have the data in your row.
Try oTable.fnGetData(rowIndexor|trNode)
you can try this and it will work.
First: create your datatable.
var table = $('#myTable').DataTable( {
ajax: '/api/staff',
columns: [
{
className: 'details-control',
orderable: false,
data: null,
defaultContent: ''
},
{ data: "name" },
{ data: "position" },
{ data: "office" },
{ data: "salary" }
],
order: [[1, 'asc']] } );
Second: Event handlers
$('#myTable tbody').on('click', 'td.details-control', function () {
var tr = $(this).closest('tr');
var row = table.row( tr );
if ( row.child.isShown() ) {
row.child.hide();
tr.removeClass('shown');
}
else {
row.child( format(row.data()) ).show();
tr.addClass('shown');
} } );
Third: Ajax request and formatting the response
function format ( rowData ) {
var div = $('<div/>')
.addClass( 'loading' )
.text( 'Loading...' );
$.ajax( {
url: '/api/staff/details',
data: {
name: rowData.name
},
dataType: 'json',
success: function ( json ) {
div
.html( json.html )
.removeClass( 'loading' );
}
} );
return div; }
you can pass any row argument to format method.
Check This For More Details

How update datatable without render all the table again?

I´m working with datatables for a meteor app.
My problem is that when some fields change all the table is rendered again, if I´m on page two on the table or I order by field, the table is rendered again and I´m back on the beginning.
My code:
Template.adminpage.rendered = function() {
$('#userData').dataTable({
"bDestroy":true,
"aaSorting": [[ 0, "desc" ]],
"bAutoWidth":false,
"bFilter": false,
"aoColumns": [
{ "bVisible": false },
null,
null,
null,
null,
null,
null,
null
],
"aaData": Template.adminpage.arrayUsersAdmin()
});
}
Array that populates the table:
Template.adminpage.arrayUsersAdmin=function() {
var adminUsers = allUserData.find({roles: 'basic'});
var arrayUserAdmin = [];
var count=0;
adminUsers.forEach(function(user) {
var idColumn = user._id;
var dateColumn=moment(user.createdAt).format("MMM Do HH:mm");
var usernameColumn=username;
var emailColumn=email;
arrayUserAdmin[count]=[
idColumn,
dateColumn,
usernameColumn,
emailColumn
];
count++;
});
return arrayUserAdmin;
}
Collection on the server:
if(Meteor.users.find({_id: this.userId}, {roles: 'admin'})){
Meteor.publish("allUserData", function () {
var self = this;
var handle = Meteor.users.find({}).observeChanges({
added: function(id, fields){
self.added("allUsersCollection", id, fields);
},
changed: function(id, fields){
self.changed("allUsersCollection", id, fields);
},
removed: function(id){
self.removed("allUsersCollection", id);
}
});
self.ready();
this.onStop(function() {
handle.stop();
});
});
}
Thanks for your time.
You can pass reactive: false as an option to find, which disables the underlying addition of a dependency, like so:
Template.adminpage.arrayUsersAdmin=function() {
var adminUsers = allUserData.find({roles: 'basic'}, reactive: false);
// Your code
return arrayUserAdmin;
}
This behaviour is documented here
Alternatively, if you would like the individual fields to update, you will have to add them in yourself. To do this, you can use allUserDate.find({roles: 'basic'}).observe. This will require you, however, to edit the HTML directly, and is quite messy. A better alternative would be to change your table structure entirely - don't use a data table, use a vanilla HTML table, and sort the data with minimongo queries.
Regardless, you can use observe like so:
allUserData.find({roles: 'basic'}).observe({
changed: function(newDocument, oldDocument) {
// Update table
}
});