I have been working with datatables for a couple of weeks and I have this custom datatables that I'm identifying by class (tableIdentifyClass):
var handleDataTable = function () {
if ($("." + tableIdentifyClass).length) {
table = $("." + tableIdentifyClass).DataTable({
aaData: dataForTable,
aoColumns: [
{ mData: "IsDefault", title: "" },
{ mData: "Name", title: "Name" },
{ mData: "Icon", title: "Icon" },
{ mData: "IsDefault", title: "" }],
"order": [[1, "asc"]],
"bAutoWidth": false,
"lengthChange": false,
"columnDefs": [{
"targets": 0,
"render": function (data, type, full, meta) {
if (type === 'display') {
if (!data)
return '<span class="fa-xs"><i class="fa fa-edit" style="font-size:125%" onclick:""></i></span>';
else return '<span></span>';
}
return (isNaN(data)) ? -1 : +data;
}
},
{
"targets": 2,
"render": function (data, type, full, meta) {
if (type === 'display') {
if (data != '')
return '<span class="fa-xs"><i class="fa ' + data + '" style="font-size:125%"></i></span>';
else return '<span>-</span>';
}
return (isNaN(data)) ? -1 : +data;
}
},
{
"targets": 3,
"render": function (data, type, full, meta) {
if (type === 'display') {
if (!data)
return '<a class="fa-xs"><i class="fa fa-times" style="font-size: 125%; color: red;" onclick="deletePrefLocally(' + full.UId + ',' + full.Id + ',\'' + tableIdentifyClass + '\')"></i></a>';
else return '<span></span>';
}
return (isNaN(data)) ? -1 : +data;
}
}]
});
}
}
The data for the table (dataForTable):
[ { "Icon": "fa-exclamation-circle", "IsDefault": true, "Name": "Nixon", "UId": 1 },
{ "Icon": "fa-exclamation-circle", "IsDefault": false, "Name": "Tiger", "UId": 2 }]
I'm trying to delete the second row by calling function deletePrefLocally
function deletePrefLocally(uId, deletedId, tableIdentifyClass) {
var crtUsage = dataForTable; //same items as the table
var inItems = crtUsage.filter(function (elem) {
return elem.Id === deletedId; // find the item with the same id
})[0];
var found = crtUsage.indexOf(inItems);
if (found != -1) crtUsage.splice(found, 1);
table = $("." + tableIdentifyClass);
datatable = table.DataTable();
datatable.clear();
datatable.rows.add(crtUsage).draw();
}
My problem is that the last row datatable.rows.add(crtUsage).draw(); pops-up a message: DataTables warning: - Request unknows parameter '0' for row 0, column 0. For more information about this error, please see http://datatables.net/tn/4
Why is not applying the new content? Why after closing the error box I have two search areas and paging and all the values are null? What am I doing wrong?
You've defined "IsDefault" twice in your column list.
aoColumns: [
{ mData: "IsDefault", title: "" },
{ mData: "Name", title: "Name" },
{ mData: "Icon", title: "Icon" },
{ mData: "IsDefault", title: "" }],
I suspect you meant to have "UId" for the last one, as that is included in the data.
Found the reason... After all the page was loaded I've checked if based on tableIdentifyClass I'll receive true after calling $.fn.DataTable.isDataTable( '.' + tableIdentifyClass) but it was false. When calling datatable = table.DataTable(); I was creating a datatable inside the existing one, duplicate search area and paging :( I've tried to save all the "tables" after initialization inside an global array and search for it in order to add the new rows. Perhaps this is not the best solution but it worked for me.
Related
I am working on an ASP.NET Core 2.1 website and I am using Datatables.net to display my record lists retrieved from a backend API.
This issue I am trying to resolve is that, whenever an error occurs while retrieving the data from the backend API, I want the error message to appear in a Bootstrap alert-error DIV on the same page as the datatable.
I have looked at https://datatables.net/forums/discussion/30033/override-default-ajax-error-behavior and Enable datatable warning alert but I am not strong in javascript so I am having some difficulty determining how to implement this feature.
Currently, I have the datatable set up in my cshtml page as follows;
<script>
jQuery(document).ready(function ($) {
var table = $("#sitelist").DataTable({
"processing": true,
"serverSide": true,
"filter": true,
"orderMulti": false,
"ajax": {
"url": "/Sites/LoadData",
"type": "POST",
"datatype": "json"
},
"columnDefs": [
{ "orderable": false, "targets": 6 },
{ "className": "text-center", "targets": [4, 5] },
{
"targets": [4, 5],
"createdCell": function(td, cellData, rowData, row, col) {
if (cellData) {
$(td).html('<i class="far fa-check-circle text-primary""></i>');
} else {
$(td).html('<i class="far fa-times-circle text-danger""></i>');
}
}
}
],
"columns": [
{ "data": "Id", "name": "Id", "autoWidth": true, "defaultContent": "" },
{ "data": "SiteName", "name": "SiteName", "autoWidth": true, "defaultContent": "" },
{ "data": "CompanyId", "name": "CompanyId", "autoWidth": true, "defaultContent": "" },
{ "data": "CompanyName", "name": "CompanyName", "autoWidth": true, "defaultContent": "" },
{ "data": "IsAdminSite", "name": "IsAdminSite", "autoWidth": true, "defaultContent": "" },
{ "data": "IsEnabled", "name": "IsEnabled", "autoWidth": true, "defaultContent": "" },
{
"render": function (data, type, full, meta) { return `<i class="far fa-edit text-primary" title="Edit">`; }
}
],
// From StackOverflow http://stackoverflow.com/a/33377633/1988326 - hides pagination if only 1 page
"preDrawCallback": function (settings) {
var api = new $.fn.dataTable.Api(settings);
var pagination = $(this)
.closest('.dataTables_wrapper')
.find('.dataTables_paginate');
pagination.toggle(api.page.info().pages > 1);
}
});
});
</script>
And here is the loaddata action in my SitesController class;
public async Task<IActionResult> LoadData()
{
try
{
await SetCurrentUser();
ViewData["Role"] = _currentRole;
var draw = HttpContext.Request.Form["draw"].FirstOrDefault();
var start = Request.Form["start"].FirstOrDefault();
var length = Request.Form["length"].FirstOrDefault();
var sortColumn = Request.Form["columns[" + Request.Form["order[0][column]"].FirstOrDefault() + "][name]"].FirstOrDefault();
var sortColumnDirection = Request.Form["order[0][dir]"].FirstOrDefault();
var searchValue = Request.Form["search[value]"].FirstOrDefault();
var pageSize = length != null ? Convert.ToInt32(length) : 0;
var skip = start != null ? Convert.ToInt32(start) : 0;
var request = new SitesGetListRequest
{
OrderBy = SetOrderBy(sortColumn, sortColumnDirection),
Filter = SetFilter(searchValue),
PageNumber = (skip / pageSize) + 1,
PageSize = pageSize
};
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var endpoint = $"api/companies/{SetCompanyId()}/sites/filtered";
var siteData = await _client.GetSiteListAsync(request, endpoint, token);
if (siteData.Sites != null)
{
return Json(new
{
draw,
recordsFiltered = siteData.Paging.TotalCount,
recordsTotal = siteData.Paging.TotalCount,
data = siteData.Sites.ToList()
});
}
//TODO: Find a way to pass error to a Bootstrap alert-warning DIV rather than the jQuery (javascript) alert box
var errorMessage = $"Http Status Code: {siteData.StatusCode} - {siteData.ErrorMessages.FirstOrDefault()}";
return Json(new
{
data = "",
error = errorMessage
});
}
catch (Exception ex)
{
const string message = "An exception has occurred trying to get the list of Site records.";
_logger.LogError(ex, message);
throw;
}
}
As it stands right now, If an error exists in the object returned from the API call, I pass a message to the error property in the returned json and it shows up as an javascript alert popup box on my cshtml page and when I click OK, the datatable displays "No records found", as shown in the images below;
and...
What I want is for the error message to display in a bootstrap alert-danger div at the top of the cshtml page. I so not want the alert popup to appear and I still want the datatable to show "No records found".
I think that what I am looking for is described on Enable datatable warning alert...
Disable the alert popup by using
$.fn.dataTable.ext.errMode = 'none';
And pass the error message to the BootStrap div using
$('#example')
.on( 'error.dt', function ( e, settings, techNote, message ) {
console.log( 'An error has been reported by DataTables: ', message );
} )
.DataTable();
but instead of
console.log( 'An error has been reported by DataTables: ', message );
use something like
$("#error").html(MY ERROR MESSAGE HERE);
and assign id="error" to the bootstrap div.
But, I am having trouble figuring out how to trigger the Ajax call from my loaddata method in the SitesController and also how to correctly add the error event to the beginning of my datatable script.
Before I burn more time trying to work this out, I thought I would put this on SO and see if anyone with javascrit/jquery experience can provide some guidance.
You can add the error property to the ajax call. Probably the best will be to use fnServerData.
jQuery(document).ready(function ($) {
var table = $("#sitelist").DataTable({
"processing": true,
"serverSide": true,
"filter": true,
"orderMulti": false,
"sAjaxSource": "/Sites/LoadData",
"fnServerData": function (sSource, aoData, fnCallback) {
$.ajax({
"dataType": 'json',
"type": "GET",
"url": sSource,
"data": aoData,
"cache": false,
"success": function (data) {
fnCallback(data);
},
"error": function(error){
$("#error").html(error);
}
});
},
"columnDefs": [
{ "orderable": false, "targets": 6 },
{ "className": "text-center", "targets": [4, 5] },
{
"targets": [4, 5],
"createdCell": function(td, cellData, rowData, row, col) {
if (cellData) {
$(td).html('<i class="far fa-check-circle text-primary""></i>');
} else {
$(td).html('<i class="far fa-times-circle text-danger""></i>');
}
}
}
],
"columns": [
{ "data": "Id", "name": "Id", "autoWidth": true, "defaultContent": "" },
{ "data": "SiteName", "name": "SiteName", "autoWidth": true, "defaultContent": "" },
{ "data": "CompanyId", "name": "CompanyId", "autoWidth": true, "defaultContent": "" },
{ "data": "CompanyName", "name": "CompanyName", "autoWidth": true, "defaultContent": "" },
{ "data": "IsAdminSite", "name": "IsAdminSite", "autoWidth": true, "defaultContent": "" },
{ "data": "IsEnabled", "name": "IsEnabled", "autoWidth": true, "defaultContent": "" },
{
"render": function (data, type, full, meta) { return `<i class="far fa-edit text-primary" title="Edit">`; }
}
],
// From StackOverflow http://stackoverflow.com/a/33377633/1988326 - hides pagination if only 1 page
"preDrawCallback": function (settings) {
var api = new $.fn.dataTable.Api(settings);
var pagination = $(this)
.closest('.dataTables_wrapper')
.find('.dataTables_paginate');
pagination.toggle(api.page.info().pages > 1);
}
});
});
</script>
we coding a quotation form for our company and want to add products a datatable and changing value on it. After change data we send to controller but they same the first time. Here is datatable structure.
var selectedProduct = $('#selectedproduct').DataTable({
"columns": [
{
"orderable": false,
"data": "IsConfirm",
},
{ "orderable": false, "data": "Product.Id" },
{ "orderable": false, "data": "Product.Name" },
{ "orderable": false, "data": "Product.Description" },
{
"orderable": false,
"data": "Quantity",
"render": function (data, type, full, meta) {
return '<td width="100px"><input class="touchspinquantity" type="text" value="' + data + '" name="quantity"></td>';
}
},
{ "orderable": false, "data": "Product.SalePrice" },
{
"orderable": false,
"data": "Discount",
"render": function (data, type, full, meta) {
return '<td width="100px"><input class="touchspindiscount" type="text" value="' + data + '" name="discount"></td>';
}
},
{ "orderable": false, "data": "Product.Currency" },
{ "orderable": false, "data": null, "defaultContent": '' },
{
"orderable": false,
"data": null,
"defaultContent": '<button id="deleteproduct" class="btn btn-warning btn-circle" type="button"><i class="fa fa-times"></i></button>'
},
],
"createdRow": function (row, data, index) {
if (data.IsConfirm) {
$('td', row).eq(0).html('<input type="checkbox" checked class="i-checks" name="input[]">');
}
else {
$('td', row).eq(0).html('<input type="checkbox" class="i-checks" name="input[]">');
}
},
"searching": false,
"paging": false,
"bInfo": false,
"ordering": false
});
Here is how to get data
var datat = table.fnGetData();
You may need to redraw the datatable after the updation
selectedProduct.draw();
I solved problem but maybe that's not good way.
Here is the solve
var rows = table.fnGetNodes();
var arr = [[]];
for (var i = 0; i < rows.length; i++) {
var detaildata = [];
var cells = rows[i].cells;
detaildata[0] = cells[0].childNodes["0"].checked;
detaildata[1] = cells[1].innerText;
detaildata[2] = cells[2].innerText;
detaildata[3] = cells[3].innerText;
detaildata[4] = cells[4].firstChild.childNodes[1].value;
detaildata[5] = cells[5].innerText;
detaildata[6] = cells[6].firstChild.childNodes[1].value;
detaildata[7] = cells[7].innerText;
detaildata[8] = cells[8].innerText;
arr[[i]] = detaildata;
//var select = cells[0].children[0].value;
//if (cells[0].children[0].checked) {
// select = cells[0].children[0].value;
//} else {
// select = 'off';
//}
}
I need to pass the Value of the first column into the second column render function() to make a hyperlink where the value of the first column is parameter. of the hyperlink.
"Columns": [
{
"data": "Code", "autoWidth": true,
},
{ "data" : "StyleReference","autoWidth": true,
"render": function (data, oObj) {
return '' + data + '';
}
}
]
Any Help Please!!
You're nearly there. The render function can take up to 4 variables. Your row represents the whole object, this should work:
"columns": [{
"data": "Code",
"autoWidth": true
}, {
"data": "StyleReference",
"autoWidth": true,
"render": function(data, type, row, meta) {
return '' + data + '';
}
}]
Hope that helps.
DataTables alerts me if there is an empty cell in my table. Here is the warning:
Requested unknown parameter 'Description' for row 1.
My code is here:
var columns = [
{
mDataProp: 'Description',
sTitle: 'Description'
},
//
// other columns
//
];
var dt = $('#myDataTable').dataTable({
sAjaxSource: '/JobScheduler/GetJobs',
bServerSide: true,
fnServerData: function (sSource, aoData, fnCallback) {
$(aoData).each(function(i, o){
var params = o.name.split('_');
if (params[0] == 'mDataProp')
{
var value = $.grep(aoData, function(e){ return e.name == "sSearch_" + params[1]; })[0].value;
if (value != "")
{
aoData.push({ name: o.value, value: value });
}
}
});
$.getJSON(sSource, aoData, function (data) {
if (isSuccess(data)) {
fnCallback(data.message);
} else {
showMessage(data);
}
});
},
bProcessing: true,
sDom: 'T<"new">Rrlptip',
fnRowCallback: function (nRow, aData) {
nRow.setAttribute('id', aData['JobId']);
},
aoColumns: columns
})
What should I do to prevent this warning? Thanks in advance.
Check your columns and add a defaultContent option for the one(s) causing you issues.
Something like this:
...
{
mDataProp: 'YourData',
sTitle: 'YourDescription',
sDefaultContent: ''
},
...
I m using jquery datatables in many pages and its working good in every page and in a single page its not working properly, i mean when i use tab to go through datatable, it works fine for the first time and when i try to do the same for second time, if i try to focus on any thing in few seconds in data table, the focus disappears and the foucs starts from the starting of the page.
Here goes the code
function tableCall(){
var clientId = $('#clientId').val();
var versionCount = $('#versionCount').val();
var fromDate = $('#fromDate').val();
var toDate = $('#toDate').val();
$.ajax({
url: auditTrail.props.reporttableURL,
type: "POST",
dataType: "json",
data: {
clientId:clientId,
versionCount:versionCount,
fromDate:fromDate,
toDate:toDate
},
success: function (data) {
searchJSON = data.data;
var len=searchJSON.length;
if (len > 0){
$('.no-data, #warning-sign').hide();
createTable();
}else{
$('.no-data').hide();
$('#warning-sign').show();
}
}
});
}
function createTable() {
wwhs.setADAAttrDynamic($('#auditTable'));
if ($.fn.DataTable.isDataTable('#auditTable')) {
// table.destroy();
$("#auditTable tbody").empty();
}
table = $('#auditTable').dataTable({
"searching":false,
"destroy":true,
"autoWidth": false,
"ordering": true,
"destroy":true,
"stateSave": true,
"drawCallback": attachEvents,
"stateLoadParams": function (settings, data) {
return false;
},
data: searchJSON,
columns: [{
data: "reportName"
}, {
data: "reportStatus"
}, {
data: "timeStamp"
}, {
data: "requestedBy"
}],
"columnDefs": [{
"render": function (data, type, row) {
if(row.reportStatus.toUpperCase() == 'PROCESSED')
return '<a class="blue-text" " data-name="'+ row.reportName +'">' + row.reportName + '</a>';
else
return row.reportName;
},
"width": "50%",
"targets": 0
}, {
"width": "15%",
"targets": 1
}, {
"width": "20%",
"targets": 2
}, {
"width": "15%",
"targets": 3
}]
});
}
I think the problem is because the datatable instance is not destroyed.
Since datatables saves all the nodes into an object and renders it when ever it wants, emptying the tbody doesnt do anything. it just removes the elements in the page which can be re-drawn/re-rendered by datatable from its stored object.
You can check if the object is already initialized and the destroy it before re-initializing.
if(typeof table != "undefined")
table.destroy();
So the final code will look something like
function tableCall(){
var clientId = $('#clientId').val();
var versionCount = $('#versionCount').val();
var fromDate = $('#fromDate').val();
var toDate = $('#toDate').val();
$.ajax({
url: auditTrail.props.reporttableURL,
type: "POST",
dataType: "json",
data: {
clientId:clientId,
versionCount:versionCount,
fromDate:fromDate,
toDate:toDate
},
success: function (data) {
searchJSON = data.data;
var len=searchJSON.length;
if (len > 0){
$('.no-data, #warning-sign').hide();
createTable();
} else {
$('.no-data').hide();
$('#warning-sign').show();
}
}
});
}
function createTable() {
wwhs.setADAAttrDynamic($('#auditTable'));
if ($.fn.DataTable.isDataTable('#auditTable')) {
if(typeof table != "undefined")
table.destroy();
}
table = $('#auditTable').dataTable({
"searching":false,
"destroy":true,
"autoWidth": false,
"ordering": true,
"destroy":true,
"stateSave": true,
"drawCallback": attachEvents,
"stateLoadParams": function (settings, data) {
return false;
},
data: searchJSON,
columns: [{
data: "reportName"
}, {
data: "reportStatus"
}, {
data: "timeStamp"
}, {
data: "requestedBy"
}],
"columnDefs": [{
"render": function (data, type, row) {
if(row.reportStatus.toUpperCase() == 'PROCESSED')
return '<a class="blue-text" " data-name="'+ row.reportName +'">' + row.reportName + '</a>';
else
return row.reportName;
},
"width": "50%",
"targets": 0
}, {
"width": "15%",
"targets": 1
}, {
"width": "20%",
"targets": 2
}, {
"width": "15%",
"targets": 3
}]
});
}