DataTable how to get data from AJAX - javascript

I've been making CRUD tables in school traditionally through scaffolding per page and wanted to try out if I could do all operations without using Partial View. I opted to use AJAX which I followed a guide here: https://dzone.com/articles/crud-operation-in-aspnet-mvc-using-ajax-and-bootst
Everthing works flawlessly, but I wanted to use DataTable API to add Search and sorting functionality to the table. This is what the table looks like
HERE.
As you can see it doesn't recognize the data coming from the JS that I made, most notably with "Showing 0 to 0 of 0 entries". Is there any way to load data from AJAX to the DataTable script? Thanks very much! I'll provide my code below.
EDIT: I put the DataTable initilization in Inventory.js and the DataTable SOMETIMES works on page load. It's very random when trying to refresh the page multiple times. I tried putting a delay before the page loads to see if that makes any difference but it doesn't work. Anybody know what's going?
Inventory(model)
public List<Inventory> ListAll()
{
List<Inventory> lst = new List<Inventory>();
using (SqlConnection con = new SqlConnection(Helper.GetCon()))
{
con.Open();
string query = #"SELECT * FROM Inventory";
using (SqlCommand cmd = new SqlCommand(query, con))
{
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
lst.Add(new Inventory
{
InventoryId = Convert.ToInt32(dr["inv_id"]),
Category = Helper.Decrypt(dr["category_name"].ToString()),
Name = Helper.Decrypt(dr["item_name"].ToString()),
Details = Helper.Decrypt(dr["item_details"].ToString()),
Quantity = Convert.ToInt32(dr["quantity"]),
CsbCode = Helper.Decrypt(dr["csb_code"].ToString()),
Notes = Helper.Decrypt(dr["notes"].ToString()),
Location = Helper.Decrypt(dr["location"].ToString()),
DateCreated = DateTime.Parse(dr["date_created"].ToString()),
LastModified = DateTime.Parse(dr["last_modified"].ToString()),
});
}
return lst;
}
}
}
}
InventoryController.cs
public JsonResult List()
{
return Json(invDB.ListAll(), JsonRequestBehavior.AllowGet);
}
Inventory.js(How I get my data)
function loadData() {
$.ajax({
url: "/Inventory/List",
type: "GET",
contentType: "application/json;charset=utf-8",
dataType: "json",
success: function (result) {
var html = '';
$.each(result, function (key, item) {
html += '<tr>';
html += '<td>' + item.InventoryId + '</td>';
html += '<td>' + item.Category + '</td>';
html += '<td>' + item.Name + '</td>';
html += '<td>' + item.Details + '</td>';
html += '<td>' + item.Quantity + '</td>';
html += '<td>' + item.CsbCode + '</td>';
html += '<td>' + item.Notes + '</td>';
html += '<td>' + item.Location + '</td>';
html += '<td>' + dateTimeFormat(item.DateCreated) + '</td>';
html += '<td>' + dateTimeFormat(item.LastModified) + '</td>';
html += '<td>Edit | Delete</td>';
html += '</tr>';
});
$('.tbody').html(html);
},
error: function (errormessage) {
alert(errormessage.responseText);
}
});
}
Index (DataTable script):
#section scripts {
<script src="https://cdn.datatables.net/1.10.19/js/dataTables.uikit.min.js"></script>
<script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/buttons/1.5.6/js/dataTables.buttons.min.js"></script>
<script src="https://cdn.datatables.net/buttons/1.5.6/js/buttons.print.min.js"></script>
<script>
$(document).ready(function () {
$('#user').DataTable({
dom: 'Bfrtip',
buttons: [
'print'
]
});
});
</script>
}

