Datatables deferRender not deferring - javascript

I don't understand what is wrong with this implementation. Do note that my data is "empty-ish" as I plan on created cells based on their row/col coordinates. So I pass in a dummy array and return the content in the render() callback.
You will notice in the console log it calls createdCell() 100*100 times... The html generated also agrees.
var size = 100
var zeroes = new Uint8Array(size)
var data = _.range(size).map(function() {
return zeroes
})
var cells = 0
var rows = 0
var config = {
autoWidth: false,
paging: false, // Disable Paging
ordering: true, // Sortable columns
info: false, // Disable 'showing x of x entries'
data: data,
deferRender: true,
processing: true,
createdRow: function(cell, data, dataIndex) {
rows += 1
},
columnDefs: [{
targets: _.range(size),
title: 'Title',
render: function(data, type, row, meta) {
return meta.col * meta.row
},
createdCell: function(cell, cellData, rowData, rowIndex, colIndex) {
cells += 1
},
}],
}
var dataTable = $('#dashboard-table').DataTable(config)
console.log("Rows: " + rows)
console.log("Cells: " + cells)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.12/js/jquery.dataTables.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.12/css/jquery.dataTables.min.css" rel="stylesheet"/>
<table className="table table-compressed" id="dashboard-table">
</table>
Here's the fiddle as well:
https://jsfiddle.net/rrauenza/x5nj7qgt/
Why isn't this deferring the cell creation?

Ah, I think I see what is going on. deferRender only works when paging=true in the config and defers the additional page renders.
The Datatables Scroller plugin may be closer to what I expect.

Related

Datatable activate single cell editing onclick

