Search code examples
asp.net-core.net-coredatatablesasp.net-core-webapiblazor-server-side

How to receive response from an API endpoint to bind the DataTablein Blazor server project


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?


Solution

  • 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:

    enter image description here

    enter image description here

    enter image description here