Таблица PrimeNG с сгруппированными столбцами не сортируется - PullRequest
0 голосов
/ 26 октября 2018

Таблицы 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" в открывающем теге работает точно так, как и ожидалось, поэтому это не кажетсябыть проблема с источником данных.

Если вы видите мою ошибку, пожалуйста, укажите на это!Я с удовольствием отвечу на уточняющие вопросы, если есть что-то, что я упустил из описания проблемы.Я также открыт для предложений об альтернативных способах реализации необходимой функциональности.

1 Ответ

0 голосов
/ 08 ноября 2018

Итак, у моего первоначального вопроса есть [по крайней мере] два решения.Первый быстрый, но имеет запах кода.Второй - более сложный, но, вероятно, будет правильным способом решения поставленной мною задачи.


ПЕРВОЕ РЕШЕНИЕ

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-таблицы.

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

Объяснение: Предоставляя p-таблице значение для свойства столбцов, становятся доступными имена полей, найденные в каждом столбце.Свойство столбцы предполагается, что содержит массив, из которого столбцы будут генерироваться динамически, но вы этого не делаете.(Tricksy!) Это работает в данный момент, хотя пока неизвестно, что будущие изменения в 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},
    ];

Примечаниечто свойство hasSubs верно для sixthSortedProperty.Это свойство указывает, что заголовок имеет подзаголовки и будет использоваться в 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", чтобы заголовок также заполнял строку подзаголовка (для этого столбца).(К сожалению, вы не можете попробовать что-то сверхъестественное, используя одновременно и rowspan, и colspan. Это должен быть один или другой.)

Также обратите внимание на использование логических контейнеров для обработки* ng Для вне условной установки.Вам нужен * ngFor для итерации по столбцам, но вы не можете установить заголовки таблицы условно, если * ngFor находится внутри тега (как в примерах, которые обычно приводятся для динамической генерации столбцов).

3) Код подзаголовка фактически останется прежним.Если вы хотите привести код в порядок, чтобы подзаголовки также генерировались динамически, это можно сделать mutatis mutandis .

Теперь, когда все сгенерировано динамически, это открывает возможности для таких вещей, как:

  • Изменение порядка столбцов (хотя столбец с подзаголовками нельзя легко переставить)
  • Разрешение пользователю выбирать, какие столбцы включать / исключать из таблицы
  • Изменение размера столбцов
  • Повышение рейтинга этого ответа
  • Разрешение пользователю добавлять собственные столбцы с функцией CRUD в таблицу

БОНУС!

Вы все еще можете подумать, что вам нужны статические столбцы, потому что дизайн вашей таблицы требует, чтобы данные в разных столбцах форматировались или передавались по-разному.(Это хороший шанс, что вы новичок, если вы так думаете, но мы все начинаем с этого.) К счастью, вы уже настроили все, чтобы решить эту проблему с массивом cols.Используйте [ngSwitch] со свойством поля, чтобы определить, какие данные столбца отображаются в ячейке, и соответствующим образом отформатируйте ячейку.Вам все еще нужно перебирать столбцы, но теперь вполне нормально, чтобы * 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 может не быть очевидным, как заставить его работать.)


IНадеемся, что эти решения помогут вам быстро и правильно настроить стол PrimeNG.Удачи!

...