I was unable to utilize the jQuery datatable plugin here:
https://editor.datatables.net/examples/inline-editing/simple
I kept getting an error, so I just dropped it and decided to do it myself.
Starting with the datatable:
$.ajax({
url: 'api/searchVoyageInfo.php',
type: 'POST',
data: '',
dataType: 'html',
success: function(data, textStatus, jqXHR){
var jsonObject = JSON.parse(data);
var table = $('#example1').DataTable({
"data": jsonObject,
"columns": [{
{ "data": "COLUMN1" },
{
"data": "COLUMN2",
"fnCreatedCell": function (nTd, sData, oData, iRow, iCol)
{
$(nTd).html("<a href='#' class='checkBound'>"+oData.COLUMN2+"</a>
<input type='text' class='editbound'
id='editbound' data-uid='"+oData.VOYID+"'
data-editbound='"+oData.COLUMN2+"' value='"+oData.BOUND+"
display: none;' />");
}
},
{ "data": "COLUMN3" },
// few more columns
}],
"iDisplayLength": 50,
"paging": true,
"bDestroy": true,
"autoWidth": true,
"dom": 'Bfrtip',
"buttons": [
// some extend buttons
]
});
},
error: function(// some stuff){
// do some other stuff
// this part is not important
}
});
Within COLUMN2, you should see a class 'checkBound' which is visible when the page loads. There is also an input class 'editbound' which is not visible.
Here is the function that is supposed to hide class 'checkBound' and then display class 'editbound':
$('#example1').on('click', 'tr > td > a.checkBound', function(e)
{
e.preventDefault();
var $dataTable = $('#example1').DataTable();
var tr = $(this).closest('tr');
var data = $dataTable.rows().data();
var rowData = data[tr.index()];
$('.checkBound').hide();
$('.editbound').show();
});
Using the above, when the page is finished loading, the datatable is displayed with no problem.
Upon clicking one of the cells with class 'checkBound' to display the input class 'editbound', the input does display itself, but it also displays every other cell in the column.
Before click:
After click:
As you can see, the first cell in the BOUND column is the cell that was clicked. But when clicked, the rest of the cells were activated. I want to prevent this from happening.
How can I make this work?
This is the way i created a column with a button in it . You should be able to do similar instead of button !
fields: [
{ name: "column_id", title:"View" ,itemTemplate: function(value) {
return $("<button>").text("buttontitle")
.on("click", function() {
//do something
return false;
});
}]
This is how I (somewhat) solved my problem. In the datatable section, I added an ID field called VOYID and included that ID with the class in the href and the input:
"data": "COLUMN2",
"fnCreatedCell": function (nTd, sData, oData, iRow, iCol)
{
$(nTd).html("<a href='#' class='checkBound"+oData.VOYID+"' id='checkBound'>"+oData.COLUMN2+"</a>
<input type='text' class='editbound"+oData.VOYID+"'
id='editbound' data-uid='"+oData.VOYID+"'
data-editbound='"+oData.COLUMN2+"' value='"+oData.BOUND+"
display: none;' />");
}
Then down in the button click section, I utilized the rowData to check for the exact class. This way, when you click the link, only the unique class will open and not all of the cells in the column:
$('#example1').on('click', 'tr > td > a.checkBound', function(e)
{
e.preventDefault();
var $dataTable = $('#example1').DataTable();
var tr = $(this).closest('tr');
var data = $dataTable.rows().data();
var rowData = data[tr.index()];
var voyid = rowData.VOYID;
$('.checkBound'+voyid).hide();
$('.editbound'+voyid).show();
});
Now, when I click on the link, it is only that cell that gets the input activated:

Data Table with AJAX, sum and add total footer

I have a datatable created by the following code
var data = results.rows;
var column_names = results.headers;
if (column_names) {
var columns = [];
var total = 0;
for (var i = 0; i < column_names.length; i++) {
columns[i] = {
'title': column_names[i],
'data': i
}
};
dataTable=$('#report').DataTable( {
columns: columns,
data: data,
paging: false,
dom: 'Bfrtip',
buttons: [
'copy', 'csv', 'excel', 'pdf', 'print'
]
}
);
showTable();
dataTable.columns.adjust().draw();
} else {
alert('No Results Found');
}
I would like to add a footer to the table that contains a sum of the 2nd column and has text that says "Total: "
The table in the html looks like:
<table id="report" class="compact">
</table>
I tried adding a footer in html but it was overwritten when the report is rerun so this needs to be done in the top section of code in order to display every time a table is created.
Thanks in advance:)
I found an example here http://jsbin.com/putiyep/edit?js.
It wont look as pretty as you hoped for but it'll do the job.
It leverages the footerCallback of the API and use the column index of the table and basic math to return your total.
The data table section of the code would look like:
dataTable=$('#report').DataTable( {
columns: columns,
data: data,
paging: false,
dom: 'Bfrtip',
"footerCallback": function (tfoot, data, start, end, display) {
var api = this.api();
var p = api.column(2).data().reduce(function (a, b) {
return a + b;
}, 0)
$(api.column(2).footer()).html("Total: "+p);
},
buttons: [
'copy', 'csv', 'excel', 'pdf', 'print'
]
}
);

Remove row from Kendo UI Grid with jQuery

I am using a Kendo UI grid and for deleting a row I am using a custom button with bootstrap that when I click on it, with ajax I call a web api method to remove that row and if it is successfully deleted that row removes it from the DOM. (I'm not using the command destroy of kendo)
The problem I have is that if I try to filter that row that was removed, it appears again in the grid and it seems that it was not removed at all.
This is my Kendo UI grid:
var table = $("#grid").kendoGrid({
dataSource: {
transport: {
read: {
url: "/api/customers",
dataType: "json"
}
},
pageSize: 10
},
height: 550,
filterable: true,
sortable: true,
pageable: {
refresh: true,
pageSizes: true,
buttonCount: 5
},
columns: [{
template: "<a href='' class='btn-link glyphicon glyphicon-remove js-delete' title='Delete' data-customer-id= #: Id #></a>",
field: "Id",
title: " ",
filterable: false,
sortable: false,
width: 50,
attributes: {
style: "text-align: center"
}
}, {
field: "Name",
title: "Name",
width: 100,
}, {
field: "LastName",
title: "LastName",
width: 100,
}, {
field: "Email",
title: "Email",
width: 150
}]
});
And this is my jQuery code for deleting a row:
$("#grid").on("click", ".js-delete", function () {
var button = $(this);
if (confirm("Are you sure you want to delete this customer?")) {
$.ajax({
url: "/api/customers/" + button.attr("data-customer-id"),
method: "DELETE",
success: function () {
button.parents("tr").remove(); //This part is removing the row but when i filtered it still there.
}
});
}
});
I know that in jQuery DataTables when can do something like this:
table.row(button.parents("tr")).remove().draw();
How can i do something like this with Kendo UI using jQuery?
Don't ever play with a Kendo's widget DOM. Always use it's methods instead.
Using Grid's removeRow():
$("#grid").on("click", "button.remove", function() {
var $tr = $(this).closest("tr"),
grid = $("#grid").data("kendoGrid");
grid.removeRow($tr);
});
Demo
Using DataSource's remove():
$("#grid").on("click", "button.remove", function() {
var $tr = $(this).closest("tr"),
grid = $("#grid").data("kendoGrid"),
dataItem = grid.dataItem($tr);
grid.dataSource.remove(dataItem);
});
Demo
My usage was a little different. I have a custom delete button, so I needed to delete by ID, not UID.
You should be able to match on any field value instead of ID.
var grid = $("#grid").data("kendoGrid");
var dataItem = grid.dataSource.get(ID);
var row = grid.tbody.find("tr[data-uid='" + dataItem.uid + "']");
grid.removeRow(row);
We were trying to prevent messing with the controller, and this calls the existing delete function.
The removed row will be present in the kendo ui till you push changes to server.
To remove the row entirely you need to use
grid.saveChanges()
So the code below will remove row from server as well from ui
const row = $(e.target).closest('tr')[0];
const grid = $(e.target).closest('#grid').data("kendoGrid");
grid.removeRow(row);
grid.saveChanges() //comment out if you need to remove only from ui

Two DataTable in One Page - Second one initialising weird

I have two dataTable in my page and I have a method like below:
function ToDataTable()
{
$(".dataTable").css("width", "100%");
$(".dataTable").each(function ()
{
var $that = $(this);
/* Start of method */
function ToDataTableInternal()
{
var table = $that.DataTable({
responsive: {
details: { type: "column", target: -1 },
},
columnDefs: [{
className: "control", orderable: !1, targets: -1,
},
{ orderable: !1 }],
"paging": false,
"ordering": false,
"info": false,
"searching": false,
retrieve: true
});
}
/* End of method */
if ($that.is(":visible"))
{
ToDataTableInternal()
}
else
{
// Observe all invisible parents or table to trigger
// ToDataTableInternal method if made visible
var $arr = $(this).parentsUntil(":visible").filter(function ()
{
return $(this).css("display") === "none";
}).add($(this));
var observers = [];
$arr.each(function ()
{
var observer = new MutationObserver(function (mutations)
{
mutations.forEach(function (mutation)
{
if ((mutation.attributeName === 'style' ||
mutation.attributeName === 'class') &&
$that.is(":visible"))
{
ToDataTableInternal();
for (var i = 0; i < observers.length; i++)
{
// Disconnect observers
observers[i].disconnect();
}
}
});
});
observers.push(observer);
observer.observe(this, {
attributes: true
});
});
}
});
}
The reason I have this method is that when table's display is none, it really lags browser(especially IE, where I cannot do anything for minimum of 5 seconds) which is the reason of that I'm changing the table to DataTable after it made visible.
But the problem with calling methods individually is the second DataTable doesn't have the same settings which I passed on.(The first one has) Instead, second one has filters, paging, sort elements in it too.
If I call both at the same time, nothing out of ordinary happens. What may be the problem?
EDIT: I can't reproduce the same behaviour in fiddles.
There seems to be no problems in another environments when I'm trying to do the same thing.
An another library we use is causing problems and there is no problem with DataTable library.
you can add following properties of dataTable in your datatable configuration to remove filtering, pageing and sorting:
Datatable 1.9
"bPaginate":false, //Enable or disable pagination.
"bFilter": false, //Enable or disable filtering of data
"bLengthChange": false, //Enable or disable the size dropdown
"bSort": false, //Enable or disable sorting of columns.
"bInfo": false, //Enable or disable the table information display.
Update
Datatable 1.10
Option name update in datatable 1.10
bPaginate -> paging
bFilter -> searching
bLengthChange -> lengthChange
bSort -> ordering
bInfo -> info

Flexigrid: selection of rows to survive refresh

I am using flexigrid in a project and I would like to be able to keep the selected rows after the grid is refreshing. I asked the same question on the flexigrid discussion board and I got this answer:
Add a click handler, save the id if the row id of the row selected. On refresh completion, select the row again (if still present)
Not sure how to proceed on this, I don't even know how a function will look like, so that's why I don't have any code to start with.
If someone could point me in the right direction will be greatly appreciated.
Thanks,
Cristian.
Flexigrid adds a class called trSelected to selected rows, so whenever a click event happens on the grid you could just look for all the selected rows and save them in some way. Below is just a quick example of what you could do:
var selectedRows = new Array();
$('#myGrid').click(function() {
selectedRows = new Array();
$(this).find('tr.trSelected').each(function(i, selectedRow) {
selectedRows.push($(selectedRow));
});
});
I have done small code to keep multi-selection between pagination and also during refresh.
$("#searchPhonoList").flexigrid($.extend({}, flexigridAttrs, {
url: './rest/phono/search',
preProcess: formatSearchPhonoResults,
onSuccess: successSearchPhono,
onSubmit: submit,
method: 'GET',
dataType: 'json',
colModel : [
{display: 'titre', name: 'titre_brut', width : 240, sortable : true, align: 'left'},
{display: 'version', name: 'version_brut', width : 60, sortable : true, align: 'left'}
],
height: "auto",
sortname: "score",
sortorder: "desc",
showTableToggleBtn: false,
showToggleBtn: false,
singleSelect: false,
onToggleCol: false,
usepager: true,
title: "Liste des candidats",
resizable: true,
rp:20,
useRp: true
}));
var searchPhonoListSelection = new Array();
$('#searchPhonoList').click(function(event){
$(' tbody tr', this).each( function(){
var id = $(this).attr('id').substr(3);
if ( searchPhonoListSelection.indexOf(id) != -1 ) {
searchPhonoListSelection.splice(searchPhonoListSelection.indexOf(id), 1);
}
});
$('.trSelected', this).each( function(){
var id = $(this).attr('id').substr(3);
if ( searchPhonoListSelection.indexOf(id) == -1 ) {
searchPhonoListSelection.push(id);
}
});
});
function successSearchPhono() {
$("#searchPhonoList tbody tr").each( function() {
var id = $(this).attr('id').substr(3);
if ( searchPhonoListSelection.indexOf(id) != -1 ) {
$(this).addClass("trSelected");
}
});
}

Categories