I have an asp.net web application that has the option to provide pseudo-realtime data about an automation machine. I am using the JQuery Datatables with an ajax datasource. I have an interval that reloads the data source every set amount of time (which updates my datatable asynchronously from the db) and then redraws the table.
I am also using the responsive plug in for the table, so the web app can be accessed well from phone sized devices. I have set this up so that it drops all of the columns but the first(primary) column and adds the other columns a child (detail) record. This is where my app breaks and my phone users loose usability. This is because whenever the table redraws detail records snaps close. Therefore if a phone user is looking at the table and has expanded the detail of a record the record will snap shut as soon as the table is redrawn.
My solution would be to capture the opened detail and then at the time of redraw re-open the detail. I believe I have captured the detail successfully but everything I have found to try to programmatically expand it has not worked.
$(document).ready(function () {
var row;
var tr;
var table = $('#myDataTable').DataTable({
autoWidth: false,
processing: false,
stateSave: true,
sAjaxSource: '#Url.Action("GetDropData", "Drops")',
"columns":
[
{ "width": "10%" },
{ "width": "50%" },
{ "width": "40%" }
]
});
var timer = setInterval(function () {
table.ajax.reload(null, false);
}, 1000);
//flag is used to determine if last click expanded a detail
var flag = false;
//If table is clicked find closest 'tr'
table.on('click', 'tr', function () {
tr = $(this).closest('tr');
row = table.row(tr);
//was click a detail expansion
if (row.child.isShown()) {
flag = true;
}
})
// event fires after ajax call completes (reload and redraw)
$('#myDataTable').on('xhr.dt', function () {
if (flag) {
$(tr).addClass('row_selected');
}
});
});
If you can tell why the detail isn't expanded or a better way solution please let me know. I do have a temporary solution in place that just pauses the interval when the detail button is clicked but this makes my phone users table not update.
If you're using Datatables 1.9 and earlier use fnDrawCallback().
If you're using Datatables 1.10+ use drawCallback().
Both of these callbacks go in your datatables initializer and can take your row detail opening code.
$(document).ready( function() {
$('#example').dataTable( {
"fnDrawCallback": function( oSettings ) {
//open detail row here
}
} );
} );
Related
I'm using ag-grid (javascript) to display a large amount of rows (about 3,000 or more) and allow the user to enter values and it should auto-save them as the user goes along. My current strategy is after detecting that a user makes a change to save the data for that row.
The problem I'm running into is detecting and getting the correct values after the user enters a value. The onCellKeyPress event doesn't get fired for Backaspace or Paste. However if I attach events directly to DOM fields to catch key presses, I don't know how to know what data the value is associated with. Can I use getDisplayedRowAtIndex or such to be able to reliably do this reliably? What is a good way to implement this?
EDIT: Additional detail
My current approach is to capture onCellEditingStopped and then getting the data from the event using event.data[event.column.colId]. Since I only get this event when the user moves to a different cell and not just if they finish typing I also handle the onCellKeyPress and get the data from event.event.target (since there is no event.data when handling this event). Here is where I run into a hard-to-reproduce problem that event.event.target is sometimes undefined.
I also looked at using forEachLeafNode method but it returns an error saying it isn't supported when using infinite row model. If I don't use infinite mode the load time is slow.
It looks like you can bind to the onCellKeyDown event. This is sometimes undefined because on first keydown the edit of agGrid will switch from the cell content to the cell editor. You can wrap this around to check if there is a cell value or cell textContent.
function onCellKeyDown(e) {
console.log('onCellKeyDown', e);
if(e.event.target.value) console.log(e.event.target.value)
else console.log(e.event.target.textContent)
}
See https://plnkr.co/edit/XhpVlMl7Jrr7QT4ftTAi?p=preview
As been pointed out in comments, onCellValueChanged might work, however
After a cell has been changed with default editing (i.e. not your own custom cell renderer), the cellValueChanged event is fired.
var gridOptions = {
rowData: null,
columnDefs: columnDefs,
defaultColDef: {
editable: true, // using default editor
width: 100
},
onCellEditingStarted: function(event) {
console.log('cellEditingStarted', event);
},
onCellEditingStopped: function(event) {
console.log('cellEditingStopped', event);
},
onCellValueChanged: function(event) {
console.log('cellValueChanged', event);
}
};
another option could be to craft your own editor and inject it into cells:
function MyCellEditor () {}
// gets called once before the renderer is used
MyCellEditor.prototype.init = function(params) {
this.eInput = document.createElement('input');
this.eInput.value = params.value;
console.log(params.charPress); // the string that started the edit, eg 'a' if letter a was pressed, or 'A' if shift + letter a
this.eInput.onkeypress = (e) => {console.log(e);} // check your keypress here
};
// gets called once when grid ready to insert the element
MyCellEditor.prototype.getGui = function() {
return this.eInput;
};
// focus and select can be done after the gui is attached
MyCellEditor.prototype.afterGuiAttached = function() {
this.eInput.focus();
this.eInput.select();
};
MyCellEditor.prototype.onKeyDown = (e) => console.log(e);
// returns the new value after editing
MyCellEditor.prototype.getValue = function() {
return this.eInput.value;
};
//// then, register it with your grid:
var gridOptions = {
rowData: null,
columnDefs: columnDefs,
components: {
myEditor: MyCellEditor,
},
defaultColDef: {
editable: true,
cellEditor: 'myEditor',
width: 100
},
onCellEditingStarted: function(event) {
console.log('cellEditingStarted', event);
},
onCellEditingStopped: function(event) {
console.log('cellEditingStopped', event);
}
};
Please refer to my test case
https://jsfiddle.net/1c3Lmace/13/
This is my code
$(document).ready(function() {
$('#example').DataTable( {
dom: 'C<"clear">lfrtip',
"fnPreDrawCallback": function( oSettings ) {
alert('pre');
},
"fnDrawCallback" : function() {
alert('+++++');
}
} );
} );
When you go to Show/Hide Columns and click on any column item you will see that each preDrawCallBack and drawCallback event fires twice.
Does anyone having any idea why it happens.
I want to show a loader before data loads and hide it and when data is successfully loaded. Any help is appreciated
Thanks
Indeed the events are fired twice but only when sorted column visibility is being toggled.
I see no point in showing loading indicator for client-side processing, column visibility changes occur very fast. For server-side processing, there is processing option already available.
You can do something like this. But I had to put an alert() because columns are toggled very fast and Processing... message disappears quickly.
$(document).ready(function() {
$('#example').DataTable( {
dom: 'C<"clear">lfrtip',
processing: true,
drawCallback : function() {
$('.dataTables_processing', $('#example').DataTable().table().container()).hide();
}
} );
} );
$('#example').on( 'column-visibility.dt', function ( e, settings, column, state ) {
$('.dataTables_processing', $('#example').DataTable().table().container()).show();
alert('Column visibility is toggled');
} );
See this jsFiddle for code and demonstration.
Following is the code found in data table website in order to remove the paging.
$(document).ready(function() {
$('#example').DataTable( {
"paging": false
} );
} );
My question is how to enable and disable paging on button click.
as when i call DataTable function second time to same table. It shows error that data table is already initiated and im calling it second time.
simply recreate the dataTable using destroy: true and paging:
I wanted to show only the first 10 rows of the table, but still be able to sort the whole table. But I also wanted the ability to click a link and show the whole table.
Here's what I did: (my table is "ka_ad")
First, turn on paging
table_ad = $('#ka_ad').DataTable({
paging: true,
});
Second (optional: I didn't want to display the datatable pagination links and element, so I hid them with css
#ka_ad_length{display: none;}
#ka_ad_paginate{display: none;}
Lastly, toggle the bPaginate setting (I have a button with an ID of "test"):
$('#test').click( function () {
//console.log(mytable.settings()[0]['oFeatures']['bPaginate'] );
if(table_ad.settings()[0]['oFeatures']['bPaginate'] == false)
{
table_ad.settings()[0]['oFeatures']['bPaginate'] = true;
$('#test').html('Show All Rows');
}
else
{
table_ad.settings()[0]['oFeatures']['bPaginate'] = false;
$('#test').html('Show Fewer Rows');
}
table_ad.draw();
});
Try like this.
var oTable;
$(document).ready(function() {
oTable = $('#example').DataTable( {
"paging": false
} );
$('.btn').click( function () {
oTable.paging= false;
oTable.fnDraw();
});
} );
try this:(but i don't guarantee, because, i haven't tested)
var oTable = $('#example').dataTable();
// get settings object after table is initialized
var oSettings = oTable.fnSettings();
oSettings.paging = false;
$(".button").click(function(){
oSettings.paging = !oSettings.paging;
});
https://www.datatables.net/forums/discussion/16373/enable-disable-features-after-initializing-the-table
I have several data listed on the jquery dataTable and its done pagination by the DataTable plugins default. I want to get the current page of the dataTable while processing the data and set that page into active after the action is processed and reload the data.
See this fiddle. You can see how to get the current pages. In the JSFiddle you can try refresh browser. Example let say the current page now is 3. When you refresh the browser, you still in page 3.
To solve your problem want to go back to the last page when editing or deleting row, u must use this option to make jquery datatable remember where the last page. Jquery Datatable will save the state of a table (its paging position, ordering state etc). The state saving method uses the HTML5 localStorage and sessionStorage APIs for efficient storage of the data. See this link to read more detail about it. State saving
"bStateSave": true
JSFiddle Link
Fiddle Demo
Javascript code
$(document).ready(function() {
var table = $('#example').DataTable({
"sPaginationType": "full_numbers",
"bStateSave": true
});
$("#example").on('page.dt', function () {
var info = table.page.info();
$('#pageInfo').html('Currently showing page ' + (info.page + 1) + ' of ' + info.pages + ' pages.');
});
} );
Use only stateSave: true
like this:
$(document).ready(function() {
$('#tableId').DataTable( {
stateSave: true
} );
})
Copied from Datatable
var table = $('#example').DataTable( {
ajax: "data.json"
} );
setInterval( function () {
table.ajax.reload( null, false ); // user paging is not reset on reload
}, 30000 );
Pass null, false on reload function to stay on that page while reloading the table. See ajax.reload() documentation for more information.
See the dataTables documentation which provides a call back function from which you can obtain the current page:
$('#example').dataTable( {
"drawCallback": function( settings ) {
var api = new $.fn.dataTable( settings );
// Output the data for the visible rows to the browser's console
// You might do something more useful with it!
console.log( api.rows( {page:'current'} ).data() );
}
});
Add this where you are initializing datatable
"drawCallback": function( settings ) {
alert ( 'You are on ssame page' );
}
It works for me :)
I'm aware there's a similar question on here JQuery DataTables: How to show/hide row details with multiple tables? but that doesn't apply to my current problem completely.
I have the code:
var oTable = $('.dataTable').dataTable( {
"aoColumnDefs": [
{ "bSortable": false, "aTargets": [ 0,3,4 ] },
{ "bVisible": false, "aTargets": [ 4 ] }
],
"aoColumns": [
null,
null,
null,
null,
{ "sType": "html" }
],
"aaSorting": [[1, 'asc']],
"bFilter": false,
"bPaginate": false,
"fnInitComplete": function(oSettings) {
/* Add event listener for opening and closing details
* Note that the indicator for showing which row is open is not controlled by DataTables,
* rather it is done here
*/
$('.dataTable tbody td img').live('click', function () {
var nTr = this.parentNode.parentNode;
if (oTable.fnIsOpen(nTr)) {
// This row is already open - close it
this.src = "css/images/details_open.png";
oTable.fnClose(nTr);
} else {
// Open this row
this.src = "css/images/details_close.png";
oTable.fnOpen(nTr, fnFormatDetails(oTable, nTr), 'details');
}
} );
}
});
That works if there's only one if I add the dataTable class to a second table, then they work as datatables but the show/hide buttons fail in both tables. Both tables have the same count of fields and content, just for the sake of making it work, but still no success.
On the similar post, the person suggests adding:
tbl = $(this).parent().parent().dataTable();
to the click function but I have tried that and it didn't work.
What am I missing??
In short: get rid of the fnInitComplete, and move the "live" call to below the dataTable call.
As an example, if you have three tables, after each table is completed, your current code will execute the fnInitComplete method - so fnInitComplete gets called 3 times. Your fnInitComplete uses a selector to "live" the click event to an img, and the selector will "live" to all tables. This results in multiple bindings. See this jsfiddle, http://jsfiddle.net/KeVwJ/, which duplicates your method. (Note that I'm not using images so only capturing click on the td cell, not an image).
var oTable = $('.dataTable').dataTable( {
"bFilter": false,
"bPaginate": false,
"fnInitComplete": function(oSettings) {
$('.dataTable tbody td').live('click', function () {
var nTr = this.parentNode;
alert(nTr);
} );
}
});
If you click on any row in the table, you will get 3 alert boxes, because 3 tables are created and they each "live" click for all tables at fnInitComplete.
To fix, remove the fnInitComplete, and put the code for "live" after the call to dataTable. That should solve it. See this jsfiddle: http://jsfiddle.net/rgMNu/ Click on any row in the table and it will identify the correct table class. Again since I am capturing the click on td, I only have to do this.parentNode.parentNode.parentNode. I think you'll have to do another level.
$('.dataTable tbody td').live('click', function ()
{
var t = this.parentNode.parentNode.parentNode;
alert(jQuery(t).attr('class'));
} );