Trying to do a sum on data tables, but its only suming first page - datatables

I'm trying to sum columns in a data table. But it is only suming the first page?
The two variables Requiredone and Bookedtwo only sum the values from the first page of the data, not the entire data set :s
var sTable = $('.datatable').dataTable({
"bJQueryUI": true,
"sPaginationType": "full_numbers",
"bScrollCollapse": true,
"aaSorting": [[1, "desc"]],
"bServerSide": true,
"bProcessing": true,
"sAjaxSource": CycleTimeReport,
"aoColumns": [
{ "sName": "one", "sClass": "ellipsis" },
{ "sName": "two", "sClass": "ellipsis" }
],
"fnServerData": function (sSource, aoData, fnCallback) {
var data = new Object();
data.jsonAOData = JSON.stringify(aoData);
dataToSend = data;
$.ajax({
contentType: "application/json; charset=utf-8",
type: "POST",
url: sSource,
data: JSON.stringify(dataToSend),
success: function (msg) {
fnCallback(msg);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
if (document.Invoice.hostname == "localhost") {
alert(XMLHttpRequest.status);
alert(XMLHttpRequest.responseText);
}
}
});
},
"fnFooterCallback": function (nRow, aaData, iStart, iEnd, aiDisplay) {
var Requiredone = 0;
var Bookedtwo = 0;
for (var i = 0; i < aaData.length; i++) {
Requiredone+= aaData[i][2] * 1;
Bookedtwo += aaData[i][3] * 1;
}
},
"oLanguage": {
"sSearch": "_INPUT_"
},
"fnInitComplete": function (oSettings, json) {
},
"bSortCellsTop": true
});

You are using server-side processing of the data. So your datatable-object only has the data for the currently displayed page. You have to implement the sum on the server-side and add it to the JSON-response or do it in an extra ajax-request.
Another option would be to disable the server-side processing and pre-populate the table element or fill the aaData-property of the datatales-settings with a json object containing all data.

Related

Datatable returns all the data when server side is set to true

I have the following code where I want to use server side to lazy load my data. My goal is to display 10 records per page. The rest of the data should be loaded as and when the user clicks on a particular page.
What's happening now is that the datatable displays all the records at once. Can someone help me fix this issue?
var table = $("#members").DataTable({
"processing": true,
"serverSide": true,
paging: true,
"pagingType": "full_numbers",
"iDisplayLength": "10",
"length": "10",
ajax: {
url: "/api/members",
dataSrc: "",
},
columns: [
{
data: "cardNumber"
},
{
data: "registrationDate",
},
{
data: "fullName",
},
{
data: "address"
},
{
data: "phoneNumber"
},
{
data: "email"
}
]
});
Here's the API code:
// GET /api/members
public IEnumerable<MemberDto> GetMembers(string query = null)
{
var membersQuery = _context.Members.ToList();
if (!String.IsNullOrWhiteSpace(query))
membersQuery = membersQuery.Where(c => c.FullName.Contains(query.ToUpper())).ToList();
var memberDtos = membersQuery.ToList()
.Select(Mapper.Map<Member, MemberDto>);
return memberDtos;
}

How to filter server side jquery datatable with range date picker

