【问题标题】:PrimeNG table with grouped columns won't sort具有分组列的 PrimeNG 表不会排序
【发布时间】:2018-12-18 03:43:49
【问题描述】:

PrimeNG 表可以按列排序。 https://www.primefaces.org/primeng/#/table/sort

它们也可以有列组。 https://www.primefaces.org/primeng/#/table/colgroup

很遗憾,我无法让这两个功能协同工作。前者的示例代码通过动态列生成简化了创建过程,但后者的示例代码需要手动编码每一列。

我有一种编写代码的方法,在我看来它应该可以工作,并且它可以毫无错误地构建和显示;但是单击排序图标时它不会对数据进行排序。

这是我的代码(去掉了识别变量名):

<div *ngIf="(sourceObservableReturningAnArray$ | async) as arrayOfDataNeeded">
  <p-table
    [value]="arrayOfDataNeeded"
    autoLayout="true"
    sortField="firstSortedProperty"
    [rows]="25">
    <ng-template pTemplate="header" let-columns>
      <tr>
        <th rowspan="2" [pSortableColumn]="arrayOfDataNeeded.firstSortedProperty">
          Header for First Property
          <p-sortIcon [field]="arrayOfDataNeeded.firstSortedProperty"></p-sortIcon>
        </th>
        <th rowspan="2" [pSortableColumn]="arrayOfDataNeeded.secondSortedProperty">
          Header for Second Property
          <p-sortIcon [field]="arrayOfDataNeeded.secondSortedProperty"></p-sortIcon>
        </th>
        <th rowspan="2" [pSortableColumn]="arrayOfDataNeeded.thirdSortedProperty">
            Header for Third Property
            <p-sortIcon [field]="arrayOfDataNeeded.thirdSortedProperty"></p-sortIcon>
        </th>
        <th rowspan="2" [pSortableColumn]="arrayOfDataNeeded.fourthSortedProperty">
            Header for Fourth Property
            <p-sortIcon [field]="arrayOfDataNeeded.fourthSortedProperty"></p-sortIcon>
        </th>
        <th rowspan="2" [pSortableColumn]="arrayOfDataNeeded.fifthSortedProperty">
            Header for Fifth Property
            <p-sortIcon [field]="arrayOfDataNeeded.fifthSortedProperty"></p-sortIcon>
        </th>
        <th [pSortableColumn]="arrayOfDataNeeded.sixthSortedProperty" colspan="2">
            Header with Subheadings
            <p-sortIcon [field]="arrayOfDataNeeded.sixthSortedProperty"></p-sortIcon>
        </th>
        <th rowspan="2" [pSortableColumn]="arrayOfDataNeeded.seventhSortedProperty">
            Header for Seventh Property
            <p-sortIcon [field]="arrayOfDataNeeded.seventhSortedProperty"></p-sortIcon>
        </th>
      </tr>
      <tr>
        <th>Subheading 1</th>
        <th>Subheading 2</th>
      </tr>
    </ng-template>
    <ng-template pTemplate="body" let-data>
        <tr>
            <td>{{data.firstSortedProperty | currency}}</td>
            <td>{{data.secondSortedProperty}}</td>
            <td>{{data.thirdSortedProperty | date : 'shortTime'}}<br>{{data.thirdProperty | date : 'MM/dd/yyyy'}}</td>
            <td>{{data.fourthSortedProperty}}%</td>
            <td>{{data.fifthSortedProperty}}%</td>
            <td>{{data.sixthSortedProperty}}%</td>
            <td>{{data.additionalUnsortedProperty | currency}}</td>
            <td>{{data.seventhSortedProperty}}</td>
        </tr>
    </ng-template>
  </p-table>
</div>

我猜测问题出在排序字段的规范中:因为 arrayOfDataNeeded 是一个对象数组,但它是具有我想要排序的属性的对象,也许我没有识别对象的以正确的方式处理相关财产。我对 PrimeNG 不够熟悉,不知道我应该怎么做。有可能我可以通过使用隐式上下文来解决它,但我不确定是什么。

