https://habrahabr.ru/post/345096/
Всем привет! В целом,
документация данного компонента покрывает многие вопросы использования, но в процессе реальной разработки встречается много подводных камней. Хотел бы рассказать о них и как с ними боролся.
Читаемость кода
Пример из документации:
<mat-table #table [dataSource]="dataSource">
<ng-container matColumnDef="position">
...
</ng-container>
<ng-container matColumnDef="weight">
...
</ng-container>
...
</mat-table>
Скажу, это немного не соотвествует моему понятию читаемости. И будет совсем ужасно, если колонок в таблице больше 5. И здесь приходит на помощь *ngFor (material data table надстройка над cdk data table, поэтому динамические колонки возможны). Вот как это может выглядеть более читаемо:
<mat-table [dataSource]="data">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.key">
<mat-header-cell *matHeaderCellDef>{{ column.header }}</mat-header-cell>
<mat-cell *matCellDef="let row">{{ column.cell(row) }}</mat-cell>
</ng-container>
...
</mat-table>
columns = [
{key: 'position', header: 'Position', cell: (row: Row) => `${row.position}`},
{key: 'weight', header: 'Weight', cell: (row: Row) => `${row.weight}`},
...
];
Хочу еще заметить, что сортировка не работает с полем типа array. Поэтому пришлось хардкодить с добавлением числа к именам динамических полей.
Sticky заголовки
.mat-header-row {
position: sticky;
top: 0;
background: white;
z-index: 9999;
}
Такое нехитрое решение, и ваша header строка зависает при скроллинге.
Можно не ограничиваться ею и сделать статичную боковую панель для удобства при горизонтальной прокрутке данных (пример на картинке, как это работает). В нем использован атрибут [ngStyle] для каждой динамической клетки (у первых двух для каждой строки с подобными выше стилями).
При горизонтальном скроллинге также нарушается разделение строк (и для sticky частей обрывается задний фон). Атрибут flex здесь оказался отличным помощником.
Немного о фильтре
На странице таблицы есть важное замечание о фильтровании по умолчанию:
For example, the data object {id: 123, name: 'Mr. Smith', favoriteColor: 'blue'} will be reduced to 123mr. smithblue
Лично я считаю такой подход малоприемлемым, так как часто при фильтровании визуально возникает путаница (совпадений не наблюдается). Наиболее подходящий вариант был бы фильтровать раздельно по каждому видимому полю. Плюс лучше не вносить при таком подходе дополнительные невидимые поля (тоже внесут свою путаницу). Но разработчики предложили решение:
To override the default filtering behavior, a custom filterPredicate function can be set which takes a data object and filter string and returns true if the data object is considered a match.
filterPredicate: ((data: T, filter: string) => boolean)
Проблемы решена. Советую переопределять фильтрование по умолчанию.
Спасибо разработчикам Angular за такой могучий фреймворк и вам за внимание.