如何解决PrimeNG的 p-table中 pTemplate='rowexpansion' 的问题?表格的行无法展开

前端开发 2026-07-11

我遇到了一个问题。pTemplate="rowexpansion" 在p-table上不起作用,可能是我的实现方式与PrimeNG的文档不太一致。

在展开方面,我想使用p-button的 (click) 和其中的一个特定函数来获取数据。我在按钮上放了 [pRowToggler]="entry",但它不起作用。有什么可行的实现思路?

文件 component.html

<div style="height: calc(100vh - 230px)">
<p-table
      #dt
      [columns]="columns"
      dataKey="someKey"
      [value]="smthliste"
      [expandedRowKeys]="expandedRowKeys"
      [(selection)]="selectedsmthliste"
      selectionMode="multiple"
      [totalRecords]="totalElements"
      [rowsPerPageOptions]="[10, 50, 100]"
      [lazy]="true"
      (onLazyLoad)="filtersmthliste($event)"
      [scrollable]="true"
      scrollHeight="flex"
      [paginator]="true"
      [(rows)]="numberOfRows"
      [showCurrentPageReport]="true"
      styleClass="p-datatable-gridlines, p-datatable-striped, p-datatable-sm"
      >
<ng-template pTemplate="header" let-columns>
...
</ng-template>
<ng-template
        pTemplate="body"
        let-entry
        let-columns="columns"
        let-ri="rowIndex"
      >
<tr [attr.data-test]="'smthliste-' + ri">
          <td
            class="sticky-checkbox"
            [attr.data-test]="'smthliste-' + ri + '-column-checkbox'"
          >
            <p-tableCheckbox
              [name]="'checkbox' + ri"
              [value]="entry"
            ></p-tableCheckbox>
          </td>
          <td class="sub-super-elements-td sticky-checkbox">
            <div class="sub-super-elements">
              @if (!rowExpansionExpanded.includes(entry.someKey)) {
                <p-button
                  class="sub-super-elements__button-super"
                  [pRowToggler]="smthliste"
                  (click)="onClickExpansion('super', entry)"
                  data-test="button-super"
                  [icon]="'pi pi-directions'"
                  [plain]="true"
                  pRipple
                  [rounded]="true"
                  size="large"
                  [text]="true"
                  type="button"
                ></p-button>
              }
              @if (!rowExpansionExpanded.includes(entry.someKey)) {
                <p-button
                  class="sub-super-elements__button-sub"
                  (click)="onClickExpansion('sub', entry)"
                  data-test="button-sub"
                  [icon]="'pi pi-directions'"
                  [plain]="true"
                  pRipple
                  [pRowToggler]="entry"
                  [rounded]="true"
                  size="large"
                  [text]="true"
                  type="button"
                ></p-button>
              }
              @if (rowExpansionExpanded.includes(entry.someKey)) {
                <p-button
                  class="sub-super-elements__button-close"
                  (click)="onClickExpansion('close', entry)"
                  data-test="button-close"
                  [icon]="'pi pi-chevron-up'"
                  [plain]="true"
                  pRipple
                  [pRowToggler]="entry"

                  [rounded]="true"
                  size="large"
                  [text]="true"
                  type="button"
                ></p-button>
              }
            </div>
          </td>
         </tr>
...

<ng-template pTemplate="rowexpansion" let-entry>
        <tr>
          <td colspan="999">
            <div class="p-3">
              <div>DEBUG: {{ entry.someKey }} | expansion length: {{ entry.expansion?.length }}</div>
              <app-smthliste-row-expansion
                [...]="..."
                [columns]="columns"
                [...]="
                  ...
                "
                [...]="..."
                [onClickExpansion]="onClickExpansion"
                [(pTableSelection)]="selectedsmthliste"
                [rowExpansionExpanded]="rowExpansionExpanded"
                [selectedUserGroup]="sessionService...."
                [smthlisten]="entry.expansion"
                [...]="..."
                [...]="..."
                >
              </app-smthliste-row-expansion>
            </div>
          </td>
        </tr>
      </ng-template>
    </p-table>

文件 component.ts

...

onClickExpansion(type: 'super' | 'sub' | 'close', smthliste: Smthliste) {
    this.table.toggleRow(smthliste);
    console.log('1. onClick called', type, smthliste.someKey);

    if (type === 'close') {
      const indexOf = this.rowExpansionExpanded.indexOf(someliste.someKey);
      if (indexOf >= 0) {
        this.rowExpansionExpanded.splice(indexOf, 1);
      }
      delete this.expandedRowKeys[smthliste.someKey];
      return;
    }

    if (this.rowExpansionExpanded.includes(smthliste.smthKey)) {
      console.log('2. Already expanded, returning');
      return;
    }

    console.log('3. Calling API for', type);
    const superSubSmthlistenObservable =
      type === 'super'
        ? this.smthlisteService.getSuperSmthlisten(smthliste)
        : this.smthlisteService.getSubSmthlisten(smthliste);

    superSubSmthlistenObservable.subscribe({
      next: (superSubSmthlisten) => {
        console.log('4. API returned', superSubSmthlisten);

        if (!superSubSmthlisten || superSubSmthlisten.length === 0) {
          this.messageService.add({
            severity: 'info',
            summary: 'No data',
            detail: `No ${type} elements found for ${smthliste.someKey}`,
          });
          return; // Do not expand empty row
        }

        smthliste.expansion = superSubSmthlisten;
        this.rowExpansionExpanded.push(smthliste.someKey);
        this.expandedRowKeys[smthliste.someKey] = true;
        this.cdr.detectChanges();
      },
      error: (err) => {
        console.error('API ERROR:', err);
      },
    });
  }

...
this.dt.toggleRow(entry); // It doesn't work

Delete(点击)不起作用。

只有这个能工作,但这并不是我想要的:

<!-- ...existing code... -->

<ng-template pTemplate="body">
  <tr >


  @if (rowExpansionExpanded.includes(entry.someKey)) {
    <tr>
      <td colspan="999">
        <div class="p-3">
          <div>DEBUG: </div>

          <app-smthliste-row-expansion
          >
          </app-smthliste-row-expansion>
        </div>
      </td>
    </tr>
  }
</ng-template>

解决方案

移除切换控件,确保你的 p-button 只触发你的逻辑,它是为“无逻辑的切换”场景设计的。移除它后,你就可以通过 onClickExpansion 函数获得完全的控制。

要渲染 pTemplate="rowexpansion",PrimeNG会检查该行的 dataKey 是否存在于 expandedRowKeys 对象中。你现在是手动在管理这个,但你必须确保对象引用会更新,以便Angular能检测到变化。

  1. dataKey 匹配: 确保你在 <p-table> 中的 dataKey="someKey" 与属性名 entry.someKey 完全一致。如果不匹配,PrimeNG就不会知道要展开哪一行。
  2. 展开模板的位置: 确保你的 <ng-template pTemplate="rowexpansion" let-entry><p-table> 的直接子元素。它应该在 pTemplate="body" 之外但在 p-table 标签内。
  3. 可变vs不可变: PrimeNG常常使用 ChangeDetectionStrategy.OnPush。如果你只是简单地执行 this.expandedRowKeys[key] = true,对象引用仍然相同,表格可能不会重新渲染。请始终使用扩展运算符 { ...this.expandedRowKeys } 来创建一个新的引用。

请按如下操作:

  1. 从按钮中移除 [pRowToggler]
  2. 确保表格上的 dataKey"someKey"
  3. 在订阅中用不可变的方式更新 expandedRowKeys
  4. 在表格绑定中使用 this.expandedRowKeys[expandedRowKeys]="expandedRowKeys"
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章