Skip to content

feat(table): add optional footer row #10330

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

Merged
merged 1 commit into from
Apr 23, 2018
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 45 additions & 6 deletions src/cdk/table/cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,17 @@

import {ContentChild, Directive, ElementRef, Input, TemplateRef} from '@angular/core';

/** Base interface for a cell definition. Captures a column's cell template definition. */
export interface CellDef {
template: TemplateRef<any>;
}

/**
* Cell definition for a CDK table.
* Captures the template of a column's data row cell as well as cell-specific properties.
*/
@Directive({selector: '[cdkCellDef]'})
export class CdkCellDef {
export class CdkCellDef implements CellDef {
constructor(/** @docs-private */ public template: TemplateRef<any>) { }
}

Expand All @@ -22,7 +27,16 @@ export class CdkCellDef {
* Captures the template of a column's header cell and as well as cell-specific properties.
*/
@Directive({selector: '[cdkHeaderCellDef]'})
export class CdkHeaderCellDef {
export class CdkHeaderCellDef implements CellDef {
constructor(/** @docs-private */ public template: TemplateRef<any>) { }
}

/**
* Footer cell definition for a CDK table.
* Captures the template of a column's footer cell and as well as cell-specific properties.
*/
@Directive({selector: '[cdkFooterCellDef]'})
export class CdkFooterCellDef implements CellDef {
constructor(/** @docs-private */ public template: TemplateRef<any>) { }
}

Expand Down Expand Up @@ -51,6 +65,9 @@ export class CdkColumnDef {
/** @docs-private */
@ContentChild(CdkHeaderCellDef) headerCell: CdkHeaderCellDef;

/** @docs-private */
@ContentChild(CdkFooterCellDef) footerCell: CdkFooterCellDef;

/**
* 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
Expand All @@ -59,6 +76,14 @@ export class CdkColumnDef {
cssClassFriendlyName: string;
}

/** Base class for the cells. Adds a CSS classname that identifies the column it renders in. */
export class BaseCdkCell {
constructor(columnDef: CdkColumnDef, elementRef: ElementRef) {
const columnClassName = `cdk-column-${columnDef.cssClassFriendlyName}`;
elementRef.nativeElement.classList.add(columnClassName);
}
}

/** Header cell template container that adds the right classes and role. */
@Directive({
selector: 'cdk-header-cell, th[cdk-header-cell]',
Expand All @@ -67,9 +92,23 @@ export class CdkColumnDef {
'role': 'columnheader',
},
})
export class CdkHeaderCell {
export class CdkHeaderCell extends BaseCdkCell {
constructor(columnDef: CdkColumnDef, elementRef: ElementRef) {
super(columnDef, elementRef);
}
}

/** Footer cell template container that adds the right classes and role. */
@Directive({
selector: 'cdk-footer-cell, td[cdk-footer-cell]',
host: {
'class': 'cdk-footer-cell',
'role': 'gridcell',
},
})
export class CdkFooterCell extends BaseCdkCell {
constructor(columnDef: CdkColumnDef, elementRef: ElementRef) {
elementRef.nativeElement.classList.add(`cdk-column-${columnDef.cssClassFriendlyName}`);
super(columnDef, elementRef);
}
}

Expand All @@ -81,8 +120,8 @@ export class CdkHeaderCell {
'role': 'gridcell',
},
})
export class CdkCell {
export class CdkCell extends BaseCdkCell {
constructor(columnDef: CdkColumnDef, elementRef: ElementRef) {
elementRef.nativeElement.classList.add(`cdk-column-${columnDef.cssClassFriendlyName}`);
super(columnDef, elementRef);
}
}
51 changes: 49 additions & 2 deletions src/cdk/table/row.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
ViewContainerRef,
ViewEncapsulation,
} from '@angular/core';
import {CdkCellDef} from './cell';
import {CdkCellDef, CdkColumnDef} from './cell';

/**
* The row template that can be used by the mat-table. Should not be used outside of the
Expand Down Expand Up @@ -57,6 +57,9 @@ export abstract class BaseRowDef {
getColumnsDiff(): IterableChanges<any> | null {
return this._columnsDiffer.diff(this.columns);
}

/** Gets this row def's relevant cell template from the provided column def. */
abstract extractCellTemplate(column: CdkColumnDef): TemplateRef<any>;
}

/**
Expand All @@ -71,6 +74,30 @@ export class CdkHeaderRowDef extends BaseRowDef {
constructor(template: TemplateRef<any>, _differs: IterableDiffers) {
super(template, _differs);
}

/** Gets this row def's relevant cell template from the provided column def. */
extractCellTemplate(column: CdkColumnDef): TemplateRef<any> {
return column.headerCell.template;
}
}

/**
* Footer row definition for the CDK table.
* Captures the footer row's template and other footer properties such as the columns to display.
*/
@Directive({
selector: '[cdkFooterRowDef]',
inputs: ['columns: cdkFooterRowDef'],
})
export class CdkFooterRowDef extends BaseRowDef {
constructor(template: TemplateRef<any>, _differs: IterableDiffers) {
super(template, _differs);
}

/** Gets this row def's relevant cell template from the provided column def. */
extractCellTemplate(column: CdkColumnDef): TemplateRef<any> {
return column.footerCell.template;
}
}

/**
Expand All @@ -96,12 +123,17 @@ export class CdkRowDef<T> extends BaseRowDef {
constructor(template: TemplateRef<any>, _differs: IterableDiffers) {
super(template, _differs);
}

/** Gets this row def's relevant cell template from the provided column def. */
extractCellTemplate(column: CdkColumnDef): TemplateRef<any> {
return column.cell.template;
}
}

