我正在尝试查看是否可以动态定义 mat-table 的列,包括列的宽度和对齐方式。
我可以使它与 ngStyle 一起工作,如果我使用管道,则不会经常调用代码:
<ng-container *ngFor="let column of columns" matColumnDef="{{column.columnDef}}">
<th mat-header-cell *matHeaderCellDef mat-sort-header >
{{column.header}}
</th>
<td mat-cell *matCellDef="let row" [ngStyle]="column | styleRow">
{{column.cell(row)}}
</td>
</ng-container>
这styleRow
是一个管道,它转换列定义列表中的一行并为该列返回正确的 css 规则;例如
transform(column: ColumnConfig): object {
const obj = {
textAlign: column.textAlign,
width: column.type === 'number' ?
column.length + 'ch' :
(column.length * 0.45) + 'rem'
};
console.log(column, obj);
return obj;
}
问题是,根据我的口味,它仍然经常被称为方式,当我所需要的只是将以下规则放入组件的样式表中时:
.mat-column-foo {
width: 7em;
}
.mat-column-bar {
width: 15em;
}
.mat-column-baz {
width: 7em;
text-align: right;
}
// ... and so on.
...但我不知道该怎么做。在以下示例中,我希望 setStyles 函数为:
将 css 规则添加到我在 test.component.css 中找到规则的相同样式标记中
使用规则创建一个新的样式标签,但我必须找到组件的 _ngcontent_xxxxxx 属性,这样我才能创建看起来像的规则
.mat-column-foo[_ngcontent_xxxxxx] {...}
export interface TblData {
foo: string;
bar: string;
baz: number;
}
export interface ColumnConfig {
columnDef: string;
header: string;
textAlign: string;
length: number;
type: string;
cell: any;
}
const ELEMENT_DATA: TblData[] = [ .... ];
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TestComponent implements OnInit {
columns: ColumnConfig[] = [
{ columnDef: 'foo',
header: 'Foo',
textAlign: 'left',
length: 10,
type: 'date',
cell: (element: any) => `${element.foo}`
},
{ columnDef: 'bar',
header: 'Bar',
textAlign: 'left',
length: 50,
type: 'string',
cell: (element: any) => `${element.bar}`
},
{ columnDef: 'baz',
header: 'Baz',
textAlign: 'right',
length: 7,
type: 'number',
cell: (element: any) => `${element.baz}`
}
];
displayedColumns = ['select', ...this.columns.map(c => c.columnDef)];
dataSource = new MatTableDataSource<TblData>(ELEMENT_DATA);
selection = new SelectionModel<TblData>(true, []);
@ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;
@ViewChild(MatSort, {static: true}) sort: MatSort;
constructor() {
}
ngOnInit() {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
// setStyles(columns); <-- how do I implement this function ?
}
.....
示例的完整来源:
html:
<div>
<div class="mat-elevation-z8">
<div class="table_scroll">
<div class="table_intro">
<p>
Some text above the table.
</p>
<p>
And more text.
</p>
</div>
<table mat-table [dataSource]="dataSource" matSort>
<!-- Checkbox Column -->
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox (change)="$event ? masterToggle() : null"
[checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()"
[aria-label]="checkboxLabel()">
</mat-checkbox>
</th>
<td mat-cell *matCellDef="let row">
<mat-checkbox (click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)"
[aria-label]="checkboxLabel(row)">
</mat-checkbox>
</td>
</ng-container>
<!-- Dynamic Columns -->
<ng-container *ngFor="let column of columns; trackBy: columnId" matColumnDef="{{column.columnDef}}">
<th mat-header-cell *matHeaderCellDef mat-sort-header>
{{column.header}}
</th>
<td mat-cell *matCellDef="let row" [ngStyle]="column | styleRow">
{{column.cell(row) | formatRow:column}}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-toolbar>
<mat-toolbar-row>
<mat-icon title="Export as CSV">table_chart</mat-icon>
<mat-icon title="Export as PDF">print</mat-icon>
<span class="example-spacer"></span>
<mat-paginator class="paginator" [pageSizeOptions]="[50, 100, 200]"></mat-paginator>
</mat-toolbar-row>
</mat-toolbar>
</div>
</div>
TS:
import {ChangeDetectionStrategy, Component, Input, OnInit, ViewChild} from '@angular/core';
import {MatTableDataSource} from '@angular/material/table';
import {SelectionModel} from '@angular/cdk/collections';
import {MatPaginator} from '@angular/material/paginator';
import {MatSort} from '@angular/material/sort';
/**
* Column definition.
* columnDef is the key name in the row record
* header is the text displayed in the column's header
* textAlign and length are for styling the columns
* type is for future use
* cell is a function to get that cell's value from the row.
*/
export interface ColumnConfig {
columnDef: string;
header: string;
textAlign: string;
length: number;
type: string;
cell: any;
}
/**
* Displayed rows must have a selection label property.
*/
export interface MrmTableRow {
selection_label: string;
}
@Component({
selector: 'app-mrm-table',
templateUrl: './mrm-table.component.html',
styleUrls: ['./mrm-table.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MrmTableComponent<T extends MrmTableRow> implements OnInit {
@Input() columns: ColumnConfig[];
@Input() data: T[];
selection = new SelectionModel<T>(true, []);
@ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;
@ViewChild(MatSort, {static: true}) sort: MatSort;
public dataSource: MatTableDataSource<T>;
public displayedColumns: string[];
constructor() {
}
ngOnInit() {
this.dataSource = new MatTableDataSource<T>(this.data);
this.displayedColumns = ['select', ...this.columns.map(c => c.columnDef)];
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
// setStyles(data);
}
/**
* returns true if all rows are selected
*/
isAllSelected() {
const numSelected = this.selection.selected.length;
const numRows = this.dataSource.data.length;
return numSelected === numRows;
}
/**
* Selects all rows if they are not all selected; otherwise clear selection.
*/
masterToggle() {
this.isAllSelected() ?
this.selection.clear() :
this.dataSource.data.forEach(row => this.selection.select(row));
}
/** The aria label (accessibility) for the checkbox on the passed row */
checkboxLabel(row?: T): string {
if (!row) {
return `${this.isAllSelected() ? 'select' : 'deselect'} all`;
}
return `${this.selection.isSelected(row) ?
'deselect' :
'select'} row ${row.selection_label} `;
}
/**
* This for the trackBy in the column loop.
*/
columnId(index: number, item: ColumnConfig): string {
return item.columnDef;
}
}
SCSS:
.padded {
padding: 15px;
background-color: #fafafa;
}
.example-spacer {
flex: 1 1 auto;
}
:host > div {
padding: 10px;
& > div {
.mat-toolbar {
background-color: transparent;
}
width: 48em;
.table_intro {
padding: 25px;
}
div.table_scroll {
height: 600px;
overflow: auto;
}
}
}
styleRow 管道供参考,但我想要一个不需要它的解决方案。
import {Pipe, PipeTransform} from '@angular/core';
import {ColumnConfig} from './mrm-table/mrm-table.component';
@Pipe({
name: 'styleRow'
})
export class StyleRowPipe implements PipeTransform {
transform(column: ColumnConfig): object {
const obj = {
textAlign: column.textAlign,
width: column.type === 'number' ?
column.length + 'ch' :
(column.length * 0.55) + 'rem'
};
console.log('styleRow', column, obj);
return obj;
}
}