You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular Datatable首次渲染无数据,排序/搜索后恢复的问题求助

Angular Datatable首次渲染不加载数据,排序/搜索后正常的问题排查与解决

问题描述

使用Angular Datatable通过Ajax从API获取数据时,组件首次渲染无法加载数据,但点击列排序或使用搜索栏后数据显示正常。已在ngOnInit方法中初始化dtOptions,预期首次渲染即可加载数据。

控制台报错

main.ts:11 ERROR TypeError: Cannot read properties of undefined (reading 'length')
    at Jb (node_modules\datatables.net\js\jquery.dataTables.min.js:40:238)
    at Aa (node_modules\datatables.net\js\jquery.dataTables.min.js:62:175)
    at f (node_modules\datatables.net\js\jquery.dataTables.min.js:111:104)
    at HTMLTableElement.<anonymous> (node_modules\datatables.net\js\jquery.dataTables.min.js:111:157)
    at Function.each (node_modules\jquery\dist\jquery.js:385:1)
    at jQuery.fn.init.each (node_modules\jquery\dist\jquery.js:207:1)
    at jQuery.fn.init.u [as dataTable] (node_modules\datatables.net\js\jquery.dataTables.min.js:101:182)
    at l.fn.DataTable (node_modules\datatables.net\js\jquery.dataTables.min.js:191:467)
    at angular-datatables.directive.js:80:58
    at timer (zone.js:2405:41)

环境信息

  • NodeJS version: 18.0.0
  • Angular version: 14.1.0
  • Angular CLI version: 14.1.0
  • jQuery version: 3.6.1
  • DataTables version: ^14.0.0
  • angular-datatables version: ^14.0.0

现有代码

ngOnInit代码

ngOnInit() {
    const me = this;
 // get language
 this.langServiceSupscribtion = this.sharedService.lang.subscribe((l) => {
  this.lang = l;
});

this.dtOptions = {
  paging: true,
  pagingType: 'full_numbers',
  pageLength: 10,
  autoWidth: true,
  serverSide: true,
  searching: true,
  ajax: (dataTablesParameters: any, callback, settings) => {
    console.log(dataTablesParameters);
    dataTablesParameters.searchCriteria = me._searchCriteria;
    me.transactionService
      .getAllTransactionsFunctional(dataTablesParameters)
      .subscribe((resp) => {
        if (resp['succeeded']) {
          me.transactionsList = resp['data'];
          console.log(me.transactionsList);
          callback({
            recordsTotal: resp['recordsTotal'],
            recordsFiltered: resp['recordsFiltered'],
            data: [],
          });
        } else {
          console.log("resp['errors']");
        }
      });
  },
  columns: [
    { data: 'transactionType' },
    { data: 'radionuclideName' },
    { data: 'radioActivity' },
    { data: 'createdOn' },
    { data: 'facilityEn' },
    { data: 'licenseNumber' },
    { data: 'permitNumber' },
    { data: 'manufacturerSerialNo' },
    { data: 'sourceStatus' },
    { data: null },
  ],
};

HTML代码

<table
          datatable
          [dtOptions]="dtOptions"
          id="sourcesDataTable"
          class="table datatable table-responsive table-striped table-bordered row-border table-hover table-sm w-100 overflow-auto"
        >
          <thead>
            <tr>
              <th class="select-filter">
                {{ "landingPage.transactionType" | translate }}
              </th>
              <th class="select-filter">
                {{ "landingPage.radionuclide" | translate }}
              </th>
              <th class="select-filter">
                {{ "landingPage.radioactivity" | translate }}
              </th>
              <th class="select-filter">
                {{ "landingPage.transactionDate" | translate }}
              </th>
              <th class="select-filter">
                {{ "landingPage.facility" | translate }}
              </th>
              <th class="select-filter">
                {{ "landingPage.license" | translate }}
              </th>
              <th class="select-filter">
                {{ "landingPage.permit" | translate }}
              </th>
              <th class="select-filter">
                {{ "landingPage.manufacturerSerialNo" | translate }}
              </th>
              <th class="select-filter">
                {{ "landingPage.transactionStatus" | translate }}
              </th>
              <th>{{ "landingPage.view" | translate }}</th>
            </tr>
          </thead>
          <tbody *ngIf="transactionsList?.length != 0">
            <tr *ngFor="let t of transactionsList">
              <td>{{ t.transactionType }}</td>
              <td>{{ t.radionuclideName }}</td>
              <td>{{ t.radioActivity }}</td>
              <td>{{ t.createdOn }}</td>
              <td>{{ t.facilityEn }}</td>
              <td>{{ t.licenseNumber }}</td>
              <td>{{ t.permitNumber }}</td>
              <td>{{ t.manufacturerSerialNo }}</td>
              <td>{{ t.sourceStatus }}</td>
              <td class="px-2">
                <button
                  class="edit btn btn-success btn-sm mx-1"
                  style="width: 100%"
                >
                  <fa-icon [icon]="faListDots"> </fa-icon>
                </button>
              </td>
            </tr>
          </tbody>
          <tbody *ngIf="transactionsList?.length == 0">
            <tr>
              <td colspan="10" class="no-data-available">
                {{ "no_data" | translate }}
              </td>
            </tr>
          </tbody>
          <tfoot>
            <th>
              <input
                class="search-input"
                name="transactionType"
                type="text"
                placeholder="{{
                  'landingPage.transactionTypePlaceholder' | translate
                }}"
                style="width: 100%"
              />
            </th>
            <th>
              <input
                class="search-input"
                name="radionuclide"
                type="text"
                placeholder="{{
                  'landingPage.radionuclidePlaceholder' | translate
                }}"
                style="width: 100%"
              />
            </th>
            <th>
              <input
                class="search-input"
                name="radioactivity"
                type="text"
                placeholder="{{
                  'landingPage.radioactivityPlaceholder' | translate
                }}"
                style="width: 100%"
              />
            </th>
            <th>
              <input
                class="search-input"
                name="transactionType"
                type="text"
                placeholder="{{
                  'landingPage.transactionDatePlaceholder' | translate
                }}"
                style="width: 100%"
              />
            </th>
            <th>
              <input
                class="search-input"
                name="transactionType"
                type="text"
                placeholder="{{
                  'landingPage.facilityPlaceholder' | translate
                }}"
                style="width: 100%"
              />
            </th>
            <th>
              <input
                class="search-input"
                name="transactionType"
                type="text"
                placeholder="{{ 'landingPage.licensePlaceholder' | translate }}"
                style="width: 100%"
              />
            </th>
            <th>
              <input
                class="search-input"
                name="transactionType"
                type="text"
                placeholder="{{ 'landingPage.permitPlaceholder' | translate }}"
                style="width: 100%"
              />
            </th>
            <th>
              <input
                class="search-input"
                name="transactionType"
                type="text"
                placeholder="{{
                  'landingPage.manufacturerSerialNoPlaceholder' | translate
                }}"
                style="width: 100%"
              />
            </th>
            <th>
              <input
                class="search-input"
                name="transactionType"
                type="text"
                placeholder="{{
                  'landingPage.transactionStatusPlaceholder' | translate
                }}"
                style="width: 100%"
              />
            </th>
            <th></th>
          </tfoot>
        </table>

