I'm currently starting using Datatables (https://datatables.net) to create tables.
The data in the table are obtained through socket.io from the server.
My problem is when socket.io add data, the table isn't "updated", it says it only have 1 entry and search box is only working on the last element added.
Here is a sample of my code:
socket.on('jobStepsResponse', function(message) {
document.getElementById('listOfJobs').style.display = 'none';
document.getElementById('contentJob').style.display = 'block';
document.getElementById('jobid').innerHTML = "<button onClick=returnToJobList()>Retour</button> Job "+message.idJob;
for(var i=0;i<Object.keys(message.status).length;i++){
document.getElementById('tabstats').innerHTML += '<tr><td>'+Object.keys(message.status)[i]+'</td>'+'<td>'+ts2time(message.status[Object.keys(message.status)[i]])+'</td>'+'</tr>';
}
$(document).ready(function() {$('#example2').DataTable();} );
setInterval( function () { $('#example2').DataTable().ajax.reload( null, false ); }, 1000 );
});
As you can see, I tried using ajax reload but i think its for ajax data sources, so it doesn't work.
As a workaround, i wait for table to be fully populated first, the call the Datatables style which will count all the element added.
Only problem is that it show the unformatted datas for some times so you need to add a DOM control to show a loading thing for example.
Related
I'm using a custom Primefaces-based framework to display a datatable, and it looks like that:
<xy:dataTable id="tableId" value="#{lazyTableBean.dates}" var="date">
<xy:column id="nameColumnId">
<xy:outputText id="nameOutputId" value="date.name"/>
</xy:column>
<xy:column id="actionColumnId">
<xy:actionButton id="actionButtonId" label="Button"
action="#{someBean.someAction(date.id)}"/>
</xy:column>
</xy:dataTable>
Now I want to set the tooltip of the button. Since the actionButton component of that framework doesn't have the title attribute, I'm using JavaScript to alter it:
var rows = // getting the table content row components here
// iterating through table rows and setting the button tooltip to the name of the corresponding date
for (const row of rows) {
var myTooltip = row.children.item(0).textContent;
row.children.item(1).firstChild.setAttribute("title", myTooltip);
}
This basically works as it should when I import the JS script at the end of the file.
However, there are several AJAX events (e.g. when sorting or filtering the table, or when using pagination...) that reprint the table content. Since the JS script isn't triggered again, the tooltips aren't set in that case.
Now I've planned to simply import the script at some appropriate place (e.g. inside the component that gets rerendered) so that it's executed whenever the button is rendered. However, I haven't found quite the right place to make it work. When I'm putting it inside the column:
<xy:dataTable id="tableId" value="#{lazyTableBean.dates}" var="date">
<xy:column id="nameColumnId">
<xy:outputText id="nameColumnId" value="date.name"/>
</xy:column>
<xy:column id="actionColumnId">
<xy:actionButton id="actionColumnId" label="Button"
action="#{someBean.someAction(date.id)}"/>
<h:outputScript library="js" name="addTooltipToTableButtons.js" />
</xy:column>
</xy:dataTable>
This results in only the first row to correctly set their tooltip, all other rows keep their generic one. But on AJAX events, the correct behavior takes place, all rows set their tooltip correctly. The same behavior takes place if the script is also imported at the end. I guess this has to do with the table format of dynamically printing a number of rows with the same column components, but this is just guessing.
Putting it inside the table (directly before </xy:dataTable>) results in no script execution at all.
I'm totally new to JavaScript and we're just using this approach until our custom framework supports setting arbitrary attributes. I hope you have an idea (or an explanation why it won't work like that) - thanks in advance!
Greetings
In case anyone's interested in my solution, I used a MutationObserver to handle the events, in addition to the "normal" JS at page load.
The whole JS file looked like that:
var table = ...; // get table by normal means
for (var i = 0, row; row = table.rows[i]; i++) {
var tooltip = row.cells[0].textContent;
row.cells[1].firstChild.setAttribute(tooltip);
}
var observer = new MutationObserver(function( mutations ) {
mutations.forEach(function( mutation ) {
var newNodes = mutation.addedNodes;
if( newNodes !== null ) {
var $nodes = $( newNodes );
$nodes.each(function() {
var tooltip = this.cells[0].textContent;
this.cells[1].firstChild.setAttribute(tooltip);
});
}
});
});
var config = {
attributes: true,
childList: true,
characterData: true
};
observer.observe(table.children.item(1), config);
I am trying to source some data from the datatable I am working on. I have an edit button on every row and when is clicked it suppose to bring a form with the data that is already in the table for editing. I need to get real time data when the form is render however ajax.reload() doesn't load the table on time for the form be filled by the correct data and with code below only shows the form for the first employee:
let editEmployeeId;
$(document).ajaxStop(function(){
$('#employeesTable tbody').on('click', '.btn.btn-warning.small-edit-button', function(){
let thisRow = this;
tableEmployees.ajax.reload(function(){
//tableDepartments.draw();
tableDepartments.columns().search("").draw();
//tableEmployees.columns().search("").draw();
getDropdown(1,'#departmentEditDropdown', 'Departments');
var data = tableEmployees.row($(thisRow).parents('tr')).data() || tableEmployees.row($(thisRow).parents('li').attr('data-dt-row')).data();
$('#editFirstName').val(data.firstName);
$('#editLastName').val(data.lastName);
$('#departmentEditDropdown>select').val(data.department);
updateLocation('#locationEditDropdown','#departmentEditDropdown>select');
$('#departmentEditDropdown>select').trigger('change');
$('#locationEditDropdown>select').val(data.locationID);
$('#editJobTitle').val(data.jobTitle);
$('#editEmail').val(data.email);
$('#editEmployeeModal').modal("show");
});
});
I tried:
promise
settimeout
nested functions
async functions
I also try to change ajax call to set async: false and this way it works perfect but I don't think that is a good practice and I have other calls through the document and takes double of time to load the page first time.
I changed the way of calling the button with an extra class for the employees page and used the .click() method instead .on() because for some reason it was going in a loop with the last one. Now works and this is how it looks:
let editEmployeeId;
$(document).ajaxStop(function(){
$('.btn.btn-warning.small-edit-button.employees').click(function(e){
e.preventDefault();
let thisRow = tableEmployees.row($(this).parents('tr'));
let thatRow = tableEmployees.row($(this).parents('li').attr('data-dt-row'));
tableDepartments.columns().search("").draw();
tableEmployees.columns().search("").draw();
getDropdown(1,'#departmentEditDropdown', 'Departments');
tableEmployees.ajax.reload(function(){
var data = thisRow.data() || thatRow.data();
editEmployeeId = data.id;
$('#editFirstName').val(data.firstName);
$('#editLastName').val(data.lastName);
$('#departmentEditDropdown>select').val(data.department);
$('#departmentEditDropdown>select').trigger('change');
$('#editJobTitle').val(data.jobTitle);
$('#editEmail').val(data.email);
$('#editEmployeeModal').modal("show");
})
});
I have got a problem with getting information from jQuery datatable.
Here is the table:
I would like to get information stored in the table. I have tried to do this by this:
var languages=[];
var people=[];
$("select[name='languageID']").each(function(){
languages.push( $(this).val() );
});
$("input:hidden[name='personID']").each(function(){
people.push( $(this).val() );
});
but it is getting values from current chosen page. If I run this in the situation like on the screenshot, only values from page 2 would be pushed to the arrays. I have tried to check where values from page 1 are stored, but I could not find anything. I also looked for it on jQuery datatables homepage
Could anyone help?
Regards
EDIT:
so I should do something like this:
table.column( 0 ).cache( 'search' ).each( function ( d ) { /*action here*/ } );
?
But what should be in action?
When I debug table.column( 2 ).cache( 'search' ); I have got this:
[ choose language ", " choose language ", " choose language ", " choose language ", " choose language ", " choose language " ]
It is first option in "Chosen language" select. I think, that I need something, which would return html code from each cell in column, so that I can analyse it later.
This one turns out harder than expected. At first, I try using the datatable data() API, but that returns the dropdown lists as HTML strings, which are not very useful. Then I come across this article on how datatable deals with form inputs. The trick is to recognize that your datatable object can retrieve nodes from within the document regardless of paging.
A live demo can be found on my jsfiddle.
EDIT: As per discussion with OP, the following codes can be utilized instead of relying on embedded column selectors:
table.$('select[name="languageID"]').each(function(index, value{
languages.push($(value).val());
});
In the legacy api, fnGetData should return what you need.
$(document).ready(function() {
oTable = $('#example').dataTable();
oTable.$('#myButton').click( function () {
var data = oTable.fnGetData( this );
// ... do something with the array / object of data for the row
} );
});
In the new api (v1.10+), you'll probably want column().cache().
http://datatables.net/reference/api/column().cache()
In my case, I should modify my code to:
var languages=[];
var people=[];
table
.column(0)
.nodes()
.each(function(a){
people.push( $(a).find("input:hidden[name='personID']").val() );
});
table
.column(2)
.nodes()
.each(function(a){
languages.push( $(a).find("select[name='languageID']").val() );
});
As #ivan.sim says, it's not so easy to get the full table data, although I finally found a solution which you can use to get values (including hidden inputs etc) from the full table including pages that are not displayed:
table.rows().every(function (rowIdx, tableLoop, rowLoop) {
var data = this.node();
console.log($(data).find('input').prop('checked'));
console.log($(data).find('input[name=someField]').val());
});
I'm trying to use tablesorter.js but im running into issues when using ajax to update my table. I followed the code on this page but it doesn't seem to be working properly. One thing i also notice is that the code doesnt work properly even on the example website. When i click "append new table data" it adds the data to the table but it isn't sorting it correctly. If i copy the javascript code and paste it into the console, it works fine and sorts the table correctly. The code im using is the following:
var updateTableSort = function(){
var table = $('#transaction-table')
//tells table sorter that table has been updated
table.trigger("update");
//re sorts after table has been updated based on
//current sort patern
var sorting=table.get(0).config.sortList;
table.trigger('sorton', [sorting]);
}
Again, if i copy and past this into console it works fine, but when i have it in my success ajax function, it doesnt sort the table properly. Any help figuring out what the issue is would be greatly appreciated
Try my fork of tablesorter. It automatically resorts the table after an update:
// pass anything BUT false and the table will resort
// using the current sort
$("table").trigger("update", [false]);
Here is the updated append data to the table using ajax demo:
$(function() {
$("table").tablesorter({ theme : 'blue' });
$("#ajax-append").click(function() {
$.get("assets/ajax-content.html", function(html) {
// append the "ajax'd" data to the table body
$("table tbody").append(html);
// let the plugin know that we made a update
// the resort flag set to anything BUT false (no quotes) will
// trigger an automatic
// table resort using the current sort
var resort = true;
$("table").trigger("update", [resort]);
// triggering the "update" function will resort the table using the
// current sort; since version 2.0.14
// use the following code to change the sort; set sorting column and
// direction, this will sort on the first and third column
// var sorting = [[2,1],[0,0]];
// $("table").trigger("sorton", [sorting]);
});
return false;
});
});
I have a JQuery datatable that loads data via an ajax request. There is a form by the table that lets the user filter the results on the server. When the user changes the filter form, I call fnReloadAjax() with the new filter data, and the table redraws with the new, filtered results.
The problem I have is that the pagination sticks, even if the table no longer has enough items to reach the current page. So if the table originally had 20 items, and the user was on page 2 (10 items per page), and they change the filter so only 5 items are returned, the table displays no items and shows this at the bottom:
Showing 11 to 5 of 5 entries
It's still on page 2 even though there is only enough data for one page.
I have found numerous posts about trying to preserve the current page/row, but none showing a simple way to reset pagination to the first page. What is the simplest way to do this?
Here's a simplified version of my code for clarity:
$("#mytable").dataTable({
bStateSave: false,
fnServerData: function (sSource, aoData, fnCallback) {
return $.ajax({
type: "POST",
url: url,
data: {filter: filterValue}
});
}
});
$("#myForm").submit(function(e) {
table.fnReloadAjax();
return false;
});
You could explicitly jump to the first page after reloading, see http://datatables.net/api#fnPageChange
$("#myForm").submit(function(e) {
table.fnPageChange(0);
table.fnReloadAjax();
return false;
});
Accepting the solution given by #Gigo:
$("#myForm").submit(function(e) {
table.fnPageChange(0);
table.fnReloadAjax();
return false;
});
This have a problem, it sends two request to the server.
i have found that the fnPageChange does it at the first time.
$("#myForm").submit(function(e) {
table.fnPageChange(0);
return false;
});
This can be solved by implementing the functions to save and load the state of the datatable and resetting the start point - example below
"fnStateSave": function (oSettings, oData) {
localStorage.setItem( 'MyDataTable', JSON.stringify(oData) );
},
"fnStateLoad": function (oSettings) {
var settings = JSON.parse( localStorage.getItem('MyDataTable') );
settings.iStart = 0; // resets to first page of results
return settings
},
As fnStateLoad is called when the table is reloaded - e.g. a new filter is applied - the paging is reset to the start.
fnStateSave is called each time you retrieve the next page of results
This approach avoids the overhead of an additional request back to the server