Below is the code
I'm using to bind DataTable
. This same code works fine with an MVC
project with MVC controller
. But facing problems when trying the same code with API controller.
`window.UpcomingPaymentTables = {
dataTable: null,
buildDataTable: function () {
this.dataTable = $("#UpcomingPaymentsGrid").DataTable({
columnDefs: [
{ targets: [0], data: "Date" },
{ targets: [1], data: "Amount" }
],
processing: true,
stateSave: true,
serverSide: true,
filter: true,
lengthMenu: [[10, 25, 50], [10, 25, 50]],
autoWidth: false,
ajax: {
url: "/api/Plans/GetUpcomingPayments",
type: 'POST',
dataFilter: function (resp) {
debugger;
return resp;
},
error: function (xhr, error, code) {
alert(error);
}
}
});
},
destroyDataTable: function () {
if (this.dataTable) {
this.dataTable.destroy();
}
}
}`
Receiving an empty object
in "resp" variable of dataFilter.
Below is the API
endpoint:
[HttpPost]
[Route("GetUpcomingPayments")]
public DataTablesResult GetUpcomingPayments([FromForm] DataTablesRequest request)
{
var data = _planService.GetUpcomingPayments(122).ReadDataTable(request);
DataTablesResult rs = new DataTablesResult(data);
return rs;
}
DataTablesResult
has all the required properties
for Datatable
. The same code is working for the MVC controller
. the only difference is I'm trying it with API Controller
.
In API Controller
I had to pass the DataTablesRequest object using [FromForm] while in MVC controller
it doesn't need.
Using the following code
on a razor component
to call the js
functions.
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await _jsRuntime.InvokeVoidAsync("UpcomingPaymentTables.destroyDataTable");
await _jsRuntime.InvokeVoidAsync("UpcomingPaymentTables.buildDataTable");
}
}
Am I missing something in API controller
to return the data in the required format?
Update:
Do not define $upcomingTable
and udt
, use them directly, because you are calling window.UpcomingPaymentTables
, the definition is not recognized externally:
window.UpcomingPaymentTables = {
buildDataTable: function () {
this.dataTable = $("#UpcomingPaymentsGrid").DataTable({
//...
});
},
destroyDataTable: function () {
if (this.dataTable) {
this.dataTable.destroy();
}
}
}
The corresponding data is not passed in your ajax
request, which will cause the Api call to fail. In the JSON returned from the Api, the keys are all lowercase by default. Also, I'm not sure how the rs
you return look like, but make sure it's of type List/Array/Enumerable
.
Below is a working demo, you can refer to it (For convenience, I just used the DataTablesRequest
model).
DataTablesRequest:
public class DataTablesRequest
{
public string Date { get; set; }
public string Amount { get; set; }
}
TestController:
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
[HttpPost]
[Route("GetUpcomingPayments")]
public List<DataTablesRequest> Get([FromForm] DataTablesRequest request)
{
var Request = new DataTablesRequest()
{
Date = "Date1",
Amount = "Amount1"
};
var RequestList = new List<DataTablesRequest>() { Request };
return RequestList;
}
}
DataTables.razor:
@page "/datatables"
@implements IDisposable
@using BlazorApp.Shared
@inject HttpClient Http
@inject IJSRuntime JS
<table class="table" id="dt2">
<thead>
<tr>
<th>Date</th>
<th>Amount</th>
</tr>
</thead>
</table>
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender)
{
await JS.InvokeVoidAsync("DataTables.buildDataTable");
}
}
async void IDisposable.Dispose()
{
await JS.InvokeVoidAsync("DataTables.destroyDataTable");
}
}
DataTables.js:
window.DataTables = {
dataTable: null,
buildDataTable: function (ajaxUrl) {
var data = {
"Date": "TestDate",
"Amount": "TestAmount"
}
this.dataTable = $("#dt2").DataTable({
"ajax": {
"url": "/api/Test/GetUpcomingPayments",
"type": "POST",
"data": data,
"dataSrc": "",
"dataFilter": function (resp) {
debugger;
return resp;
},
"error": function (xhr, error, code) {
alert(error);
}
},
columnDefs: [
//lowercase
{ targets: [0], data: "date" },
{ targets: [1], data: "amount" }
],
processing: true,
stateSave: true,
filter: true,
lengthMenu: [[10, 25, 50], [10, 25, 50]],
autoWidth: false
});
},
destroyDataTable: function () {
if (this.dataTable) {
this.dataTable.destroy();
}
}
}
Don't forget to reference the JS file:
<script src="js/DataTables.js"></script>
Test Result: