在 Blazor WASM 中使用 jQuery DataTable

Using jQuery DataTable in Blazor WASM

我想将 jQuery DataTable 与我的 Blazor Wasm 项目集成。所以我添加了对这些文件的引用:

//cdn.datatables.net/1.11.4/css/jquery.dataTables.min.css

//cdn.datatables.net/1.11.4/js/jquery.dataTables.min.js

并编写此函数以调用适当的初始函数:

window.ApplyjQueryDatatable = () => {
    $('#example').DataTable();
}

为了创建 table 我在剃须刀页面中写了这段代码:

@page "/"
@inject IJSRuntime JsRuntime

<div class="row mt-4 ">
    <div class="col-12">
        <table id="example" @ref="@DataTableContainer">
            <thead>
                <tr>
                    <th>OrderID</th>
                    <th>CustomerID</th>
                    <th>OrderDate</th>
                    <th>ShipCity</th>
                    <th>ShipPostalCode</th>
                    <th>ShipCountry</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var item in OrderPage)
                {
                    <tr>
                        <td>@item.OrderID</td>
                        <td>@item.CustomerID</td>
                        <td>@item.OrderDate</td>
                        <td>@item.ShipCity</td>
                        <td>@item.ShipPostalCode</td>
                        <td>@item.ShipCountry</td>
                    </tr>
                }
            </tbody>
        </table>
    </div>
</div>

@code {
    private ElementReference DataTableContainer;
    private List<Orders> OrderPage { set; get; } = new List<Orders>();

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender == true)
        {
            //Web API Call Simulation

            OrderPage = new List<Orders>();
            OrderPage.Add(new Orders() { CustomerID = "aa1", OrderDate = DateTime.Now, OrderID = 1, ShipCity = "bb1", ShipCountry = "cc1", ShipPostalCode = "dd1" });
            OrderPage.Add(new Orders() { CustomerID = "aa2", OrderDate = DateTime.Now, OrderID = 1, ShipCity = "bb2", ShipCountry = "cc2", ShipPostalCode = "dd2" });
            OrderPage.Add(new Orders() { CustomerID = "aa3", OrderDate = DateTime.Now, OrderID = 1, ShipCity = "bb3", ShipCountry = "cc3", ShipPostalCode = "dd3" });
            OrderPage.Add(new Orders() { CustomerID = "aa4", OrderDate = DateTime.Now, OrderID = 1, ShipCity = "bb4", ShipCountry = "cc4", ShipPostalCode = "dd4" });
            OrderPage.Add(new Orders() { CustomerID = "aa5", OrderDate = DateTime.Now, OrderID = 1, ShipCity = "bb5", ShipCountry = "cc5", ShipPostalCode = "dd5" });

            await JsRuntime.InvokeVoidAsync("ApplyjQueryDatatable");
            StateHasChanged();
        }

        await base.OnAfterRenderAsync(firstRender);
    }
}

运行项目后有2个问题:

  1. Table 已创建,但我得到的是空 table 消息:

  1. 当我单击任何列时 header table 行突然消失并且 table 为空:

如何解决这些问题?

谢谢


编辑 1)

根据@Henk 的回答,我这样修改了代码:

protected override async Task OnInitializedAsync()
{
    var AllData = await apiServices.GetOrders();
    OrderPage = AllData.Take(100).ToList();
    //await JsRuntime.InvokeVoidAsync("ApplyjQueryDatatable");
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender == true)
    {
        await JsRuntime.InvokeVoidAsync("ApplyjQueryDatatable");
    }
}

新问题是当 table 再次创建任何 jQuery DataTable 功能时不起作用。例如,如果我更改下拉记录数,则 table 将为空:

当我点击任何 header 时:

我该如何解决这个问题?谢谢


编辑 2)

再次根据@Henk 的评论:我以这种方式更改了代码并且有效:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender == true)
    {
        var AllData = await apiServices.GetOrders();
        OrderPage = AllData.Take(100).ToList();

        StateHasChanged();
        await JsRuntime.InvokeVoidAsync("ApplyjQueryDatatable");
    }
    base.OnAfterRender(firstRender);
}