I am using 1.10 Jquery Datatables and for the templating i am using Underscore JS.
Here is my code for loading from server side.
Put this template and table in your html code.
<table class="table table-bordered table-condensed" id="tblAccounts"></table>
<script type="text/template" id="tmpl_Grid">
<td><%= Id %></td>
<td><%= Amount %></td>
<td><%= Date %></td>
<td><%= Type %></td>
</script>
Then this method for js to load data from server side.
function Load() {
var tmpl = _.template($('#tmpl_Grid').html());
$('#tblAccounts').DataTable({
"dom": "<'row'<'col-md-6 col-sm-12'l><'col-md-6 col-sm-12'f>r>t<'row'<'col-md-5 col-sm-12'i><'col-md-7 col-sm-12'p>>",
"paging": true,
"info": true,
"ordering": true,
"search": true,
"processing": true,
"serverSide": true,
"destroy": true,
"ajax": {
"url": "/Accounts/LoadList",
"type": "POST",
"data": function (d) {
d.startDate = $("#txtStartDate").val();
d.endDate = $("#txtEndDate").val();
}
},
"columns": [
{ "data": null, "title": "ID", "className": "", "orderable": false, "searchable": false },
{ "data": null, "title": "AMOUNT", "className": "", "orderable": false, "searchable": false },
{ "data": null, "title": "DATE", "className": "", "orderable": false, "searchable": false },
{ "data": null, "title": "TYPE", "className": "", "orderable": false, "searchable": false }
],
"order": [[0, "asc"]],
"rowCallback": function (row, data) {
$(row).html(tmpl(data));
},
"initComplete": function (settings, json) {
}
});
}
Here is the code for controller. I am using EntityFrameword for database processing you can use your own method or technique.
[HttpPost]
public async Task<JsonResult> LoadList(string startDate, string endDate)
{
var search = Request.Form["search[value]"] + "";
var totalCount = 0;
var fList = _context.Expenses.Include(x => x.AccountType).AsQueryable();
if (!string.IsNullOrEmpty(search))
{
fList = fList.Where(x => x.Description.ToLower().Trim().Contains(search.ToLower().Trim()));
}
var list = await fList.OrderByDescending(x => x.Id).Skip(start).Take(length).Select(x => new
{
x.Id,
x.Amount,
Date = x.Date != null ? x.Date.Value.ToString("dd-MMM-yyyy") : "",
Type = x.AccountTypeId != null ? x.AccountType.Name : "",
x.Description,
x.BillAmount,
x.Payment,
x.AccountTypeId
}).ToListAsync();
if (list.Any())
{
totalCount = fList.Count();
}
var result = JObject.FromObject(new
{
draw,
recordsFiltered = totalCount,
recordsTotal = totalCount,
data = list
});
return result;
}

