英文:
How to receive response from an API endpoint to bind the DataTablein Blazor server project
问题
以下是我为您翻译的代码部分:
以下是我用于绑定 DataTable 的代码。这段代码在 MVC 项目中与 MVC 控制器一起使用时可以正常工作,但在尝试与 API 控制器一起使用时出现问题。
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();
}
}
}
在 dataFilter 中收到一个空的 "resp" 变量。
以下是 API 端点:
[HttpPost]
[Route("GetUpcomingPayments")]
public DataTablesResult GetUpcomingPayments([FromForm] DataTablesRequest request)
{
var data = _planService.GetUpcomingPayments(122).ReadDataTable(request);
DataTablesResult rs = new DataTablesResult(data);
return rs;
}
DataTablesResult
具有 DataTable 所需的所有属性。与 MVC 控制器一起,相同的代码正常工作。唯一的区别是我正在尝试与 API 控制器一起使用。在 API 控制器中,我必须使用 [FromForm] 将 DataTablesRequest 对象传递,而在 MVC 控制器中则不需要。
在 Razor 组件上使用以下代码来调用 JavaScript 函数:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await _jsRuntime.InvokeVoidAsync("UpcomingPaymentTables.destroyDataTable");
await _jsRuntime.InvokeVoidAsync("UpcomingPaymentTables.buildDataTable");
}
}
我在 API 控制器中是否遗漏了一些内容以返回所需格式的数据?
请注意,翻译文本中的 `"` 实际上是 HTML 编码的双引号,您在代码中应该使用双引号 `"`. 此外,翻译文本中的 `'` 实际上是 HTML 编码的单引号,您在代码中应该使用单引号 `'`.
<details>
<summary>英文:</summary>
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?
</details>
# 答案1
**得分**: 0
```plaintext
**更新:**
不要定义 `$upcomingTable` 和 `udt`,直接使用它们,因为你正在调用 `window.UpcomingPaymentTables`,在外部无法识别定义:
```javascript
window.UpcomingPaymentTables = {
buildDataTable: function () {
this.dataTable = $("#UpcomingPaymentsGrid").DataTable({
//...
});
},
destroyDataTable: function () {
if (this.dataTable) {
this.dataTable.destroy();
}
}
}
相应的数据没有在你的 ajax
请求中传递,这将导致 Api 调用失败。在 Api 返回的 JSON 中,默认情况下键名都是小写。此外,我不确定你返回的 rs
是什么样子的,但请确保它是 List/Array/Enumerable
类型。
以下是一个可工作的演示,你可以参考它(为了方便起见,我只是使用了 DataTablesRequest
模型):
public class DataTablesRequest
{
public string Date { get; set; }
public string Amount { get; set; }
}
[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: [
//小写
{ 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();
}
}
}
不要忘记引用 JS 文件:
<script src="js/DataTables.js"></script>
测试结果:
<details>
<summary>英文:</summary>
**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][1]][1]
[![enter image description here][2]][2]
[![enter image description here][3]][3]
[1]: https://i.stack.imgur.com/UZrB7.png
[2]: https://i.stack.imgur.com/98NfP.png
[3]: https://i.stack.imgur.com/aLzgb.png
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论