/** Context provided to the row cells */
export interface CdkCellOutletRowContext<T> {
/** Data for the row that this cell is located within. */
$implicit: T;
$implicit?: T;

/** Index location of the row that this cell is located within. */
index?: number;
Expand Down Expand Up @@ -162,6 +194,21 @@ export class CdkCellOutlet {
})
export class CdkHeaderRow { }


/** Footer template container that contains the cell outlet. Adds the right class and role. */
@Component({
moduleId: module.id,
selector: 'cdk-footer-row, tr[cdk-footer-row]',
template: CDK_ROW_TEMPLATE,
host: {
'class': 'cdk-footer-row',
'role': 'row',
},
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
})
export class CdkFooterRow { }

/** Data row template container that contains the cell outlet. Adds the right class and role. */
@Component({
moduleId: module.id,
Expand Down
21 changes: 16 additions & 5 deletions src/cdk/table/table-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,35 @@

import {CommonModule} from '@angular/common';
import {NgModule} from '@angular/core';
import {CdkTable, HeaderRowPlaceholder, RowPlaceholder} from './table';
import {CdkCellOutlet, CdkHeaderRow, CdkHeaderRowDef, CdkRow, CdkRowDef} from './row';
import {CdkCell, CdkCellDef, CdkColumnDef, CdkHeaderCell, CdkHeaderCellDef} from './cell';
import {HeaderRowOutlet, DataRowOutlet, CdkTable, FooterRowOutlet} from './table';
import {
CdkCellOutlet, CdkFooterRow, CdkFooterRowDef, CdkHeaderRow, CdkHeaderRowDef, CdkRow,
CdkRowDef
} from './row';
import {
CdkColumnDef, CdkHeaderCellDef, CdkHeaderCell, CdkCell, CdkCellDef,
CdkFooterCellDef, CdkFooterCell
} from './cell';

const EXPORTED_DECLARATIONS = [
CdkTable,
CdkRowDef,
CdkCellDef,
CdkCellOutlet,
CdkHeaderCellDef,
CdkFooterCellDef,
CdkColumnDef,
CdkCell,
CdkRow,
CdkHeaderCell,
CdkFooterCell,
CdkHeaderRow,
CdkHeaderRowDef,
RowPlaceholder,
HeaderRowPlaceholder,
CdkFooterRow,
CdkFooterRowDef,
DataRowOutlet,
HeaderRowOutlet,
FooterRowOutlet,
];

@NgModule({
Expand Down
12 changes: 9 additions & 3 deletions src/cdk/table/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ top of the CDK data-table.

The first step to writing the data-table template is to define the columns.
A column definition is specified via an `<ng-container>` with the `cdkColumnDef` directive, giving
the column a name. Each column definition then further defines both a header-cell template
(`cdkHeaderCellDef`) and a data-cell template (`cdkCellDef`).
the column a name. Each column definition can contain a header-cell template
(`cdkHeaderCellDef`), data-cell template (`cdkCellDef`), and footer-cell
template (`cdkFooterCellDef`).

```html
<ng-container cdkColumnDef="username">
<th cdk-header-cell *cdkHeaderCellDef> User name </th>
<td cdk-cell *cdkCellDef="let row"> {{row.a}} </td>
<td cdk-footer-cell *cdkFooterCellDef> User name </td>
</ng-container>
```

Expand All @@ -35,11 +37,15 @@ Note that `cdkCellDef` exports the row context such that the row data can be ref
template. The directive also exports the same properties as `ngFor` (index, even, odd, first,
last).

The next step is to define the table's header-row (`cdkHeaderRowDef`) and data-row (`cdkRowDef`).
The next step is to define the table's header-row (`cdkHeaderRowDef`), data-row (`cdkRowDef`),
and fitler-row (`cdkFooterRowDef`). Note that each of these are optional to include, depending on
what type of rows you want rendered (e.g. if you do not need a footer row, simply do not add
its definition).

```html
<tr cdk-header-row *cdkHeaderRowDef="['username', 'age', 'title']"></tr>
<tr cdk-row *cdkRowDef="let row; columns: ['username', 'age', 'title']"></tr>
<tr cdk-footer-row *cdkFooterRowDef="['username', 'age', 'title']"></tr>
```

These row templates accept the specific columns to be rendered via the name given to the
Expand Down
Loading