DataTable - Appending Additional column is throwing some Exception Error - javascript

I'm trying to implement Server Side DataTable.
Everything goes perfectly fine up to the last rowCallback where I'm appending button to additional column for Actions (i.e. Edit/Delete).
Issue:
Here's my code.
<link href="~/Content/datatables.min.css" rel="stylesheet" /> //<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/dt/dt-1.10.16/datatables.min.css"/>
<link href="~/Content/font-awesome.min.css" rel="stylesheet" />
<div class="container">
<div class="row" style="margin-top:25px">
<table class="table table-bordered table-responsive dataTables-list">
<thead>
<tr>
<th>
Id
</th>
<th>
Name
</th>
<th>
Actions
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
<i class="fa fa-pencil"></i>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
JavaScript:
<script src="~/Scripts/datatables.min.js"></script> //<script type="text/javascript" src="https://cdn.datatables.net/v/dt/dt-1.10.16/datatables.min.js"></script>
<script>
$(document).ready(function () {
$('.dataTables-list').DataTable({
/*Sorting*/
"bSort": true,
"aoColumnDefs": [{
'bSortable': true
}],
"processing": true, // for show progress bar
"serverSide": true, // for process server side
"ajax": {
"url": "/Home/LoadData",
"type": "POST",
"datatype": "json"
},
"aoColumns": [{
"mDataProp": "Id"
}, {
"mDataProp": "Name"
}, {
"mDataProp": "Actions"
}],
"rowCallback": function (row, data, index) {
var newBtns = '<i class="fa fa-pencil"></i> ';
// $(row).append(newBtns);
$('td:eq(2)', row).html(newBtns);
},
language: {
paginate: {
next: '»',
previous: '«'
},
emptyTable: "Der er ingen poster.",
sInfo: "Viser _START_ til _END_ af poster."
}
});
});
</script>
Controller:
[HttpPost]
public ActionResult LoadData()
{
try
{
var draw = Request.Form.GetValues("draw").FirstOrDefault();
var start = Request.Form.GetValues("start").FirstOrDefault();
var length = Request.Form.GetValues("length").FirstOrDefault();
//Find Order Column
var sortColumn = Request.Form.GetValues("columns[" + Request.Form.GetValues("order[0][column]").FirstOrDefault() + "][data]").FirstOrDefault();
var sortColumnDir = Request.Form.GetValues("order[0][dir]").FirstOrDefault();
int pageSize = length != null ? Convert.ToInt32(length) : 0;
int skip = start != null ? Convert.ToInt32(start) : 0;
int recordsTotal = 0;
var v = (from a in _db.AllRoles select a); //Table contains only two Columns - Id and Name
//SORT
if (!(string.IsNullOrEmpty(sortColumn) && string.IsNullOrEmpty(sortColumnDir)))
{
v = v.OrderBy(sortColumn + " " + sortColumnDir);
}
recordsTotal = v.Count();
var data = v.Skip(skip).Take(pageSize).ToList();
return Json(new { draw = draw, recordsFiltered = recordsTotal, recordsTotal = recordsTotal, data = data }, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
throw;
}
}
The issue is due to column difference may be but I don't know how to solve it as implementing ServerSide Datatable for first time.
Thanks in advance.

I modified the below section in my Code to solve the Error.
"aoColumns": [{
"mDataProp": "Id"
}, {
"mDataProp": "Name"
}, {
"mDataProp": "Actions",
"defaultContent": '<i class="fa fa-pencil"></i> '
}],
I added defaultContent for that column as it is not getting values from Database/Sp.
P.S. Answer provided by #dee is also correct and will solve the error. Both are the Solutions to this Question.

The link in the error message provides very good information about what is the problem. You have specified three columns for the DataTable function but as you write in the comment Table contains only two Columns - Id and Name.
"aoColumns": [{
"mDataProp": "Id"
}, {
"mDataProp": "Name"
}, {
"mDataProp": "Actions"
}],
The Resolution section of the document tells what is needed to do:
If using columns ensure that you have specified exactly the number of columns that are present in the HTML for the table.
So you will need the transform the result of the query into another class which will have additional property for Actions. HTH

Related

Can't load table from json using Javascript

I want create a table with JSON using Javascript and obtaining data from a database and show it on my page when I load it. This table thas to have a link to put the data in the selected row into textboxes.
To fill the table I use a method on .asmx:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json, UseHttpGet = false, XmlSerializeString = false)]
public void CargarUsuarios()
{
var wcf = new wsDN.ServicioClient();
var respuesta = wcf.Listar_Usuario().Valor.ToString();
Context.Response.ContentType = "application/json";
Context.Response.Write("{" + $"\"data\" : {respuesta}" + "}");
}
and this is how I create my table:
<table class="table table-bordered table-hover" id="tbl_Usuarios">
<thead>
<tr>
<th>ID Usuario</th>
<th>Cédula</th>
<th>Nombre</th>
<th>Apellidos</th>
<th>Usuario</th>
<th>Contraseña</th>
<th>Opciones</th>
</tr>
</thead>
</table>
and this is the JS:
<script src="js/main.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#tbl_Usuarios').DataTable({
"language": {
"url": "https://cdn.datatables.net/plug-ins/1.10.11/i18n/Spanish.json"
},
"ajax": {
"url": "/Contenido.asmx/CargarUsuarios",
"type": "POST",
"dataType": "json"
},
"columnDefs": [
{
"targets": 6,
"orderable": false,
"render": function (data, type, row) {
return 'Modificar';
}
}
]
});
});
</script>
Probably you need to add some library which will Add DataTable property/function to jquery/html element (do you use this jquery plugin datatables.net ? )

