So I'm using Electron.js, datables.net plugin, and child rows.
When I am updating data in the table, child rows stop working until I update data once more, and so on. So child-rows works only once per two data updates. I tried to make a loop where code executes two times, but no success. I got data from Postgres database.
var table = window.$('#table_id').DataTable({
data: data,
select: "single",
retrieve: true,
columns: [{
"className": 'details-control',
"orderable": false,
"data": null,
"defaultContent": '',
"render": function() {
return '<i class="fa fa-plus-square" aria-hidden="true"></i>';
},
width: "15px"
},
{"data": "fn"},
{"data": "username"},
{"data": "timestamp"},
{"data": "filename"},
{"data": "agent"},
{"data": "job_type"},
{"data": "progress"},
{"data": "status"},
{"data": "priority"},
],
"order": [
[1, 'asc']
]
});
myConsole.log("1")
window.$('#table_id tbody').on('click', 'td.details-control', function() {
var tr = window.$(this).closest('tr');
var tdi = tr.find("i.fa");
var row = table.row(tr);
if (row.child.isShown()) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
tdi.first().removeClass('fa-minus-square');
tdi.first().addClass('fa-plus-square');
} else {
// Open this row
row.child(format(row.data())).show();
tr.addClass('shown');
tdi.first().removeClass('fa-plus-square');
tdi.first().addClass('fa-minus-square');
}
});
window.$('#table_id').on("user-select", function(e, dt, type, cell, originalEvent) {
if (window.$(cell.node()).hasClass("details-control")) {
e.preventDefault();
}
});
function format(d) {
// `d` is the original data object for the row
return '<table cellpadding="5" cellspacing="0" border="0" style="padding-left:50px;">' +
'<tr>' +
'<td>Path:</td>' +
'<td>' + d.path + '</td>' +
'</tr>' +
'<tr>' +
'<td>Message::</td>' +
'<td>' + d.message + '</td>' +
'</tr>' +
'</table>';
}
window.$('#table_id').DataTable().clear().draw();
window.$('#table_id').DataTable().rows.add(data); // Add new data
window.$('#table_id').DataTable().columns.adjust().draw(); // Redraw the DataTable
So, problem was, that each time when i update data and code is running once more, another event listener is created. Code just open and close child row when there is even number of listeners, you just cant see it by eye :)
To fix this issue i added ".off('click')" in my code and now everything works as should.
window.$('#table_id tbody').off('click').on('click', 'td.details-control', function () {
Related
I have a html table with rows and child rows that are filled with data from a json array.
The problem I'm having are :
- The objects in the json array may or may not contain several object arrays, which need to be added as a child row.
- I can't get the array of child objects (interactions) out of the main object
An object of the json array is given below.
So far, I've managed to fill the table rows with data. I can also fill one child row, but only with data from the root of the object.
json object:
[
{
"name": "XXXXXXX",
"firstName": "XXXXXXX",
"contactnr1": "+123456789",
"wrapup": "WRAPUP",
"agent": "SUMO",
"date": "05/02/2019 10:10:30",
"totalAttempts": "2",
"interactions": [
{
"agent": "SUMO",
"interactionAlertStart": "02-05-2019 22:04:30",
"interactionStart": "02-05-2019 22:04:32",
"interactionCallStart": "02-05-2019 22:04:38",
"interactionCallEnd": "02-05-2019 22:05:04",
"interactionWrapupStart": "02-05-2019 22:05:16",
"interactionWrapupEnd": "02-05-2019 22:05:16",
"interactionEnd": "02-05-2019 22:05:26",
"interactionType": "XXXXX",
"interactionDuration": "54 s",
"queue": "XXXX",
"wrapup": "WRAPUP 1",
"dnis": "tel:+123456789"
},
{
"agent": "SUMO",
"interactionAlertStart": "02-05-2019 22:10:29",
"interactionStart": "02-05-2019 22:10:36",
"interactionCallStart": "02-05-2019 22:10:52",
"interactionCallEnd": "02-05-2019 22:11:00",
"interactionWrapupStart": "02-05-2019 22:11:12",
"interactionWrapupEnd": "02-05-2019 22:11:12",
"interactionEnd": "02-05-2019 22:11:14",
"interactionType": "Callback",
"interactionDuration": "37 s",
"queue": "YYYY",
"wrapup": "WRAPUP 2",
"dnis": "tel:+987654321"
}
]
},
++++++++++++++++++++++
javascript:
// function for formatting row details
function format (d) {
// 'd' is the original data object for the row
return '<table cellpadding="5" cellspacing="0" border="0" style="padding-left:50px;">' +
'<tr>' +
'<td>Agent:</td>' +
'<td>Datum:</td>' +
'<td>Contactnr:</td>' +
'<td>' + d.queue+ '</td>' +
'</tr>' +
'<tr>' +
'<td>Contactnummer:</td>' +
'<td>' + d.interactionStart+ '</td>' +
'</tr>' +
'<tr>' +
'<td>TotaalPoging</td>' +
'<td>' + d.interactionEnd+ '</td>' +
'</tr>' +
'</table>';
}
$(document).ready(function() {
var table = $('#example').DataTable({
'ajax': {
'url': 'http://127.0.0.1:8088/campaigns/contacttable?orgName=xxx&campaignId=yyyy-yyyy-yyyy-yyyy',
'dataSrc': ''
},
'columns': [
{
'className': 'com-table',
'orderable': false,
'data': null,
'defaultContent': ''
},
{'data': 'name'},
{'data': 'firstName'},
{'data': 'contactnr1'},
{'data': 'totalAttempts'}
],
'order': [[1, 'asc']]
});
});
So to conclude: I want to dynamically add the data from the interactions as child rows. An object can have multiple interactions, only one interaction, or no interction.
My current javascript code is below the json array
If I understood well, you want to build the table based on this interactions array. I would start processing it. I recommend you to using the .map() method to create an array of rows.
function processResponse(res){
var interactions = response[0].interactions;
// If no interactions, you may to return a single row
if(!interactions || interactions.length === 0){
return '<tr><td>No interactions to display.</td></tr>'
}
var interactionsRows = interactions.map(function(interaction){
return '<tr>' +
'<td>Agent:</td>' +
'<td>Datum:</td>' +
'<td>Contactnr:</td>' +
'<td>' + interaction.queue+ '</td>' +
'</tr>' +
'<tr>' +
'<td>Contactnummer:</td>' +
'<td>' + interaction.interactionStart+ '</td>' +
'</tr>' +
'<tr>' +
'<td>TotaalPoging</td>' +
'<td>' + interaction.interactionEnd+ '</td>' +
'</tr>'
});
// Concatenate the rows into one string
return interactionsRows.join();
}
Once I processed the response, I just need to concatenate it in the table.
document.getElementById('table').innerHTML = processResponse(response)
See the snippet code working here.
Note you should use the DOM API to manipulate HTML elements in a better way instead to inject strings using .innerHTML. It's easier using JQuery.
I have the following datatable. Its got a list of columns. Last column is a checkbox.
I want to get list of all rows which has the checkbox ticked? is it possible to get all datatable rows with the checkbox checked? my datatable is like below
$.fn.dataTable.moment('DD.MM.YYYY');
$('#bankReconDataListing tbody').off('click');
RECON_DATATABLE = $('#bankReconDataListing').DataTable({
"language": __DT,
"select": true,
"order": [
[1, "desc"]
],
"searchable": true,
"destroy": true,
"sAjaxSource": '/bankReconciliationGetData?coa=' + coa + '&toDate=' + toDate + '&fromDate=' + fromDate,
"sAjaxDataProp": "",
"bLengthChange": false,
"pageLength": 20,
"aoColumns": [{ //document date : 0
"mDataProp": null,
{ //Document type //5
//balance
"mDataProp": null,
render: function(data, type, row) {
return data.doctype;
}
},
render: function(data, type, row) {
return "<input type='checkbox' name='" + checkBoxName + "' data-tableinput='checkbox' " +
"id='checkBox" + reconJrnlId + "' value='" + reconJrnlId + "' checked='checked' />";
}
}],
"columnDefs": [],
"initComplete": function() {}
});
Give a class name to your checkbox column, say checkboxclass.
Then,
$('.checkboxclass:checked',table.fnGetNodes()).each(function(){
//what you want to do
}
You could attach an event handler to the checkboxes in the table. Whenever a checkbox is clicked, that row gets added to an array. If it's unchecked, you remove it from the array.
This is untested but something like this should work:
let arr = [];
$("#tableDiv tbody").on("click", "input[type='checkbox']", function(e) {
let row = $(this).closest('tr');
// Get row data
let data = table.row(row).data();
if (this.checked) {
// Add to array
arr.push(data);
} else {
arr.splice(arr.indexOf(data), 1);
}
});
#tableDiv is just the table's container. You could use whatever other selector is appropriate depending on your application.
I have a jQuery's datatable which gets filled up with server side data like this:
"columns": [
{
"targets": -1,
"data": "ImageURL",
"name": "Title",
"render": function (data, type, row) {
return '<td><div class="tableimage"><img src="' + data + '"/></div></td>'; //'<td><img src=' + data + '></td>';
}
},
{
"data": "Title",
"name": "Title",
"render": function (data, type, row) {
return '<td>' + data + '</td>';
}
},
{
"data": "CurrentPrice",
"name": "CurrentPrice",
"render": function (data, type, row) {
return '<td>$ ' + data + '</td>';
}
},
]
And this is fine, each column gets generated and rendered in my browser like this:
<tr>
// generated td's here...
<tr>
Now my question here is whether I can generate a custom tr tag with specially added class?
Something like this:
<tr class="myclassNameGoesHere">
</td>
Is this doable via server side data processing & jquery's datatables ?
P.S. I tried something like this:
$(row).addClass("alert-danger");
// or
row.className = "alert-danger";
But neither of these worked... :/
Firstly, you don't need to return td tags in render functions, datatables automatically created td tags for you.
So,
return '<td>' + data + '</td>';
would become
return data;
Now, to answer your question, use createdRow callback provided by datatables.
Like,
$('#example').dataTable( {
"createdRow": function( row, data, dataIndex ) {
$(row).addClass( 'alert-danger' );
}
} );
I have an ajax backed dynatable. At the moment, it works perfectly for tables with known headers prior.
Example:
var tableHeaders = '';
// Generate table headers from some list
$scope.Model.computed.selection_list.map(
function(selection){
column_name = selection.table + "." + selection.column;
tableHeaders += "<th>" + column_name + "</th>";
});
//wipe div hosting the dynatable and reinitialise a table
var table_div = $('#TableDiv');
table_div.empty();
table_div.append('<table id="previewTable" class="table table-condensed table-responsive table-striped table-hover"><thead><tr>' + tableHeaders + '</tr></thead></table>');
var preview_table = $('#previewTable');
console.log("Table wiped");
//initialise the dynatable
preview_table.dynatable({
features: {
perPageSelect: true,
search: false
},
table: {
defaultColumnIdStyle: 'underscore',
headRowSelector:'thead tr',
headRowClass: ''
},
dataset: {
ajax: true,
ajaxUrl: data_url,
ajaxOnLoad: false,
ajaxMethod: 'POST',
records: []
}
});
However, I'd like to have the table headers generated after fetching the records but prior to filling out the rows.
Is this possible?
// Changing via an ajax success event hook doesn't work.
// The table headers change but the records don't bind to the correct column leaving every row as null
preview_table.bind('dynatable:ajax:success', function(e, response){
console.log("Ajax response: " + response) ;
tableHeaders = '';
first_record = response.records[0];
Object.keys(first_record).map(function(column_name){
tableHeaders += "<th>" + column_name + "</th>";
}
)
preview_table.html('<thead><tr>' + tableHeaders + '</tr></thead>')
console.log("headers: " + tableHeaders);
})
I had exactly the same problem and after hours of struggling I came up with this solution:
First, your initial TABLE should look like this:
<table id="my-table">
<thead>
<tr><th></th></tr>
</thead>
<tbody>
</tbody>
</table>
We need the empty TH to prevent the plugin from throwing an error (Couldn't find any columns headers in...), it will be removed later.
Then we use the dynatable:ajax:success to edit the columns as follow:
$("#my-table").one('dynatable:ajax:success', function(e, response){
//Get dynatable
var dynatable = $(this).data('dynatable');
//Remove the empty column
dynatable.domColumns.remove(0);
//Add new columns
var pos = 0;
for(var column in response.records[0]) {
dynatable.domColumns.add($('<th>'+column+'</th>'), pos++);
}
});
Finally, you can initiate the plugin:
$("#my-table").dynatable({
features: {
perPageSelect: true,
search: false
},
table: {
defaultColumnIdStyle: 'underscore',
headRowClass: ''
},
dataset: {
ajax: true,
ajaxUrl: data_url,
ajaxOnLoad: false,
records: []
}
});
Check the following demo, please note that the snippet is not fully functional it throws (SecurityError). Here is a fully working jsfiddle:
var data_url = "https://gist.githubusercontent.com/iRbouh/47a9fb7e5f6a79e0f4b0e7e8a837a825/raw/6adbba47bfbf9453c50f9710f77c71e69f683139/sample-data.json";
var preview_table = $('#my-table');
preview_table.one('dynatable:ajax:success', function(e, response){
//Get dynatable
var dynatable = $(this).data('dynatable');
//Remove init column
dynatable.domColumns.remove(0);
//Add new columns
var pos = 0;
for(var column in response.records[0]) {
dynatable.domColumns.add($('<th>'+column+'</th>'), pos++);
}
});
preview_table.dynatable({
features: {
perPageSelect: true,
search: false
},
table: {
defaultColumnIdStyle: 'underscore',
headRowClass: ''
},
dataset: {
ajax: true,
ajaxUrl: data_url,
ajaxOnLoad: false,
records: []
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link href="https://cdn.rawgit.com/alfajango/jquery-dynatable/master/jquery.dynatable.css" rel="stylesheet"/>
<script src="https://cdn.rawgit.com/alfajango/jquery-dynatable/master/jquery.dynatable.js"></script>
<table id="my-table">
<thead>
<tr><th></th></tr>
</thead>
<tbody>
</tbody>
</table>
I want to implement a Datatable into a theme, which gets the data via an Ajax Request. Once the document is loaded, I build the HTML part for the datatable. The problem is: Once I click a sort function (for example sort one row ascending) it uses the original data to sort (which is given in the .php file) instead of the new JQuery loaded datatable. So probably I need to reinitialize the datatable or anything else?
HTML Part:
<tbody id="accountList">
<!-- List all accounts -->
<tr>
<td>username#hostname-de</td>
<td>PS</td>
<td>350000</td>
<td>45000</td>
<td>Victor Ibarbo</td>
<td>30 / 30</td>
<td>224500</td>
<td><label class="label label-success">Online</label></td>
</tr>
</tbody>
JQuery part:
function buildAccountList(){
$.ajax({
url: "/database/accounts.php",
type: "POST",
data: {action: "selectAccounts"},
success: function (response) {
var opt = '';
$.each(response, function(i, e){
opt +='<tr>';
opt += '<td>' + e.email + '</td>';
opt += '<td>' + e.platform + '</td>';
opt += '<td>' + e.coins + '</td>';
opt += '<td>' + e.password + '</td>';
opt += '<td>' + e.tradepileCards + '</td>';
opt += '<td>' + e.tradepileValue + '</td>';
opt += '<td>' + e.enabled + '</td>';
opt += '</tr>';
});
$('#accountList').html(opt);
},
dataType: "json"
});
}
The creation of the table works fine, but as I described, once I press a sort function it uses the old table (given by the html file). I hope you guys can help me.
Are you using the jQuery DataTables plug-in? If so, they already have built-in functionality for ajax data sources: DataTables with AJAX
Alternatively, I think you should rather try to modify the table data itself in javascript instead of the rendered HTML. Using the DataTable API, especially table.clear(), table.rows.add() followed by a table.draw()(also check here), you should be able to update the data properly and use the order functionality afterwards.
In response to the comment:
Basically something like this should be enough as an initialization of the datatable:
$(document).ready(function() {
$('#example').dataTable( {
"ajax": 'your url here'
});
});
Then your json should be organized as:
{
"data": [
[
'your columns',
...
],
]
}
If you want to not name the top-level key of your data 'data' you could set it by initializing with
"ajax": {
"url": "data/objects_root_array.txt",
"dataSrc": "your top-level key (or nothing for a flat array"
}
And as last option you can use objects instead of arrays in your ajax by adding a columns option to the initialization:
"ajax": ...,
"columns": [
{ "data": "email" },
{ "data": "platform" },
{ "data": "coins" },
...
]
and return json with objects like that:
{
"email": "some#email.com",
"platform": "PS",
"coins": "320,800",
...
}
By the way, using this you would not even have to add a tbody to the table in the first place at it should be automatically be created by the plugin once it gets the AJAX data.