I have several options for my JQuery datatable which will clear the DataTable and load new data via WebSockets. Therefore I clear the Table contents with fnClearTable()and a few moments later I get the new data via my WebSocket.
This can last up to a few seconds and in the meantime I would like to display a loading image in my DataTable. How can I achieve this?
My event handler which clears the DataTable:
/* On Daterange change (e.g. Last 3 Days instead of Last 24h) */
$('#profitList_dateRange').change(function() {
var dateRangeHours = $("#profitList_dateRange").val();
var jsonParamObject = JSON.parse(dateRangeHours);
// Clear table
var profitList = $('#profitList').dataTable();
profitList.fnClearTable(); // Now I want to show the loading image!
socket.emit('load-statistics', (jsonParamObject));
});
One way to achieve it is if you have 2 divs (I assume that your divs are properly styled to the content inside of them):
<div id="profitList"> your table content </div>
<div id="profitListLoading"> show loading here </div>
Then in your handler:
$('#profitList_dateRange').change(function() {
var dateRangeHours = $("#profitList_dateRange").val();
var jsonParamObject = JSON.parse(dateRangeHours);
// Clear table
var profitList = $('#profitList').dataTable();
profitList.fnClearTable(); // Now I want to show the loading image!
$('#profitList').hide();
$('#profitListLoading').show();
socket.emit('load-statistics', (jsonParamObject));
});
In your handling of loaded data you should ofc. revert the change
$('#profitList').show();
$('#profitListLoading').hide();
Make sure you have processing: true
$('#example').dataTable({
processing: true
});
Then add:
$('.dataTables_processing', $('#example').closest('.dataTables_wrapper')).show();
If you want to add a GIF image you can change the markup as follows:
$('#example').dataTable({
oLanguage: {
sProcessing: "<img src='https://d13yacurqjgara.cloudfront.net/users/12755/screenshots/1037374/hex-loader2.gif'>"
},
processing: true
});
DEMO: http://jsfiddle.net/0m6uo54t/2
processing:
Enable or disable the display of a 'processing' indicator when the
table is being processed (e.g. a sort). This is particularly useful
for tables with large amounts of data where it can take a noticeable
amount of time to sort the entries.
https://datatables.net/reference/option/processing
[UPDATE] bProcessing is the legacy option, the new DT code uses processing
Related
I am trying to run a report with two tabulator tables. One main table, then on click of a row it will populate a modal. All the html part works and the jquery (JS) works. I have a success function on my ajax call to set the data in the modal. But it does not seem to be waiting for the ajax to return the data. See code below. I can see the data in the console.log so the console.log seems to be running its just not pushing to the table. If I run a function to set the data manually from the console it works. So not really sure whats going on.
var CatVolumetable = new Tabulator("#myreport", {
//height:205, // set height of table (in CSS or here), this enables the Virtual DOM and improves render speed dramatically (can be any valid css height value)
placeholder:"Select Year-Month to populate Data",
layout:"fitColumns", //fit columns to width of table (optional)
columns:[ //Define Table Columns
{title:"Category Name", field:"Category_name", align:"left"},
{title:"State", field:"State",align:"center"},
{title:"Max Quantity",field:"maxQuantity", align:"left"},
],
rowClick:function(e, row){ //trigger an alert message when the row is clicked
var state = row.getData().State;
//getStoresByState(state);
$('#drilldown').modal('toggle');
let myUrl = 'http://localhost:3000/view_state_category_volume_drilldown/'+state;
$.ajax({
//$.ajax({
url: myUrl,
method: 'get',
dataType: 'json',
success: function(data){
console.log(data);
ddtable.setData(data);
}
});
var ddtable = new Tabulator("#drilldownTable", {
//height:205, // set height of table (in CSS or here), this enables the Virtual DOM and improves render speed dramatically (can be any valid css height value)
//ajaxURL:""
placeholder:"No Data Available",
layout:"fitColumns", //fit columns to width of table (optional)
columns:[ //Define Table Columns
{title:"Manager_email", field:"Manager_email"},
{title:"Manager_name", field:"Manager_name", align:"left"},
{title:"Store_num", field:"Store_num"},
{title:"Street_address", field:"Street_address", align:"center"},
{title:"City Name", field:"City_name", align:"center"},
],
});
SOLUTION:
I figured out the problem is that the data must be loaded after the modal is toggled (i.e. after it is visible). If I load data on the show event listener it works perfectly. Below is code with bootstrap.
$("#drilldown").on('shown.bs.modal', function (e){
///Ajax call with success handler to load data
})
If the API is too fast for your second tabulator table
Check this post
.Use below code to set Data after drilldownTable is initialized
if ($("#drilldownTable").hasClass("tabulator")){
//element has class of .tabulator
}
I have the tabulator plugin set up and working with my data. Currently, using the remote pagination feature but whenever the pagination buttons are clicked it loads the data and then scrolls to the top of the page. The pagination buttons do not contain href="#" so it shouldn't be trying to load a browser state.
The really odd thing is it is doing this behavior on any ajax call I make relative to tabulator. I used the setData function to load updated data and it scrolled to the top of the page again.
Here's a very simplified version of my code:
<div id="#tabulator"></div>
<script>
$("#tabulator").tabulator({
movableColumns: true,
layout: "fitColumns",
pagination: "remote",
paginationSize: 10,
ajaxURL: "rosterusers_tabulator_data-json.cfm",
ajaxParams: {/* url params here */},
columns: [/* columns set here*/]
});
/*then I have a modal dialog update event which calls the following*/
$("#tabulator").tabulator(
"setData",
"rosterusers_tabulator_data-json.cfm",
{/*url params here*/}
);
</script>
I don't think I'm doing anything bizarre here but each time the table data gets updated via ajax in anyway (page change, data change, filter change, etc.) it scrolls to the top of the page.
Here is solution for various scroll to top related issues. It involves extending the tabulator.js with two functions:
Tabulator.prototype.getVerticalScroll = function () {
var rowHolder = this.rowManager.getElement();
var scrollTop = rowHolder.scrollTop;
return scrollTop;
}
Tabulator.prototype.setVerticalScroll = function (top) {
var rowHolder = this.rowManager.getElement();
rowHolder.scrollTop = top;
}
Then get and set like this:
let pos = table.getVerticalScroll();
// do table management e.g. setColumns
table.setVerticalScroll(pos);
The replaceData function can be used to set data in the table without changing the scroll position:
$("#example-table").tabulator("replaceData", "rosterusers_tabulator_data-json.cfm")
I am using Datatables JQuery plugin in order to show data on a table.
In one of the columns I have added also a button to edit the rows.
What I am trying to do is when I click one of the buttons, to deactivate all the others.
Here is my current code together with a screenshot:
$(document.body).on("click", "._edit_save_btn",function(e){
var id = this.id; // get id of selected btn
// disable all other buttons but selected
$("._edit_save_btn").not("#"+id).prop('disabled', true);
)};
Although this works fine for the first page of data (paginated presentation), when I change page, it seems like that the property disabled is not applied.
Thus I can click any other button in order to add the property disabled.
I thought by using the on click event things would work. What am I missing here?
EDIT
The table is created automatically using DataTables jquery plugin and jquery functionality.
On page load my html structure looks like this:
<table id="example">
<thead id="table_head">
</thead>
</table>
Then the table is populated with data coming from Django. The button element looks like this:
edit_btn = '<button id="' + row_id + '" class="btn btn-info btn-sm _edit_save_btn" style="background-color:#a7a3a3;border-color:#a7a3a3">Edit</button>'
EDIT_2
This screenshot explains better what I mean with pagination and changing pages. Please check the lower right corner to see the pagination. When I go to another page (e.g. from 1 to 2) then I see that the disabled property wasnot applied for the buttons on that page:
EDIT
With the help of #Sherin Jose I have managed to reach to this point:
var disable_buttons = function(class_exists){
if (class_exists){
alert("dfdf")
$("._edit_save_btn").not(this).prop('disabled', true);
}
};
$("#example").dataTable({
"scrollX": true,
"aaData":whole_array
}).on( 'page.dt', function () {
class_exists = $("button").hasClass("clicked");
//alert(class_exists)
disable_buttons(class_exists)
});
Whenever a user clicks a button, then the button gets a class called clicked.
Then in the disable_buttons function, I check if this class exists (the 'clicked' class). If it exists I want to disable the other buttons on page change event.
The issue I am facing now is that the
on( 'page.dt', function () {
is executed before the datatable is loaded!
Try this one,
//define the disable feature as a function
var disable_buttons = function(){
$("._edit_save_btn").unbind("click").click(function(e){
// disable all other buttons but selected
$("._edit_save_btn").not(this).prop('disabled', true);
});
};
//call the above function on dataTable init and page change events like:
$("#example").dataTable({
"scrollX": true,
"aaData":whole_array,
"fnDrawCallback":function () {
disable_buttons();
}
});
The Datatables plugin is giving me some issues when trying to highlight rows beyond the first paginated page.
In the JS below you will see the commented out code where I am adding the class info to all the rows. When I do this and you paginate to the other pages all the rows on the other pages are highlighted. You will also see the uncommented code below where I add the class info to all the rows but the first row but in this case when I paginate to the other pages the rows are not highlighted.
Does anyone have any ideas on why this might be happening?
JSFiddle:
https://jsfiddle.net/ebRXw/560/
JS:
$(document).ready(function () {
$('table').dataTable({
"paging": true,
"ordering": true,
"filter": false,
"length": false,
"info": false
});
var table = $("table").dataTable();
var rows = table.$("tr");
var rowsNext = table.$("tr").next();
var cell = table.$("td:nth-child(2)");
var cellNext = table.$("tr").next().children("td:nth-child(2)");
/*rows.addClass("info");*/
rowsNext.addClass("info");
});
rowsNext.addClass("info") only adds the class to the rows on the current page, and it is only run once when the page loads.
If you want to run it every time when a different page loads, you can add an event listener to the table's draw event, like this:
$("table").on("draw.dt", function(){
var rowsNext = $("table").dataTable().$("tr").next();
rowsNext.addClass("info");
});
This code will be run every time a new page is drawn.
Demo: https://jsfiddle.net/alan0xd7/ebRXw/567/
I have a panel within which I have two more panels. When you click on panel1 then information in panel2 is loaded. Since the information is quite huge there is some delay when its being loaded. During this interim period I wish to add a loading mask which intimates the user that its getting loaded.
For the same I have done this:
var myMask = new Ext.LoadMask(Ext.getCmp('eventsPanel'), {
msg:"Please wait..."
});
myMask.show();
// eventsPanel is the main panel under which panel1 and panel2 lie.
// This code is in the selectionchange listener of panel1 whose code
// is inside the main eventsPanel code.
However, nothing is being displayed on the screen. Its still the same, i.e., for some amount of time the screen freezes and then after a delay of like 2-3 seconds the information is loaded. Can you please advise as to where am I going wrong?
I would suggest you to first show your masking like the way you are doing:
var myMask = new Ext.LoadMask(Ext.getCmp('eventsPanel'), {
msg:"Please wait..."
});
myMask.show();
Then make a delayed task
var task = new Ext.util.DelayedTask(function(){
//your loading panel2 with heavy data goes here
myMask.hide();
});
//start the task after 500 miliseconds
task.delay(500);
This should solve your problem.
I make a custom mask as follows:
var componentToMasK = Ext.ComponentQuery.query('#myChildComponent')[0];
var customMask = Ext.get(componentToMasK.getEl()).mask('My mask text...');
var task = new Ext.util.DelayedTask(function() {
customMask.fadeOut({
duration : 500,
remove:true
});
});
task.delay(1000);
Normally when a event is triggered in a first component, caused, for example, the loading of a grid in the second component, the mask appears in both components in order to avoid user errors by clicking on the first component as the second component is loading the grid or is loading the mask.
In this case:
var componentToMasK = Ext.ComponentQuery.query('#myParentComponent')[0]; //HBox, BBox layout, tab, etc. with the two child components
Hope this helps!
Edit: 10-06-2015
The 'duration:500' and the 'delay(1000)' is only to illustrate. You can adjust these values to the needs of each component that you apply a mask.
If you remove the mask abruptly the user can not even see
loading the message, that's why I use fadeOut.
Thus, you can apply a mask on virtually any component such as, for example, a fieldset, when you add it fields dynamically.
task -> http://docs.sencha.com/extjs/5.1/5.1.0-apidocs/#!/api/Ext.util.DelayedTask
Ex.get -> http://docs.sencha.com/extjs/5.1/5.1.0-apidocs/#!/api/Ext-method-get
fadeOut - > http://docs.sencha.com/extjs/5.1/5.1.0-apidocs/#!/api/Ext.dom.Element-method-fadeOut
You can also do the following:
var task = new Ext.util.DelayedTask(function() {
Ext.getBody().unmask();
});
task.delay(1000);
You can read more about this technique in the book: Mastering Ext JS - Second Edition (Loiane Groner)
Edit: 10-06-2015
One more detail:
If we apply one mask on a Hbox layout, containing as one of the childs a grid, we have two mask: HBOX mask and grid mask.
In these cases, I turn off dynamically the grid mask:
var grid = Ext.ComponentQuery.query('#griditemId')[0];
if(grid){
grid.getView().setLoading(false);
}
Hope this helps.