问题原因与解决方法

核心原因

  1. transactionsList未初始化:组件初始化时transactionsList为undefined,导致模板中*ngIf="transactionsList?.length != 0"无法渲染tbody,Datatable初始化时读取不到数据引发length错误。
  2. ServerSide回调数据冲突:ajax回调中传递data: [],但手动用Angular模板渲染数据,这种配置让Datatable首次初始化时无法获取有效数据,而排序/搜索时重新触发ajax,此时transactionsList已赋值,模板渲染正常。

解决步骤

1. 初始化transactionsList为空数组

在组件类中定义时直接初始化:

transactionsList: any[] = [];

2. 修正ajax回调的data字段

将回调中的data改为获取到的transactionsList,让Datatable能识别数据:

callback({
  recordsTotal: resp['recordsTotal'],
  recordsFiltered: resp['recordsFiltered'],
  data: me.transactionsList,
});

3. 优化模板tbody判断

合并两个tbody的判断逻辑,避免undefined导致的渲染问题:

<tbody>
  <tr *ngFor="let t of transactionsList">
    <td>{{ t.transactionType }}</td>
    <td>{{ t.radionuclideName }}</td>
    <td>{{ t.radioActivity }}</td>
    <td>{{ t.createdOn }}</td>
    <td>{{ t.facilityEn }}</td>
    <td>{{ t.licenseNumber }}</td>
    <td>{{ t.permitNumber }}</td>
    <td>{{ t.manufacturerSerialNo }}</td>
    <td>{{ t.sourceStatus }}</td>
    <td class="px-2">
      <button class="edit btn btn-success btn-sm mx-1" style="width: 100%">
        <fa-icon [icon]="faListDots"> </fa-icon>
      </button>
    </td>
  </tr>
  <tr *ngIf="transactionsList.length === 0">
    <td colspan="10" class="no-data-available">
      {{ "no_data" | translate }}
    </td>
  </tr>
</tbody>

4. 可选:手动触发Datatable初始化(若上述步骤无效)

使用DtTrigger控制初始化时机,确保数据加载完成后再初始化Datatable:

  • 组件中引入并定义DtTrigger:
import { DtTrigger } from 'angular-datatables';

export class YourComponent implements OnInit, OnDestroy {
  dtTrigger: DtTrigger = new DtTrigger();
  // ...其他代码

  ngOnDestroy(): void {
    this.dtTrigger.unsubscribe();
  }
}
  • 在ajax回调成功后触发:
me.transactionService.getAllTransactionsFunctional(dataTablesParameters).subscribe((resp) => {
  if (resp['succeeded']) {
    me.transactionsList = resp['data'];
    me.dtTrigger.next(); // 触发Datatable初始化
    callback({
      recordsTotal: resp['recordsTotal'],
      recordsFiltered: resp['recordsFiltered'],
      data: me.transactionsList,
    });
  }
});
  • 模板中添加[dtTrigger]="dtTrigger":
<table
  datatable
  [dtOptions]="dtOptions"
  [dtTrigger]="dtTrigger"
  id="sourcesDataTable"
  class="table datatable table-responsive table-striped table-bordered row-border table-hover table-sm w-100 overflow-auto"
>

内容的提问来源于stack exchange,提问作者saleem99

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 08:01:21