Gijgo Grid doesn't bind data if I call action from ajax

I am using gijgo grid to bind data. I did it two ways using gijgo grid.
1)First Binding data with html helpers to html table and doing CRUD with Gijgo,it binds data,do CRUD but does not reload grid on add,edit and delete.
<table id="grid">
<thead>
<tr>
<th width="56">ID</th>
<th data-sortable="true">Brand</th>
<th data-sortable="true">Model</th>
<th width="64" data-tmpl="<span class='material-icons gj-cursor-pointer'>edit</span>" align="center" data-events="click: Edit"></th>
<th width="64" data-tmpl="<span class='material-icons gj-cursor-pointer'>delete</span>" align="center" data-events="click: Delete"></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.Brand)
</td>
<td>
#Html.DisplayFor(modelItem => item.Model)
</td>
</tr>
}
</tbody>
</table>
in delete function,grid doesn't reload after deleting
function Delete(e) {
if (confirm('Are you sure?')) {
$.ajax({ url: '/Home/Delete', data: { id: e.data.id }, method: 'POST' })
.done(function () {
//grid.reload({ page: 1});
grid.reload();
})
.fail(function () {
alert('Failed to delete.');
});
}
}
2) Then I did a different implementation of gijgo grid binding data via ajax call of gijgo using this example
Gijgo Grid example
The Get function returns JSON
public JsonResult Get(int? page, int? limit, string sortBy, string direction, string brand, string model)
{
List<CarsViewModel> records;
int total;
var query = _context.Cars.Select(p => new CarsViewModel
{
Id = p.Id,
Brand = p.Brand,
Model = p.Model
});
if (!string.IsNullOrWhiteSpace(model))
{
query = query.Where(q => q.Model != null && q.Model.Contains(model));
}
if (!string.IsNullOrWhiteSpace(brand))
{
query = query.Where(q => q.Brand != null && q.Brand.Contains(brand));
}
if (!string.IsNullOrEmpty(sortBy) && !string.IsNullOrEmpty(direction))
{
if (direction.Trim().ToLower() == "asc")
{
switch (sortBy.Trim().ToLower())
{
case "brand":
query = query.OrderBy(q => q.Brand);
break;
case "model":
query = query.OrderBy(q => q.Model);
break;
}
}
else
{
switch (sortBy.Trim().ToLower())
{
case "brand":
query = query.OrderByDescending(q => q.Brand);
break;
case "model":
query = query.OrderByDescending(q => q.Model);
break;
}
}
}
//else
//{
// query = query.OrderBy(q => q.o);
//}
total = query.Count();
if (page.HasValue && limit.HasValue)
{
int start = (page.Value - 1) * limit.Value;
records = query.Skip(start).Take(limit.Value).ToList();
}
else
{
records = query.ToList();
}
return this.Json(new { records, total }, JsonRequestBehavior.AllowGet);
}
jQuery(document).ready(function ($) {
grid = $('#grid').grid({
primaryKey: 'Id',
dataSource: '/Home/Get',
columns: [
{ field: 'Id', width: 56 },
{ field: 'Brand', sortable: true },
{ field: 'Model', sortable: true },
{ width: 64, tmpl: '<span class="material-icons gj-cursor-pointer">edit</span>', align: 'center', events: { 'click': Edit } },
{ width: 64, tmpl: '<span class="material-icons gj-cursor-pointer">delete</span>', align: 'center', events: { 'click': Delete } }
],
pager: { limit: 5 }
});
dialog = $('#dialog').dialog({
autoOpen: false,
resizable: false,
modal: true,
width: 360
});
$('#btnAdd').on('click', function () {
$('#Id').val('');
$('#Brand').val('');
$('#Model').val('');
dialog.open('Add Car');
});
$('#btnSave').on('click', Save);
$('#btnCancel').on('click', function () {
dialog.close();
});
$('#btnSearch').on('click', function () {
grid.reload({ page: 1, name: $('#txtBrand').val(), nationality: $('#txtModel').val() });
});
$('#btnClear').on('click', function () {
$('#txtBrand').val('');
$('#txtModel').val('');
grid.reload({ brand: '', model: '' });
});});
which results in JSON returned in this format
{"records":[{"Id":7,"Brand":"toyota","Model":"matrix"},{"Id":8,"Brand":"Mazda","Model":"M3"}],"total":2} and gives error unable to bind data like
SyntaxError: Unexpected token o in JSON at position 1
If I remove the record and total section and put raw json as datasource like this
[{"Id":7,"Brand":"toyota","Model":"matrix"},{"Id":8,"Brand":"Mazda","Model":"M3"}]
then data is bound but again grid.reload() doesnt work. I am really frustrated why this issues are there. First the gijgo grid server side controller code returns JSON dataas record with total and then I am not able to bind it with the code that gijgo has provided in jquery. Then grid.reload() isn't working
Could you review our ASP.NET examples where everything is setup correctly. You can find them at https://github.com/atatanasov/gijgo-asp-net-examples