我觉得听说有一点小。如果我这样更改代码:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender == true)
    {
        OrderPage = new List<OrdersDTO>();
        OrderPage.Add(new OrdersDTO() { CustomerID = "aa1", OrderDate = DateTime.Now, OrderID = 1, ShipCity = "bb1", ShipCountry = "cc1", ShipPostalCode = "dd1" });
        OrderPage.Add(new OrdersDTO() { CustomerID = "aa2", OrderDate = DateTime.Now, OrderID = 2, ShipCity = "bb2", ShipCountry = "cc2", ShipPostalCode = "dd2" });
        OrderPage.Add(new OrdersDTO() { CustomerID = "aa3", OrderDate = DateTime.Now, OrderID = 3, ShipCity = "bb3", ShipCountry = "cc3", ShipPostalCode = "dd3" });
        OrderPage.Add(new OrdersDTO() { CustomerID = "aa4", OrderDate = DateTime.Now, OrderID = 4, ShipCity = "bb4", ShipCountry = "cc4", ShipPostalCode = "dd4" });
        OrderPage.Add(new OrdersDTO() { CustomerID = "aa5", OrderDate = DateTime.Now, OrderID = 5, ShipCity = "bb5", ShipCountry = "cc5", ShipPostalCode = "dd5" });
        OrderPage.Add(new OrdersDTO() { CustomerID = "aa6", OrderDate = DateTime.Now, OrderID = 6, ShipCity = "bb6", ShipCountry = "cc6", ShipPostalCode = "dd6" });
        OrderPage.Add(new OrdersDTO() { CustomerID = "aa7", OrderDate = DateTime.Now, OrderID = 7, ShipCity = "bb7", ShipCountry = "cc7", ShipPostalCode = "dd7" });
        OrderPage.Add(new OrdersDTO() { CustomerID = "aa8", OrderDate = DateTime.Now, OrderID = 8, ShipCity = "bb8", ShipCountry = "cc8", ShipPostalCode = "dd8" });
        OrderPage.Add(new OrdersDTO() { CustomerID = "aa9", OrderDate = DateTime.Now, OrderID = 9, ShipCity = "bb9", ShipCountry = "cc9", ShipPostalCode = "dd9" });
        OrderPage.Add(new OrdersDTO() { CustomerID = "aa10", OrderDate = DateTime.Now, OrderID = 6, ShipCity = "bb10", ShipCountry = "cc10", ShipPostalCode = "dd10" });
        OrderPage.Add(new OrdersDTO() { CustomerID = "aa11", OrderDate = DateTime.Now, OrderID = 6, ShipCity = "bb11", ShipCountry = "cc11", ShipPostalCode = "dd11" });
        OrderPage.Add(new OrdersDTO() { CustomerID = "aa12", OrderDate = DateTime.Now, OrderID = 6, ShipCity = "bb12", ShipCountry = "cc12", ShipPostalCode = "dd12" });

        StateHasChanged();
        await JsRuntime.InvokeVoidAsync("ApplyjQueryDatatable");
    }
    base.OnAfterRender(firstRender);
}

如果行不通。紧张......

但是如果我这样写它会起作用:

await Task.Run(() =>
{
    OrderPage = new List<OrdersDTO>();
    OrderPage.Add(new OrdersDTO() { CustomerID = "aa1", OrderDate = DateTime.Now, OrderID = 1, ShipCity = "bb1", ShipCountry = "cc1", ShipPostalCode = "dd1" });
    OrderPage.Add(new OrdersDTO() { CustomerID = "aa2", OrderDate = DateTime.Now, OrderID = 2, ShipCity = "bb2", ShipCountry = "cc2", ShipPostalCode = "dd2" });
...

为什么这段代码以这种方式工作?

更新

随着异步加载,它变得更加毛茸茸。 jQuery 将捕获数据,这必须在正确的时刻发生。

bool loaded = false;
protected override async Task OnInitializedAsync()
{
    await LoadData();
    loaded = true;  
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (loaded)
    {
        loaded = false;
        await JsRuntime.InvokeVoidAsync("ApplyjQueryDatatable");
    }        
}

这里的根本问题是 jQuery 修改了 DOM 并且使 Blazor 持有的副本无效。所以你可能会遇到不一致的情况。更好的解决方案是使用 Blazor 数据网格。


旧答案

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender == true)
    {
        //Web API Call Simulation
        // Do the async loading here

        await JsRuntime.InvokeVoidAsync("ApplyjQueryDatatable");
        //StateHasChanged();  -- remove
    }
}