thanks for the help. I got it to work consistently with a post I found on the same forum.
I changed my code for getting my data to this. Apparently you need to append the data, this was the most important thing that got my DataTables to work.
$("#user tbody").append(html);
$.ajax({
url: "/Artwork/List",
type: "GET",
contentType: "application/json;charset=utf-8",
dataType: "json",
success: function (result) {
$.each(result, function (key, item) {
var html = '';
html += '<tr>';
html += '<td>' + item.ArtID + '</td>';
html += '<td>' + item.Name + '</td>';
html += '<td>' + item.Details + '</td>';
html += '<td>' + item.Location + '</td>';
html += '<td>' + item.Notes + '</td>';
html += '<td>' + dateTimeFormat(item.DateCreated) + '</td>';
html += '<td>' + dateTimeFormat(item.LastModified) + '</td>';
html += '<td>Edit | Delete</td>';
html += '</tr>';
$("#user tbody").append(html);
});
$('#user').DataTable({
destroy: true,
dom: 'Bfrtip',
buttons: [
{
extend: 'print',
exportOptions: {
columns: ':visible' ,
}
},
'colvis'
],
columnDefs: [{
visible: false
}]
});
Again, thank you!

Related

Display Show More / Show Less option if text if more then 20 length

I try to add option in my Debatable column Description if text length is more then 20 character long display Show more option and collapse this column.
I try couple of option and one which work for me is something like this
function loadDataTable() {
dataTable = $('#tblData').DataTable({
"ajax": {
"url": "/Manager/Ticket/GetAll"
},
"columnDefs": [{
"targets": 0,
"data": "description",
"render": function (data, type, row, meta) {
return type === 'display' && data.length > 20 ?
'<span title="' + data + '">' + data.substr(0, 17) + '...</span>' :
data;
}
}],
"columns": [
{
"data": "description",
"width": "10%",
//"render": function (data) {
// return 'Prikazi vise'
//}
},
{ "data": "shortDescription", "width": "10%" },
{ "data": "dateAndTime", "width": "10%" },
{ "data": "ticketType.name", "width": "10%" },
{ "data": "status", "width": "10%" },
{
"data": "applicationUser.name",
"width": "10%",
"render": function (data) {
return '<a id="' + data + '" class="text-info user-details" data-toggle="modal" data-target="#userDetails" href="' + data + '" target_blank>' + data + '</a>'
}
},
{
"data": "id",
"render": function (data) {
return `
<div class="text-center">
<a href="/Manager/Ticket/Details/${data}" class="btn btn-success text-white" style="cursor:pointer">
<i class="fas fa-info-circle">Detalji/Chat</i>
</a>
<a href="/Manager/Ticket/Upsert/${data}" class="btn btn-primary text-white" style="cursor:pointer">
<i class="fas fa-edit">Uredi</i>
</a>
</div>
`;
}, "width": "15%"
}
]
});
}
After I add columnsDef
"columnDefs": [{
"targets": 0,
"data": "description",
"render": function (data, type, row, meta) {
return type === 'display' && data.length > 20 ?
'<span title="' + data + '">' + data.substr(0, 17) + '...</span>' :
data;
}
}],
This option works but only when User hover column it display text. I add ... and I want to create that this tree dots needs to be as <a> and should be clickable and when user click it needs to Show More and Show Less option.
I check couple of post here starting from this
REFERENCE 1
The problem here is that I am noob in jQuery and JavaScript and I have no idea how to implement this side.
This is how it look like right now
UPDATE
I found some solutions but doesn't work at all. I change my columnDef
"columnDefs": [{
"targets": 0,
"data": "description",
"render": function (data, type) {
return type === 'display' && data.length > 20 ?
'<span id="outer" data-shrink="' + data.substr(0, 17) + '" title="' + data + '"></span><span id="show">...</span>' :
data;
}
}],
Here is my JavaScript
$(document).ready(function () {
$(".tblData").hide();
$(".showmore").on("click", function () {
var txt = $(".tblData").is(':visible') ? 'Vise' : 'Manje';
$(".showmore").text(txt);
$(this).next('.tblData').slideToggle(200);
});
});
I successfully add ... to be clickable, but when I click text is not showing.
UPDATE
"columnDefs": [{
"targets": 0,
"data": "description",
"render": function (data, type) {
return type === 'display' && data.length > 20 ?
'<span id="outer" title="' + data + '">' + data.substr(0, 17) + '</span><span id="show">...</span>' :
data;
}
}],
$('#show').click(function () {
var text = $('#outer').attr('title');
$(this).text(text);
$('#show').after('<a id="less" onclick="someFunction()" href="#"> Show less</a>');
$('#outer').text('');
});
function someFunction() {
console.log('test');
$('#less').remove();
var txt = $('#outer').attr('data-shrink');
$('#show').text('');
$('#outer').text(txt);
$('#show').text('...');
}
var len = $('#outer').text();
if(len.length > 20) {
var txt = $('#outer').attr('data-shrink');
console.log(txt);
$('#outer').text(txt);
$('#show').text('...');
}
$('#show').click(function() {
var text = $('#outer').attr('title');
console.log('text', text.length);
$(this).text(text);
$('#show').after('<a id="less" onclick="someFunction()" href="#"> Show less</a>');
$('#outer').text('');
});
function someFunction() {
console.log('test');
$('#less').remove();
var txt = $('#outer').attr('data-shrink');
$('#show').text('');
$('#outer').text(txt);
$('#show').text('...');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span id="outer" data-shrink="Das ist ein" title="Das ist ein ganzer Text langer Text">Das ist ein sehr langer Text</span><span id="show"></span>
Just replace the html with your variables.

Using "later" variable in jQuery DataTables

My DataTables configuration is something like this:
(function ($) {
"use strict";
$(document).ready(function () {
$('#data-table-users').DataTable({
"processing": true,
"serverSide": true,
"filter": true,
"orderMulti": false,
"ajax": {
"url": "/Users/GetUsersData",
"type": "POST",
"datatype": "json"
},
"columnDefs":
[{
"targets": [0],
"visible": false,
"searchable": false
}],
"columns": [
.............................
{
"data": "Image",
"orderable": false,
"render": function (data, type, row, meta) {
var imgSrc;
if (data != null) {
imgSrc = '"data:image/jpeg;base64,' + atob(data) + '"';
}
else {
imgSrc = "/svg/" + "A" + ".svg";
}
return '<div><img class="small-img" src=' + imgSrc + '></div>';
}
},
{
"data": "UserName",
"render": function (data, type, row, meta) {
return '<div class="positioned"> <div class="editable" data-name="userName" contenteditable="true">'
+ data + '</div > <i class="fa fa-pencil pushright" aria-hidden="true"></i> </div>';
}
},
{
"data": "FirstName",
"render": function (data, type, row, meta) {
if (data == null)
data = "";
return '<div class="positioned"> <div class="editable" data-name="userName" contenteditable="true">'
+ data + '</div > <i class="fa fa-pencil pushright" aria-hidden="true"></i> </div>';
}
},
............................
],
"order": [[8, "desc"]]
});
});
})(jQuery);
For Image column I have in the Render function:
else {
imgSrc = "/svg/" + "A" + ".svg";
}
What I would like is instead of having imgSrc = "/svg/A.svg" is to construct it based on UserName column like so:
imgSrc = "/svg/" + userName[0].toUpperCase() + ".svg";
How can I do that without changing code on server side? It seems to me that DataTables is rendering UserName cell at a later time, so Image cell is already rendered. Can somehow a trigger be added when UserName is rendered to alter Image cell content?
I can change the values for all cells in Image column after the whole table gets rendered, but somehow I dislike that idea because it might look ugly. So, please, don't suggest that.
Just got it. I can access all data for the current row using row parameter.
So it's just:
imgSrc = "/svg/" + row['UserName'][0].toUpperCase() + ".svg";

How to create nested datatable from JSON array object response

I get API response in JSON format with nested arrays in it. I want to parse it in nested datatable. I've tried for this, but it won't work. Can anyone let me know where I made a mistake. In JSON I have passenger data & each passenger having multiple drivers, I want to show it in datatable in nested format, like Passenger is parent & respective drivers of it as child.
Expected Result
Here is my JSON response:
/* Formatting function for row details - modify as you need */
function format(driver_data) {
// `d` is the original data object for the row
return '<table cellpadding="5" cellspacing="0" border="0" style="padding-left:50px;">' +
'<tr>' +
'<td>Full name:</td>' +
'<td>' + driver_data.employeename + '</td>' +
'</tr>' +
'<tr>' +
'<td>Extension number:</td>' +
'<td>' + driver_data.email + '</td>' +
'</tr>' +
'</table>';
}
$(document).ready(function () {
var table = $('.trip_unmacthed').DataTable({
type: "GET",
url: "https://api.myjson.com/bins/13woes",
dataType: "json",
"columns": [
{
"className": 'details-control',
"orderable": false,
"data": null,
"defaultContent": ''
},
{
"data": "employeename"
},
{
"data": "email"
}
],
"order": [[1, 'asc']]
});
// Add event listener for opening and closing details
$('.trip_unmacthed tbody').on('click', 'td.details-control', function () {
var tr = $(this).closest('tr');
var row = table.row(tr);
if (row.child.isShown()) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
} else {
// Open this row
row.child(format(row.data())).show();
tr.addClass('shown');
}
});
});
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<table class="table table-striped table-bordered table-hover trip_unmacthed">
<thead>
<tr>
<th>User Type</th>
<th> Name</th>
<th>Start Location</th>
<th>Drop Location</th>
<th> Date </th>
<th>Actions</th>
</tr>
</thead>
<tbody id="myData">
</tbody>
</table>
Change the passenger_data to data according to API Docs and your format function.
$(document).ready(function () {
function format(driver_data) {
console.log(driver_data); var b = ''; var i;
for (i = 0; i < driver_data.length; i++) {
b = b + '<tr>' +
'<td></td>' +
'<td>' + driver_data[i].employeename + '</td>' +
'<td>' + driver_data[i].email + '</td>' +
'<td>' + driver_data[i].distance + '</td>' +
'</tr>';
}
return b;
}
var table = $('#example').DataTable({
"ajax": "https://api.myjson.com/bins/y53hs",
"columns": [
{
"className": 'details-control',
"orderable": false,
"data": null,
"defaultContent": ''
},
{
"data": "employeename"
},
{
"data": "email"
},
{
"data": "mobilenumber"
}
],
"order": [[1, 'asc']]
});
// Add event listener for opening and closing details
$('#example tbody').on('click', 'td.details-control', function () {
var tr = $(this).closest('tr');
var row = table.row(tr);
if (row.child.isShown()) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
} else {
// Open this row
console.log(row.data());
row.child(format(row.data().driver_data)).show();
tr.addClass('shown');
}
});
});
Not sure about what your JSON is . If you have a passenger in your JSON e.g.
{
"passenger_data": [
{
"employeename": "Passenger A",
"email": null,
"driver_data": [
{
"employeename": "Driver A1",
"email": null,
"distance": 0,
},
{
"employeename": "Driver A2",
"email": null,
"distance": 0,
},
],
"mobilenumber": "+12344576",
},
]
}
then you should do it like
"columns": [
{"passenger_data": "employeename"},
{"passenger_data": "driver_data.employeename"},
{"passenger_data": "driver_data.email"}
],
may be your are not using the . operator

How to use "formatter" dynamically in jqGrid.Is it possible?

Is there a way to dynamically use the "formatter" in jqGrid?I want to make use of formatTitle function from the code dynamically, Here is my code:
HTML
<table id="list47"><tr><td></td></tr></table>
<div id="plist47"></div>
Javascript:
var md=[{ "id": "83123a", Name: "Name 1", "PackageCode": "83123a" },
{ "id": "83432a", Name: "Name 3", "PackageCode": "83432a" },
{ "id": "83566a", Name: "Name 2", "PackageCode": "83566a" }]
var he=["id","Name","PackageCode"];
var c=[];
for(var i=0;i<he.length;i++){
c.push('{"name":"'+he[i]+'","index":"'+he[i]+'"}');
}
var colmodel="["+c+"]"
//var colmodel= [{name:'id', index:'id', width:55},
// {name:'Name', index:'Name' },
// {name:'PackageCode', index:'PackageCode'}]
// c.push('{"name":"'+he[i]+'","index":"'+he[i]+'"'+'"formatter":'+formatTitle+'}');
jQuery("#list47").jqGrid({
//data: md,
datatype: "local",
height: 150,
rowNum: 10,
colNames: he,
colModel: jQuery.parseJSON(colmodel),
rowList: [10,20,30],
pager: "#plist47",
viewrecords: true,
caption: "json data grid"
});
for(var i=0;i<md.length;i++){
jQuery("#list47").addRowData(i+1,md[i]);
}
function formatTitle(cellValue, options, rowObject) {
return "<a href='" + rowObject.Link + "'>" + cellValue.substring(0, 45) + "..." + "</a>";
//return cellValue.substring(0, 50) + "...";
};
You have to put the formatter in a string as follows
for(var i=0;i<he.length;i++){
c.push('{"name":"'+he[i]+'","index":"'+he[i]+'"'+',"formatter":"formatTitle"'+'}');
}
Then you defind the formatter before the jqGrid code as follows
$.fn.fmatter.formatTitle = function (cellValue, options, rowObject) {
return "<a href='" + rowObject.Link + "'>" + cellValue.substring(0, 45) + "..." + "</a>";
};
Because it is wrapped in a string(formatter: "formatTitle") you cant use your former signature for the formatter which was
function formatTitle(cellValue, options, rowObject) This can be used if formatter: formatTitle which is not possible to construct dynamically
Here is a jsfiddle solution to your problem

dataTable page length change issue

I am using dataTable 1.10. Everything works well but I got following situation. I think that dataTable not support this behaviour.
By default I set the page length be 10, then I click Next page, table display items from 11 to 20. NOW I change the page length to 25, table display item from 11 to 35. This is not the thing I suppose to have. Whenever I change the page length, I wish to display from 1st item.
Is it possible to handle the Page Length change event in dataTable and customize that function?
Thank for reading. Hope to receive help from you.
var tableHdr = '<table cellpadding="0" cellspacing="0" border="0" class="display" id="alertsList">'
+ '<thead><tr>'
+ '<th>Level</th><th>Monitor Name</th><th>Alert Message</th><th>Raised At</th><th>Action</th>'
+ '</tr></thead></table>';
$('#overview_content').html( tableHdr );
//global variable
oTable = $('#alertsList').dataTable( {
"pagingType": "full_numbers",
"bJQueryUI": true,
"aaData": alertsData,
"bAutoWidth": false,
"aaSorting" : [[3, "desc"]],
"aoColumns": [
{ "sTitle": "Level", "mData":"alert_level", "sWidth":"10%" },
{ "sTitle": "Monitor Name", "mData":"monitor_name", "sWidth":"20%" },
{ "sTitle": "Alert Message", "mData":"alert_message", "sWidth":"30%" },
{ "sTitle": "Raised At", "mData":"triggered_datetime", "sWidth":"20%"},
{ "sTitle": "Action", "mData":"id", "bSortable":false, "bSearchable":false, "sWidth":"20%"}
],
"columnDefs": [
{
"targets": 1,
"data":"monitor_name",
"render": function ( data, type, full, meta ) {
return escapeHTML(data);
}
},
{
"targets": 2,
"data":"alert_message",
"render": function ( data, type, full, meta ) {
if (data == null || typeof data == 'undefined')
{
return "";
}
var description = data.length > 30? data.substr(0,30) + '...': data;
return escapeHTML(description);
}
},
{
"targets": 4,
"render": function ( data, type, full, meta ) {
return ("<span style='cursor:pointer' id='dismiss_alert_" + full.id + "' class='dismiss'>Dismiss</span> | " +
"<span style='cursor:pointer' id='delete_alert_" + full.id + "' class='delete'>Delete</span> | " +
"<span style='cursor:pointer' id='details_alert_" + full.id + "' class='details'>Details</span>");
}
} ]
} );
Try this, I found it from datatable forum.
var t = $('#table-id').dataTable();
$('#length li').click(function () {
redrawWithNewCount(t, this.id);
});
function redrawWithNewCount(t, row_count) {
//Lifted more or less right out of the DataTables source
var oSettings = t.fnSettings();
oSettings._iDisplayLength = parseInt(row_count, 10);
t._fnCalculateEnd(oSettings);
/* If we have space to show extra rows (backing up from the end point - then do so */
if (oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay()) {
oSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength;
if (oSettings._iDisplayStart < 0) {
oSettings._iDisplayStart = 0;
}
}
if (oSettings._iDisplayLength == -1) {
oSettings._iDisplayStart = 0;
}
t.fnDraw(oSettings);
return t;
}

Categories