开始标记中的 sortField="firstSortedProperty" 完全符合预期,因此数据源似乎没有问题。

如果您看到我的错误,请指出!如果我在问题描述中遗漏了任何内容,我很乐意回答澄清问题。我也愿意接受有关实现所需功能的替代方法的建议。

【问题讨论】:

  • 您是否检查过在排序后打开组?对于如何对分组的行/列进行排序,经常会感到困惑。有些人希望对整个组进行排序,而有些则只对组内的值进行排序!
  • @alokstar - 感谢您的建议。我试过在没有列组的情况下设置它,但它仍然无法排序。所以我认为这不是问题的根源。尽管如此,列组仍然是相关的,因为它似乎要求我不动态生成列。它也与任何替代实现有关。还是我误解了你的建议?
  • 我发现了几个变通方法,其中一个有轻微的代码气味(但很容易),另一个工作干净(但需要一些额外的工作来重新设计方法)。如果没有其他答案,我会在几天后回答我自己的问题。

标签: angular html-table primeng


【解决方案1】:

所以对于我最初的问题,[至少] 有两种解决方案。第一个很快,但有代码味道。第二个涉及更多,但也可能是解决我提出的问题的正确方法。


第一个解决方案

1) 首先,在component.ts文件中添加以下内容:

cols: any[];

this.cols = [
      { field: 'firstSortedProperty', header: 'Header for First Property'},
      { field: 'secondSortedProperty', header: 'Header for Second Property'},
      { field: 'thirdSortedProperty', header: 'Header for Third Property'},
      { field: 'fourthSortedProperty', header: 'Header for Fourth Property'},
      { field: 'fifthSortedProperty', header: 'Header for Fifth Property'},
      { field: 'sixthSortedProperty', header: 'Header for Sixth Property'},
      { field: 'additionalUnsortedProperty', header: '[It Doesn't Show, So Whatever]'},
      { field: 'seventhSortedProperty', header: 'Header for Seventh Property'},
    ];

2) 然后,在 component.html 文件中,将 [columns]="cols" 添加到 p-table 属性中。

<p-table
    [value]="arrayOfDataNeeded"
    [columns]="cols"
    autoLayout="true"
    sortField="firstSortedProperty"
    [rows]="25">

解释:通过为 p 表提供 columns 属性的值,在每列中找到的字段名称变得可访问。 columns 属性应该包含一个数组,列将从该数组中动态生成,但您没有这样做。 (棘手!)它目前有效,但不知道将来对 PrimeNG 的更改是否会破坏这种解决方法。


第二个解决方案

实际上可以在同时使用标题和副标题的同时动态生成列。

1) 为了实现它,我们必须为 cols 数组中的对象添加更多属性。

this.cols = [
      { field: 'firstSortedProperty', header: 'Header for First Property', hasSubs: false, isSub: false},
      { field: 'secondSortedProperty', header: 'Header for Second Property', hasSubs: false, isSub: false},
      { field: 'thirdSortedProperty', header: 'Header for Third Property', hasSubs: false, isSub: false},
      { field: 'fourthSortedProperty', header: 'Header for Fourth Property', hasSubs: false, isSub: false},
      { field: 'fifthSortedProperty', header: 'Header for Fifth Property', hasSubs: false, isSub: false},
      { field: 'sixthSortedProperty', header: 'Header for Sixth Property', hasSubs: true, isSub: false},
      { field: 'additionalUnsortedProperty', header: '[It Doesn't Show, So Whatever]', hasSubs: false, isSub: true},
      { field: 'seventhSortedProperty', header: 'Header for Seventh Property', hasSubs: false, isSub: false},
    ];

请注意,对于 SixthSortedProperty,hasSubs 属性为真。该属性表示标题有子标题,将在 html 文件中用于更改 .