I'm trying to use this date range picker to filter the datatable processed server side.
<div class="row pb-2">
...
<input type="text" class="form-control" name="daterange"/>
...
</div>
$(function() {
$('input[name="daterange"]').daterangepicker({
opens: 'right',
locale: { format: 'DD-MM-YYYY' }
},
function (start, end, label) {
minDate = start.format('DD-MM-YYYY');
minDate = end.format('DD-MM-YYYY');
console.log("Dates Selected: " + start.format('DD-MM-YYYY') + ' to ' + end.format('DD-MM-YYYY'));
});
});
JQuery Datatable:
var table = $('#visitorsTable').DataTable({
"processing": true,
"serverSide": true,
"ajax": {
"url": '#Url.Action("GetData", "History")',
"type": "POST",
"datatype": "json"
},
"columns": [
{ "data": "VisitorID" },
{ "data": "Visitor" },
{ "data": "Email" },
{ "data": "PhoneNumber" },
{
"data": "CheckedIn",
"render": function (d) {
return moment(d).format('DD-MM-YYYY HH:mm');
}
},
]
});
Server side action:
[HttpPost]
public ActionResult GetData()
{
// Initialization.
JsonResult result = new JsonResult();
try
{
// Initialization.
string search = Request.Form.GetValues("search[value]")[0];
string draw = Request.Form.GetValues("draw")[0];
string order = Request.Form.GetValues("order[0][column]")[0];
string orderDir = Request.Form.GetValues("order[0][dir]")[0];
int startRec = Convert.ToInt32(Request.Form.GetValues("start")[0]);
int pageSize = Convert.ToInt32(Request.Form.GetValues("length")[0]);
// Loading.
var data = LoadData();
// Total record count.
int totalRecords = data.Count;
// Verification.
if (!string.IsNullOrEmpty(search) && !string.IsNullOrWhiteSpace(search))
{
// Apply search
data = data.Where(v =>
v.Visitor.ToLower().Contains(search.ToLower())
v.Email.ToString().ToLower().Contains(search.ToLower()) ||
v.PhoneNumber.ToString().Contains(search.ToLower()) ||
v.CheckedIn.ToString("dd-MM-yyyy HH:mm").Contains(search)
).ToList();
}
// Sort
data = SortByColumnWithOrder(order, orderDir, data);
// Filter record count.
int recFilter = data.Count;
// Apply pagination.
data = data.Skip(startRec).Take(pageSize).ToList();
// Loading drop down lists.
result = Json(new
{
draw = Convert.ToInt32(draw),
recordsTotal = totalRecords,
recordsFiltered = recFilter,
data = data
}, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
// Info
Console.Write(ex);
}
// Return info.
return result;
}
I'm able to get the selected date range values and the processing of the datatable is ok also.
How can I use the selected range values to filter by the CheckedIn column of the datatable on server side ?
Most of the resources I have found are with datatables on front-end only.
Here is what you can do with Custom Filtering.
HTML
Make two controls, I used the Html helper method to create below, and initialize date pickers you are doing above.
#Html.TextBox("StartDate", "", new { #class = "form-control Startdatepicker",
placeholder = "dd/mm/yyyy", #readonly = "readonly" })
#Html.TextBox("EndDate", "", new { #class = "form-control Enddatepicker",
placeholder = "dd/mm/yyyy", #readonly = "readonly" })
JQuery datatable JS
Add data attributes with the date range values
"data": function (data) {
var startDate = $('#StartDate').val();
var endDate = $('#EndDate').val();
data.startDate = startDate;
data.endDate = endDate;
}
Your JS will become like this below.
var table = $('#visitorsTable').DataTable({
"processing": true,
"serverSide": true,
"ajax": {
"url": '#Url.Action("GetData", "History")',
"type": "POST",
"datatype": "json",
"data": function (data) {
var startDate = $('#StartDate').val();
var endDate = $('#EndDate').val();
data.startDate = startDate;
data.endDate = endDate;
}
},
"columns": [
{ "data": "VisitorID" },
{ "data": "Visitor" },
{ "data": "Email" },
{ "data": "PhoneNumber" },
{
"data": "CheckedIn",
"render": function (d) {
return moment(d).format('DD-MM-YYYY HH:mm');
}
},
]
});
Once you do that, make sure to re draw your datatable when user click Apply Date Filter .
$("#filter").click(function () {
table.fnDraw();
});
Now the Start Date and End Date will be passed with your API call.
API Side
You will be able to get the date range values as follows.
var startDate = Request["startDate"];
var endDate = Request["endDate"];
Now you can apply these date filters.

Thousands separator is not applied

I use jQuery DataTable :
$(document).ready(function() {
var table = $('#t_list').DataTable({
"language": {
"decimal": ",",
"thousands": " ",
"emptyTable": _getText("datatable.resultat.zero"),
"info": _getText("datatable.zone.statut.info"),
"infoEmpty": "",
"infoFiltered": _getText("datatable.zone.statut.filtre"),
"lengthMenu": _getText("datatable.zone.nb.affichage"),
"loadingRecords": _getText("datatable.resultat.chargement"),
"processing": _getText("datatable.resultat.processing"),
"search": _getText("datatable.zone.filtre"),
"zeroRecords": _getText("datatable.resultat.zero"),
"paginate": {
"first": _getText("datatable.btn.premier"),
"previous": _getText("datatable.btn.prcdt"),
"next": _getText("datatable.btn.svt"),
"last": _getText("datatable.btn.dern")
}
},
"pagingType": "full_numbers",
"serverSide": true,
"ajax": "<c:url value='/ajaxDataTableListUsers' />",
"columns": [{
"data": "username"
}, {
"data": "email"
}, {
"data": "salary"
}, {
"data": "id"
}],
"columnDefs": [{
"targets": 2,
"className": "alignDroite"
}, {
"targets": 3,
"render": function(data, type, row, meta) {
var client_noms = row.username; < c: url
var = "url_edit"
value = "/edit" / >
var url_edit = "${url_edit}?id=" + data;
return '<div style="text-align:center;"><img src="resources/images/edit.png" /> ' +
'<img src="resources/images/cross.png" /></div>';
}
}]
});
});
As you can see there is the thousands parameter in the language option. But at runtime the formatting is not applied :
So why is the formatting not applied ?
-- EDIT --
Source of the data is here :
#Override
#Transactional
public List<User> list(int start, int length, String search, int triIdx, String ordreTri) {
Criteria criteres = sessionFactory.getCurrentSession().createCriteria(User.class);
if (!search.equals("")) {
if (NumberUtils.isNumber(search))
criteres.add(Restrictions.like("salary", Double.parseDouble(search)));
else
criteres.add(Restrictions.like("username", search, MatchMode.ANYWHERE));
}
criteres.setFirstResult(start);
criteres.setMaxResults(length);
if (ordreTri.equals("asc")) {
switch (triIdx) {
case 0:
criteres.addOrder(Order.asc("username"));
break;
case 1:
criteres.addOrder(Order.asc("email"));
break;
case 2:
criteres.addOrder(Order.asc("salary"));
break;
default:
criteres.addOrder(Order.asc("username"));
break;
}
} else {
switch (triIdx) {
case 0:
criteres.addOrder(Order.desc("username"));
break;
case 1:
criteres.addOrder(Order.desc("email"));
break;
case 2:
criteres.addOrder(Order.desc("salary"));
break;
default:
criteres.addOrder(Order.desc("username"));
break;
}
}
criteres.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
#SuppressWarnings("unchecked")
List<User> listUser = (List<User>) criteres.list();
return listUser;
}
You don't show the source of your data.
The documenation of Datatables (https://datatables.net/manual/i18n) says that the thousands and decimal options are used when parsing your data, so that sorting can happen correctly. It doesn't look like Datatables is designed to format your data, just parse it. You should format your data as you wish it to be displayed.

Sort icon not changing in Datatable server side processing

When I use server side processing in datatable the sorting works but the sort icon does not change and stays in same direction. Below is the code snippet of my datatable configuration.
$('#dtSearchResult').DataTable({
"filter": false,
"pagingType": "simple_numbers",
"orderClasses": false,
"order": [[0, "asc"]],
"info": true,
"scrollY": "450px",
"scrollCollapse": true,
"bLengthChange": false,
"searching": true,
"bStateSave": false,
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": VMCreateExtraction.AppSecurity.websiteNode() + "/api/Collection/SearchCustIndividual",
"fnServerData": function (sSource, aoData, fnCallback) {
aoData.push({ "name": "ccUid", "value": ccUid });
//Below i am getting the echo that i will be sending to Server side
var echo = null;
for (var i = 0; i < aoData.length; i++) {
switch (aoData[i].name) {
case 'sEcho':
echo = aoData[i].value;
break;
default:
break;
}
}
$.ajax({
"dataType": 'json',
"contentType": "application/json; charset=utf-8",
"type": "GET",
"url": sSource,
"data": aoData,
success: function (msg, a, b) {
$.unblockUI();
var mappedCusNames = $.map(msg.Table, function (Item) {
return new searchGridListObj(Item);
});
var data = {
"draw": echo,
"recordsTotal": msg.Table2[0].TOTAL_NUMBER_OF_RECORDS,
"recordsFiltered": msg.Table1[0].FILTERED_RECORDS,
"data": mappedCusNames
};
fnCallback(data);
$("#dtSearchResult").show();
ko.cleanNode($('#dtSearchResult')[0]);
ko.applyBindings(VMCreateExtraction, $('#dtSearchResult')[0]);
}
})
},
"aoColumns": [{
"mDataProp": "C_UID"
}, {
"mDataProp": "C_LAST_NAME"
}, {
"mDataProp": "C_FIRST_NAME"
}, {
"mDataProp": "C_USER_ID"
}, {
"mDataProp": "C_EMAIL"
}, {
"mDataProp": "C_COMPANY"
}],
"aoColumnDefs": [{ "defaultContent": "", "targets": "_all" },
//I create a link in 1 st column
]
});
There is some configuration that I am missing here. I read on datatable forums and the only issue highlighted by people was that draw should be same as what we send on server side.
For anyone looking for an answer to this. Sad but i had to write my own function as below:
function sortIconHandler(thArray, sortCol, sortDir) {
for (i = 0; i < thArray.length; i++) {
if (thArray[i].classList.contains('sorting_asc')) {
thArray[i].classList.remove('sorting_asc');
thArray[i].classList.add("sorting");
}
else if (thArray[i].classList.contains('sorting_desc')) {
thArray[i].classList.remove('sorting_desc');
thArray[i].classList.add("sorting");
}
if (i == sortCol) {
if (sortDir == 'asc') {
thArray[i].classList.remove('sorting');
thArray[i].classList.add("sorting_asc");
}
else {
thArray[i].classList.remove('sorting');
thArray[i].classList.add("sorting_desc");
}
}
}
}
tharrray-> The array of all row headers(You can just write a jquery selector for this).
sortCol->Column on which sort is clicked (Datatable param iSortCol_0)
sortDir -> Sorting direction (Datatable param sSortDir_0)
I know this is an old thread, but make sure you don't have an .off() somewhere associated with the tables capture group in jQuery. I had a click event that (for some reason) I attached an off function to.. Took me 3 days to find it.

Jquery datatable server side processing erroring on json serialization for large datasets

in web.config of web service that returns more than 40,000 records I have set maxlength for json serialization
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="50000000"/>
</webServices>
</scripting>
</system.web.extensions>
function BindInfoDataTableServerSide()
{
var oTable = $('#example').dataTable({
"sScrollY": "250px",
'bPaginate': true,
"bProcessing": true,
"bFilter": false,
"bServerSide": true,
//"aoColumns": [null, null, { "bSortable": false }, { "bSortable": false}, null, null, null, null],
/* "aoColumns": [
{ "sTitle": "ScreenId" },
{ "sTitle": "RunId" },
{ "sTitle": "RecordType" },
{ "sTitle": "TrackerKey" },
{ "sTitle": "SeqNo" },
{ "sTitle": "TRSeqNo" },
{ "sTitle": "TestParam" },
{ "sTitle": "ParamValue" },
]
,*/
"sAjaxSource": "../SocWebService.asmx/LoadMidasData",
"sAjaxDataProp": "aaData",
"fnServerData": function (sSource, aoData, fnCallback) { GrabData(sSource, aoData, fnCallback); }
});
}
function GrabData(sSource, aoData, fnCallback) {
$.ajax({
type: "POST",
url: sSource,
contentType: "application/json; charset=utf-8",
dataType: "json",
data: "",
success: function (result) {
var myObject = JSON.parse(result.d);
fnCallback(myObject);
//fnCallback(result.d);
},
error: function (errMsg) {
alert(errMsg);
}
});
}
But when records go to 50,000 then I run into following Error
during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property. Jquery datatables website claim they can display 1 million records. Am I missing something ?
The main idea of using server side processing with DataTables is so that the server only returns the rows currently needed for display in the browser (as the user pages around, and sorts etc.) - so while there might in fact be 1 million records, only a small section of those should returned by the web service call, so the ajax limit should not be exceeded.
That way the client side remains nice and fast, with the heavy work getting done on the server (or perhaps in the database depending on how you have your data generated).