Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(table): column class names should be css friendly #6173

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions guides/cdk-table.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,17 @@ Event and property bindings can be added directly to the row element.
</cdk-row>
```

##### Styling columns

Each header and row cell will be provided a CSS class that includes its column. For example,
cells that are displayed in the column `name` will be given the class `cdk-column-name`. This allows
columns to be given styles that will match across the header and rows.

Since columns can be given any string for its name, its possible that it cannot be directly applied
to the CSS class (e.g. `*nameColumn!`). In these cases, the special characters will be replaced by
the `-` character. For example, cells container in a column named `*nameColumn!` will be given
the class `cdk-column--nameColumn-`.

#### Connecting the table to a data source

Data is provided to the table through a `DataSource`. When the table receives a data source,
Expand Down
19 changes: 16 additions & 3 deletions src/cdk/table/cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,26 @@ export class CdkHeaderCellDef {
@Directive({selector: '[cdkColumnDef]'})
export class CdkColumnDef {
/** Unique name for this column. */
@Input('cdkColumnDef') name: string;
@Input('cdkColumnDef')
get name(): string { return this._name; }
set name(name: string) {
this._name = name;
this.cssClassFriendlyName = name.replace(/[^a-z0-9_-]/ig, '-');
}
_name: string;

/** @docs-private */
@ContentChild(CdkCellDef) cell: CdkCellDef;

/** @docs-private */
@ContentChild(CdkHeaderCellDef) headerCell: CdkHeaderCellDef;

/**
* Transformed version of the column name that can be used as part of a CSS classname. Excludes
* all non-alphanumeric characters and the special characters '-' and '_'. Any characters that
* do not match are replaced by the '-' character.
*/
cssClassFriendlyName: string;
}

/** Header cell template container that adds the right classes and role. */
Expand All @@ -52,7 +65,7 @@ export class CdkColumnDef {
})
export class CdkHeaderCell {
constructor(columnDef: CdkColumnDef, elementRef: ElementRef, renderer: Renderer2) {
renderer.addClass(elementRef.nativeElement, `cdk-column-${columnDef.name}`);
renderer.addClass(elementRef.nativeElement, `cdk-column-${columnDef.cssClassFriendlyName}`);
}
}

Expand All @@ -66,6 +79,6 @@ export class CdkHeaderCell {
})
export class CdkCell {
constructor(columnDef: CdkColumnDef, elementRef: ElementRef, renderer: Renderer2) {
renderer.addClass(elementRef.nativeElement, `cdk-column-${columnDef.name}`);
renderer.addClass(elementRef.nativeElement, `cdk-column-${columnDef.cssClassFriendlyName}`);
}
}
32 changes: 32 additions & 0 deletions src/cdk/table/table.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ describe('CdkTable', () => {
RowContextCdkTableApp,
DuplicateColumnDefNameCdkTableApp,
MissingColumnDefCdkTableApp,
CrazyColumnNameCdkTableApp,
],
}).compileComponents();
}));
Expand Down Expand Up @@ -97,6 +98,17 @@ describe('CdkTable', () => {
});
});

it('should be able to apply class-friendly css class names for the column cells', () => {
const crazyColumnNameAppFixture = TestBed.createComponent(CrazyColumnNameCdkTableApp);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comment here like

// Test component has a column named "crazy-column-NAME-1!@#$%^-_&*()2"

const crazyColumnNameTableElement =
crazyColumnNameAppFixture.nativeElement.querySelector('cdk-table');
crazyColumnNameAppFixture.detectChanges();

// Column was named 'crazy-column-NAME-1!@#$%^-_&*()2'
expect(getHeaderCells(crazyColumnNameTableElement)[0].classList)
.toContain('cdk-column-crazy-column-NAME-1-------_----2');
});

it('should disconnect the data source when table is destroyed', () => {
expect(dataSource.isConnected).toBe(true);

Expand Down Expand Up @@ -682,6 +694,26 @@ class CustomRoleCdkTableApp {
@ViewChild(CdkTable) table: CdkTable<TestData>;
}

@Component({
template: `
<cdk-table [dataSource]="dataSource">
<ng-container [cdkColumnDef]="columnsToRender[0]">
<cdk-header-cell *cdkHeaderCellDef> Column A</cdk-header-cell>
<cdk-cell *cdkCellDef="let row"> {{row.a}}</cdk-cell>
</ng-container>

<cdk-header-row *cdkHeaderRowDef="columnsToRender"></cdk-header-row>
<cdk-row *cdkRowDef="let row; columns: columnsToRender"></cdk-row>
</cdk-table>
`
})
class CrazyColumnNameCdkTableApp {
dataSource: FakeDataSource = new FakeDataSource();
columnsToRender = ['crazy-column-NAME-1!@#$%^-_&*()2'];

@ViewChild(CdkTable) table: CdkTable<TestData>;
}

@Component({
template: `
<cdk-table [dataSource]="dataSource">
Expand Down
4 changes: 2 additions & 2 deletions src/lib/table/cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export class MdHeaderCell extends _MdHeaderCell {
elementRef: ElementRef,
renderer: Renderer2) {
super(columnDef, elementRef, renderer);
renderer.addClass(elementRef.nativeElement, `mat-column-${columnDef.name}`);
renderer.addClass(elementRef.nativeElement, `mat-column-${columnDef.cssClassFriendlyName}`);
}
}

Expand All @@ -85,6 +85,6 @@ export class MdCell extends _MdCell {
elementRef: ElementRef,
renderer: Renderer2) {
super(columnDef, elementRef, renderer);
renderer.addClass(elementRef.nativeElement, `mat-column-${columnDef.name}`);
renderer.addClass(elementRef.nativeElement, `mat-column-${columnDef.cssClassFriendlyName}`);
}
}