additionalUnsortedProperty 对象可以从数组中省略,但我将其包含在此处是为了向您指明如何继续动态生成子标题的方向。我提供的解决方案仍然静态指定子标题,因为我试图专注于解决方案的基本元素。额外的一点留给读者作为练习。 (我很懒?)

2) 接下来,我们需要更改在 component.html 文件中生成列的方式。我们将使用 *ngIf 为没有子标题的列提供一种格式,为有子标题的列提供另一种格式。

<ng-template pTemplate="header" let-columns>
  <tr [hidden]="loadOffersTable.isEmpty()">
    <th></th>
    <ng-container *ngFor="let col of columns">
      <ng-container *ngIf="col.hasSubs; else noSubs">
        <th colspan="2" [pSortableColumn]="col.field">
          {{col.header}}
          <p-sortIcon [field]="col.field" ariaLabel="Activate to sort" ariaLabelDesc="Activate to sort in descending order" ariaLabelAsc="Activate to sort in ascending order"></p-sortIcon>
        </th>
      </ng-container>
      <ng-template #noSubs>
        <th *ngIf="!col.isSub" rowspan="2" [pSortableColumn]="col.field">
          {{col.header}}
          <p-sortIcon [field]="col.field"></p-sortIcon>
        </th>
      </ng-template>
    </ng-container>
  </tr>
  <tr>
    <th></th>
    <th>Subheading 1</th>
    <th>Subheading 2</th>
  </tr>
</ng-template>

两列之间的格式差异主要取决于我们设置的 colspan 和 rowspan 属性。如果它有子标题,我们设置 colspan="2" 以便标题跨越两个子列。如果它没有子标题,我们设置 rowspan="2" 以便标题也填充子标题行(对于该列)。 (不幸的是,你不能通过在同一个 .

还要注意使用逻辑容器来处理条件设置之外的 *ngFor。您需要 *ngFor 才能遍历列,但如果 *ngFor 在标记内,则不能有条件地设置表头(就像在通常为动态列生成给出的示例中一样)。

3) 副标题代码实际上保持不变。如果您想修饰代码以便动态生成副标题,则可以这样做mutatis mutandis

现在所有内容都是动态生成的,它提供了以下选项:

  • 对列重新排序(尽管带子标题的列不容易重新排序)
  • 允许用户选择要从表中包含/排除的列
  • 调整列大小
  • 支持这个答案
  • 允许用户使用 CRUD 功能在表上添加自己的列

奖金!

您可能仍然认为您需要静态列,因为您的表格设计要求不同列中的数据以不同的格式或管道传输。 (如果您这么认为,那么您很有可能只是个新手,但我们都是这样开始的。)幸运的是,您已经设置好东西来解决 cols 数组的问题。将 [ngSwitch] 与 field 属性一起使用,以识别单元格中显示的是哪一列的数据,并相应地格式化单元格。您仍然需要遍历列,但现在 *ngFor 可以出现在标记中。逻辑容器现在将出现在单元格内部,并确定单元格内容的显示方式。这是你要做的事情的开始:

<ng-template pTemplate="body" let-nameForDataObject let-columns="columns">
  <tr>
    <td *ngFor="let col of columns">
      <ng-container [ngSwitch]="col.field">
        <ng-container *ngSwitchCase="'firstSortedProperty'">{{nameForDataObject.firstSortedProperty}}</ng-container>
        <ng-container *ngSwitchCase="'secondSortedProperty'">{{nameForDataObject.secondSortedProperty}}</ng-container>

...等等。 (使用 switch 语句来格式化表数据并不是一个聪明的技巧或新技巧,但对于 PrimeNG 新手来说,如何使其工作可能并不明显。)


我希望这些解决方案能帮助您快速正确地设置 PrimeNG 表。祝你好运!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-11
    • 2018-07-03
    • 1970-01-01
    • 2022-10-02
    相关资源
    最近更新 更多