Hyperlink gets disabled when reinitializing JQuery DataTable

The following code samples demonstrates how I initialize a jQuery Datatable with HTML, knockout and typescript
HTML:
<table id="coursemoment-info-table" class="table table-hover">
<thead>
<tr >
// headers
</tr>
</thead>
<tbody>
<!-- ko foreach: selectedCourseMoment().courseApplications -->
<tr>
<td>
<a data-bind="{text: ssn, attr:{ href: '/Medlem/' + ssn} }"></a>
</td>
<td data-bind="text:name + ' ' + surname"></td>
.
.
.
</tr>
<!-- /ko-->
</tbody>
</table>
Typescript:
private initCourseMomentInformationDataTable(): void {
$("#coursemoment-info-table").DataTable({
pageLength: 5,
order: [1, 'desc'],
language: {
url: "/Assets/js/jquery-datatable-swedish.json"
}
});
}
I have had some problems with reinitializing the table, but I managed to handle it with first clearing the datatable, and then adding rows to the datatable and redraw it.
if (this.tableInitiliazed) {
$("#coursemoment-info-table").DataTable().clear().draw();
for (var i = 0; i < data.courseApplications.length; i++) {
var application = data.courseApplications[i];
$("#coursemoment-info-table").DataTable().row.add(
[
application.ssn,
// blah blah yada yada
]).draw();
}
This does indeed reinitiliaze the datatable, but it does not put a hyperlink to the first column as it does when initializing the table. All the other table settings are correct, such as language and pagelength.
Since I add one row at a time, with the multiple columns I do not know how to set column settings for "applications.ssn" directly. I have tried to initialize the datatable in the viewmodel with typescript but I get the same problem.
Any ideas how to reinitialize and put a hyperlink setting for a specific column?
I think you want to use Datatables render to create your link. so here is a custom data binder for data table that uses render to create the link.
here is the fiddle to see it in action. http://jsfiddle.net/LkqTU/35823/
ko.bindingHandlers.dataTable = {
init: function(element, valueAccessor, allBindingsAccessor) {
var value = valueAccessor(),
rows = ko.toJS(value);
allBindings = ko.utils.unwrapObservable(allBindingsAccessor()),
$element = $(element);
var table = $element.DataTable( {
data: rows,
columns: [
{ data: "id" },
{ data: "firstName" },
{ data: "lastName" },
{ data: "phone" },
{
data: "ssn",
"render": function ( data, type, full, meta ) {
return '<a href="/Medlem/'+data+'">' + data + '<a>';
}
}
]
} );
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$element.dataTable().fnDestroy();
});
value.subscribe(function(newValue) {
rows = ko.toJS(newValue)
console.log(rows);
$element.find("tbody tr").remove();
table.rows().remove().draw();
setTimeout(function(){ $.each(rows, function( index, row ) {
table.row.add(row).draw()
});
}, 0);
}, null);
}
}

How to loop inside datatable columns declaration?

I have the below datatable declaration and want to display images depend on some column value (team_members). How can I declare the for loop inside columns declaration? i want this result:
var datatableVariable = $('#projects-progress').DataTable({
data: data,
columns: [
{ 'data': 'project_name' },
{ 'data': 'team_members_value' }, // to be hidden
{
//I want loop here depend on the number of team_members_value (second column above)
mRender: function (o) { return '<img src="images/img.jpg" class="avatar" alt="Avatar">';
},
/* EDIT Delete */
{
mRender: function (o) { return '<i class="fa fa-folder"></i> View <i class="fa fa-pencil"></i> Edit <i class="fa fa-trash-o"></i> Delete '; }
},
]
});
<table id="projects-progress" class="table table-striped projects">
<thead>
<tr>
<th>Project Name</th>
<th>Team Members</th>
<th>Actions</th>
</tr>
</thead>
</table>
You can use parameter render in column declaration.
{
"data": "team_members_value",
"render": function (data, type, full, meta) {
var markup = '';
for (var i = 0; i < data; i++) {
markup +='<img src="images/img.jpg" class="avatar" alt="Avatar">'
});
return markup ;
}
}
You need to do something like this:
Add render callback.
Proceed your team_members_value data to render needed markup, save it and return.

