Search code examples
jquerydatatablesblazor-client-sideblazor-webassembly

TypeError: Cannot read property 'removeChild' of null in blazor clinet app on using Jquery datatables


I am using jquery datatables on a blazor client app. In a razor component, I have a form which collects user inputs and get data from server. I then fill the a html table with incoming data and invoke Jquery DataTable on it. It works fine as long as number of rows are same but I get below exception when number of rows are reduced -

 Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Cannot read property 'removeChild' of null
      TypeError: Cannot read property 'removeChild' of null

Below is my razor component -

@page "/internalhealthreport"
@using BMI.SWV.Reporting.Shared;
@using Microsoft.Extensions.Configuration;
@inject HttpClient HttpClient
@inject IJSRuntime JSRuntime
@inject SpinnerService SpinnerService
@inject IConfiguration Configuration
@*@implements IDisposable*@

<body>
    <h1 class="mb-5">INTERNAL HEALTH REPORT</h1>
    <hr />
    <EditForm Model="@this.HealthReportArgs" OnValidSubmit="@HandleValidSubmit" style="width:fit-content">
        <div class="container">
            <DataAnnotationsValidator />
            <ValidationSummary />
            <div class="row">
                <div class="col-sm">
                    <div class="form-group">
                        <label for="txtAccountNo">Account Number</label>
                        <input type="text" class="form-control" name="accountNumber" placeholder="923935" @bind-value="this.HealthReportArgs.accountNumber">
                    </div>
                </div>
                <div class="col-sm">
                    <div class="form-group">
                        <label for="txtIpiBaseNumber">IPI Base Number</label>
                        <input type="text" class="form-control" name="ipiBaseNumber" placeholder="I-002184856-4" @bind-value="this.HealthReportArgs.ipiBaseNumber">
                    </div>
                </div>
                <div class="col-sm">
                    <div class="form-group">
                        <label for="txtIpiNameNumber">IPI Name Number</label>
                        <input type="text" class="form-control" name="ipiNameNumber" placeholder="00454808047" @bind-value="this.HealthReportArgs.ipiNameNumber">
                    </div>
                </div>
                <div class="col-sm">
                    <div class="form-group">
                        <label for="txtTaxId">Tax Id</label>
                        <input type="text" class="form-control" name="taxIdKey" placeholder="211700435" @bind-value="this.HealthReportArgs.taxIdKey">
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col-md-12 text-center">
                    <div class="form-group">
                        <input type="submit" class="btn btn-primary btn-lg btn-block" value="Search">
                    </div>
                </div>
            </div>
        </div>
    </EditForm>
    <hr />
    @if (this.HealthReportRows.Count() > 0)
     {
        <div class="row">
            <div class="results-table" style="overflow-x: auto;">
                <table id="resultsTable" class="table table-bordered table-striped table-sm" style="font-size:smaller;white-space:nowrap">
                    <thead class="thead-dark">

                        <tr>
                            <th>Name</th>
                            <th>Title Name</th>
                            <th>Account #</th>
                            <th>AKA Seq #</th>
                            <th>IPI Base #</th>
                            <th>IPI Name #</th>
                            <th>Title #</th>
                            <th>Title ID</th>
                            <th>Sender #</th>
                            <th>Sender Name</th>
                            <th>ISWC</th>
                            <th>SWV Status</th>
                            <th>SWV Status Reason</th>
                            <th>P/W Ind</th>
                            <th>Pay Mode</th>
                            <th>Share</th>
                        </tr>
                    </thead>
                    <tbody>
                        @foreach (var healthReportRow in this.HealthReportRows)
                        {
                            <tr>
                                <td>@healthReportRow.Name</td>
                                <td>@healthReportRow.TitleName</td>
                                <td>@healthReportRow.AccountNumber</td>
                                <td>@healthReportRow.AKASeqNumber</td>
                                <td>@healthReportRow.IPIBaseNumber</td>
                                <td>@healthReportRow.IPINameNumber</td>
                                <td>@healthReportRow.TitleNumber</td>
                                <td>@healthReportRow.TitleID</td>
                                <td>@healthReportRow.SenderNo</td>
                                <td>@healthReportRow.OriginalSubmitterName</td>
                                <td>@healthReportRow.ISWC</td>
                                <td>@healthReportRow.SongViewStatus</td>
                                <td>@healthReportRow.SongViewReason</td>
                                <td>@healthReportRow.PublisherWriterIndicator</td>
                                <td>@healthReportRow.PayMode</td>
                                <td>@healthReportRow.Share</td>
                            </tr>
                         }
                    </tbody>
                </table>
            </div>
        </div>
     }
</body>

@code {

    public HealthReportArgs HealthReportArgs { get; set; } = new HealthReportArgs() { };

    public HealthReportRow[] HealthReportRows { get; set; } = new HealthReportRow[] { };

    public async void HandleValidSubmit()
    {
        SpinnerService.Show();

        var settings = new Settings(Configuration);
        if (string.IsNullOrWhiteSpace(settings.HealthReportApiUrl))
        {
            throw new Exception($"Configuration value missing: {nameof(settings.HealthReportApiUrl)}");
        }

        this.HealthReportRows = await HttpClient.GetReportRows<HealthReportRow>(apiUrl: settings.HealthReportApiUrl, args: this.HealthReportArgs);

        await JSRuntime.InvokeAsync<object>("TestDataTablesRemove", "#resultsTable");
        await JSRuntime.InvokeAsync<object>("InitDataTable", "#resultsTable");
        this.StateHasChanged();

        SpinnerService.Hide();
    }
}

And here are the scripts in index.html -

function InitDataTable(table) {
            $(document).ready(function () {
                if (!$.fn.DataTable.isDataTable('#resultsTable')) {
                    $(table).DataTable({
                        dom: 'Bfrtip',
                        buttons: [
                            'copy', 'csv', 'excel', 'pdf', 'print'
                        ]
                    });
                }
            });
        }

        function TestDataTablesRemove(table) {
            $(document).ready(function () {
                if ($.fn.DataTable.isDataTable('#resultsTable')) {
                    $('#resultsTable').DataTable().destroy(true);                 
                }
            });
        }

Solution

  • you will have to clear the table on button click I guess. Please try this -

    @code {
    
        public HealthReportArgs HealthReportArgs { get; set; } = new HealthReportArgs() { };
    
        public HealthReportRow[] HealthReportRows { get; set; } = new HealthReportRow[] { };
    
        public async void HandleValidSubmit()
        {
            SpinnerService.Show();
    
            await JSRuntime.InvokeAsync<object>("TestDataTablesRemove", "#resultsTable");
    
            SpinnerService.Show();
    
            var settings = new Settings(Configuration);
            if (string.IsNullOrWhiteSpace(settings.HealthReportApiUrl))
            {
                throw new Exception($"Configuration value missing: {nameof(settings.HealthReportApiUrl)}");
            }
    
            this.HealthReportRows = await HttpClient.GetReportRows<HealthReportRow>(apiUrl: settings.HealthReportApiUrl, args: this.HealthReportArgs);
    
            this.StateHasChanged();
    
            await JSRuntime.InvokeAsync<object>("InitDataTable", "#resultsTable");
    
            SpinnerService.Hide();
        }
    
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
    
                await JSRuntime.InvokeAsync<object>("InitDataTable", "#resultsTable");
            }
        }