Can't make Datatables Pagination with Stored Procedure in MVC5

I've used DataTable to load data from SQL Server and display to Table.
But it just loads data.
Reference: https://gyazo.com/a77f5bee9c8f4fda3be8f9d130499bbf
Not only show this message:
No records found to show
but also, select page and page size selector don't display
Normal: https://gyazo.com/3f6d5193f36b756f752bdd20523d64e0
I hope you guys can give me a kind helpings. Thanks so much
HTML:
<table class="table table-striped table-bordered table-hover table-checkable" id="datatable_products">
<thead>
<tr role="row" class="heading">
<th width="1%">
<input type="checkbox" class="group-checkable">
</th>
<th width="10%"> ID </th>
<th width="15%"> Product Name </th>
<th width="15%"> Category </th>
<th width="10%"> Price </th>
<th width="15%"> Promotion Price </th>
<th width="10%"> Quantity </th>
<th width="15%"> Date Created </th>
<th width="10%"> Status </th>
<th width="10%"> Actions </th>
</tr>
</thead>
<tbody>
</tbody>
</table>
SQL Stored Procedure:
USE [OnlineShop]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[LoadProduct]
#Start INT=0,
#PageLimit INT=10
AS
BEGIN
SET NOCOUNT ON;
SELECT p.ID, p.Name, c.Name Category, p.Price, p.PromotionPrice, (SELECT SUM(Quantity) FROM ProductSizeColor WHERE ProductID = p.ID) as 'SumQuantity', p.CreatedDate, p.[Status]
FROM Product p
LEFT JOIN ProductCategory c
ON p.CategoryID = c.ID
ORDER BY ID
OFFSET #Start ROW
FETCH NEXT #PageLimit ROWS ONLY
END
Javascript:
var handleProducts = function() {
var grid = new Datatable();
grid.init({
src: $("#datatable_products"),
onSuccess: function(grid) {
// execute some code after table records loaded
},
onError: function(grid) {
// execute some code on network or other general error
},
loadingMessage: 'Loading...',
dataTable: {
"lengthMenu": [
[10, 20, 50, 100, 150],
[10, 20, 50, 100, 150] // change per page values here
],
"pageLength": 10, // default record count per page
"ajax": {
"url": "LoadProductTest", // ajax source
},
"processing": true,
"serverSide": true,
"columns": [
{"data": "ForCheckbox"},
{"data": "ID"},
{"data": "Name"},
{"data": "Category"},
{"data": "Price"},
{"data": "PromotionPrice"},
{"data": "SumQuantity"},
{"data": "CreatedDate"},
{"data": "DisplayStatus"},
{"data": "ForAction"},
],
"order": [
[1, "asc"]
] // set first column as a default sort by asc
}
});
Controller:
public ActionResult LoadProductTest()
{
//
var draw = Request.Form.GetValues("draw").FirstOrDefault();
var start = Request.Form.GetValues("start").FirstOrDefault();
var length = Request.Form.GetValues("length").FirstOrDefault();
int pageSize = length != null ? Convert.ToInt32(length) : 0;
int skip = start != null ? Convert.ToInt32(start) : 0;
var model = new ProductDao().LoadProduct(skip, pageSize);
int totalRecords = 0;
return Json(new { draw = draw, recordsFiltered = totalRecords, recordsTotal = totalRecords, data = model } , JsonRequestBehavior.AllowGet);
}
Method Load Product:
public List<ProductViewModel> LoadProduct(int start, int pageLimit)
{
object[] sqlParams = {
new SqlParameter("#Start", start),
new SqlParameter("#PageLimit", pageLimit)
};
return _db.Database.SqlQuery<ProductViewModel>("LoadProduct #Start, #PageLimit", sqlParams).ToList();
}
I found out how to resolve this problem.
In controller, I've set totalRecords = 0. It's wrong, it should get total records from table.
So, You no need to change any thing else but write new Stored Procedure to get count of record.
Controller : change totalRecords = 0 to
int totalRecords = new ProductDao().CountProduct();
CountProduct funtion:
public int CountProduct()
{
return _db.Database.SqlQuery<int>("CountProduct").SingleOrDefault();
}
Stored Procedure to count records:
CREATE PROCEDURE CountProduct
AS
BEGIN
SELECT COUNT(*) FROM Product
END
GO

Categories