@@ -69,11 +69,11 @@ describe('CdkTable', () => {
6969 } ) ;
7070
7171 it ( 'with a rendered header with the right number of header cells' , ( ) => {
72- const header = getHeaderRow ( tableElement ) ;
72+ const header = getHeaderRows ( tableElement ) [ 0 ] ;
7373
7474 expect ( header ) . toBeTruthy ( ) ;
7575 expect ( header . classList ) . toContain ( 'customHeaderRowClass' ) ;
76- expect ( getHeaderCells ( tableElement ) . length ) . toBe ( component . columnsToRender . length ) ;
76+ expect ( getHeaderCells ( header ) . length ) . toBe ( component . columnsToRender . length ) ;
7777 } ) ;
7878
7979 it ( 'with rendered rows with right number of row cells' , ( ) => {
@@ -87,7 +87,8 @@ describe('CdkTable', () => {
8787 } ) ;
8888
8989 it ( 'with column class names provided to header and data row cells' , ( ) => {
90- getHeaderCells ( tableElement ) . forEach ( ( headerCell , index ) => {
90+ const header = getHeaderRows ( tableElement ) [ 0 ] ;
91+ getHeaderCells ( header ) . forEach ( ( headerCell , index ) => {
9192 expect ( headerCell . classList ) . toContain ( `cdk-column-${ component . columnsToRender [ index ] } ` ) ;
9293 } ) ;
9394
@@ -101,8 +102,9 @@ describe('CdkTable', () => {
101102 it ( 'with the right accessibility roles' , ( ) => {
102103 expect ( tableElement . getAttribute ( 'role' ) ) . toBe ( 'grid' ) ;
103104
104- expect ( getHeaderRow ( tableElement ) . getAttribute ( 'role' ) ) . toBe ( 'row' ) ;
105- getHeaderCells ( tableElement ) . forEach ( cell => {
105+ expect ( getHeaderRows ( tableElement ) [ 0 ] . getAttribute ( 'role' ) ) . toBe ( 'row' ) ;
106+ const header = getHeaderRows ( tableElement ) [ 0 ] ;
107+ getHeaderCells ( header ) . forEach ( cell => {
106108 expect ( cell . getAttribute ( 'role' ) ) . toBe ( 'columnheader' ) ;
107109 } ) ;
108110
@@ -279,6 +281,40 @@ describe('CdkTable', () => {
279281 expect ( getRows ( tableElement ) . length ) . toBe ( 0 ) ;
280282 } ) ) ;
281283
284+ it ( 'should be able to render multiple header and footer rows' , ( ) => {
285+ setupTableTestApp ( MultipleHeaderFooterRowsCdkTableApp ) ;
286+ fixture . detectChanges ( ) ;
287+
288+ expectTableToMatchContent ( tableElement , [
289+ [ 'first-header' ] ,
290+ [ 'second-header' ] ,
291+ [ 'first-footer' ] ,
292+ [ 'second-footer' ] ,
293+ ] ) ;
294+ } ) ;
295+
296+ it ( 'should be able to render and change multiple header and footer rows' , ( ) => {
297+ setupTableTestApp ( MultipleHeaderFooterRowsCdkTableApp ) ;
298+ fixture . detectChanges ( ) ;
299+
300+ expectTableToMatchContent ( tableElement , [
301+ [ 'first-header' ] ,
302+ [ 'second-header' ] ,
303+ [ 'first-footer' ] ,
304+ [ 'second-footer' ] ,
305+ ] ) ;
306+
307+ component . showAlternativeHeadersAndFooters = true ;
308+ fixture . detectChanges ( ) ;
309+
310+ expectTableToMatchContent ( tableElement , [
311+ [ 'first-header' ] ,
312+ [ 'second-header' ] ,
313+ [ 'first-footer' ] ,
314+ [ 'second-footer' ] ,
315+ ] ) ;
316+ } ) ;
317+
282318 describe ( 'with different data inputs other than data source' , ( ) => {
283319 let baseData : TestData [ ] = [
284320 { a : 'a_1' , b : 'b_1' , c : 'c_1' } ,
@@ -460,7 +496,8 @@ describe('CdkTable', () => {
460496 it ( 'should be able to apply class-friendly css class names for the column cells' , ( ) => {
461497 setupTableTestApp ( CrazyColumnNameCdkTableApp ) ;
462498 // Column was named 'crazy-column-NAME-1!@#$%^-_&*()2'
463- expect ( getHeaderCells ( tableElement ) [ 0 ] . classList )
499+ const header = getHeaderRows ( tableElement ) [ 0 ] ;
500+ expect ( getHeaderCells ( header ) [ 0 ] . classList )
464501 . toContain ( 'cdk-column-crazy-column-NAME-1-------_----2' ) ;
465502 } ) ;
466503
@@ -488,7 +525,7 @@ describe('CdkTable', () => {
488525 setupTableTestApp ( UndefinedColumnsCdkTableApp ) ;
489526
490527 // Header should be empty since there are no columns to display.
491- const headerRow = getHeaderRow ( tableElement ) ;
528+ const headerRow = getHeaderRows ( tableElement ) [ 0 ] ;
492529 expect ( headerRow . textContent ) . toBe ( '' ) ;
493530
494531 // Rows should be empty since there are no columns to display.
@@ -657,6 +694,8 @@ describe('CdkTable', () => {
657694 } ) ;
658695 } ) ;
659696
697+
698+
660699 describe ( 'with trackBy' , ( ) => {
661700 function createTestComponentWithTrackyByTable ( trackByStrategy ) {
662701 fixture = createComponent ( TrackByCdkTableApp ) ;
@@ -1053,6 +1092,62 @@ class NullDataCdkTableApp {
10531092 dataSource = observableOf ( null ) ;
10541093}
10551094
1095+
1096+ @Component ( {
1097+ template : `
1098+ <cdk-table [dataSource]="[]">
1099+ <ng-container cdkColumnDef="first-header">
1100+ <th cdk-header-cell *cdkHeaderCellDef> first-header </th>
1101+ </ng-container>
1102+
1103+ <ng-container cdkColumnDef="second-header">
1104+ <th cdk-header-cell *cdkHeaderCellDef> second-header </th>
1105+ </ng-container>
1106+
1107+ <ng-container cdkColumnDef="first-footer">
1108+ <td cdk-footer-cell *cdkFooterCellDef> first-footer </td>
1109+ </ng-container>
1110+
1111+ <ng-container cdkColumnDef="second-footer">
1112+ <td cdk-footer-cell *cdkFooterCellDef> second-footer </td>
1113+ </ng-container>
1114+
1115+ <ng-container *ngIf="!showAlternativeHeadersAndFooters">
1116+ <tr cdk-header-row *cdkHeaderRowDef="['first-header']"></tr>
1117+ <tr cdk-header-row *cdkHeaderRowDef="['second-header']"></tr>
1118+ <tr cdk-footer-row *cdkFooterRowDef="['first-footer']"></tr>
1119+ <tr cdk-footer-row *cdkFooterRowDef="['second-footer']"></tr>
1120+ </ng-container>
1121+
1122+ <ng-container cdkColumnDef="alt-first-header">
1123+ <th cdk-header-cell *cdkHeaderCellDef> alt-first-header </th>
1124+ </ng-container>
1125+
1126+ <ng-container cdkColumnDef="alt-second-header">
1127+ <th cdk-header-cell *cdkHeaderCellDef> alt-second-header </th>
1128+ </ng-container>
1129+
1130+ <ng-container cdkColumnDef="alt-first-footer">
1131+ <td cdk-footer-cell *cdkFooterCellDef> alt-first-footer </td>
1132+ </ng-container>
1133+
1134+ <ng-container cdkColumnDef="alt-second-footer">
1135+ <td cdk-footer-cell *cdkFooterCellDef> alt-second-footer </td>
1136+ </ng-container>
1137+
1138+ <ng-container *ngIf="showAlternativeHeadersAndFooters">
1139+ <tr cdk-header-row *cdkHeaderRowDef="['alt-first-header']"></tr>
1140+ <tr cdk-header-row *cdkHeaderRowDef="['alt-second-header']"></tr>
1141+ <tr cdk-footer-row *cdkFooterRowDef="['alt-first-footer']"></tr>
1142+ <tr cdk-footer-row *cdkFooterRowDef="['alt-second-footer']"></tr>
1143+ </ng-container>
1144+ </cdk-table>
1145+ `
1146+ } )
1147+ class MultipleHeaderFooterRowsCdkTableApp {
1148+ showAlternativeHeadersAndFooters = false ;
1149+ }
1150+
10561151@Component ( {
10571152 template : `
10581153 <cdk-table [dataSource]="dataSource" [multiTemplateDataRows]="multiTemplateDataRows">
@@ -1586,42 +1681,62 @@ function getElements(element: Element, query: string): Element[] {
15861681 return [ ] . slice . call ( element . querySelectorAll ( query ) ) ;
15871682}
15881683
1589- function getHeaderRow ( tableElement : Element ) : Element {
1590- return tableElement . querySelector ( '.cdk-header-row' ) ! ;
1684+ function getHeaderRows ( tableElement : Element ) : Element [ ] {
1685+ return [ ] . slice . call ( tableElement . querySelectorAll ( '.cdk-header-row' ) ) ! ;
15911686}
15921687
1593- function getFooterRow ( tableElement : Element ) : Element {
1594- return tableElement . querySelector ( '.cdk-footer-row' ) ! ;
1688+ function getFooterRows ( tableElement : Element ) : Element [ ] {
1689+ return [ ] . slice . call ( tableElement . querySelectorAll ( '.cdk-footer-row' ) ) ! ;
15951690}
15961691
15971692function getRows ( tableElement : Element ) : Element [ ] {
15981693 return getElements ( tableElement , '.cdk-row' ) ;
15991694}
1695+
16001696function getCells ( row : Element ) : Element [ ] {
1601- return row ? getElements ( row , '.cdk-cell' ) : [ ] ;
1697+ if ( ! row ) {
1698+ return [ ] ;
1699+ }
1700+
1701+ let cells = getElements ( row , 'cdk-cell' ) ;
1702+ if ( ! cells . length ) {
1703+ cells = getElements ( row , 'td' ) ;
1704+ }
1705+
1706+ return cells ;
16021707}
16031708
1604- function getHeaderCells ( tableElement : Element ) : Element [ ] {
1605- return getElements ( getHeaderRow ( tableElement ) , '.cdk-header-cell' ) ;
1709+ function getHeaderCells ( headerRow : Element ) : Element [ ] {
1710+ let cells = getElements ( headerRow , 'cdk-header-cell' ) ;
1711+ if ( ! cells . length ) {
1712+ cells = getElements ( headerRow , 'th' ) ;
1713+ }
1714+
1715+ return cells ;
16061716}
16071717
1608- function getFooterCells ( tableElement : Element ) : Element [ ] {
1609- return getElements ( getFooterRow ( tableElement ) , '.cdk-footer-cell' ) ;
1718+ function getFooterCells ( footerRow : Element ) : Element [ ] {
1719+ let cells = getElements ( footerRow , 'cdk-footer-cell' ) ;
1720+ if ( ! cells . length ) {
1721+ cells = getElements ( footerRow , 'td' ) ;
1722+ }
1723+
1724+ return cells ;
16101725}
16111726
16121727function getActualTableContent ( tableElement : Element ) : string [ ] [ ] {
16131728 let actualTableContent : Element [ ] [ ] = [ ] ;
1614- if ( getHeaderRow ( tableElement ) ) {
1615- actualTableContent . push ( getHeaderCells ( tableElement ) ) ;
1616- }
1729+ getHeaderRows ( tableElement ) . forEach ( row => {
1730+ actualTableContent . push ( getHeaderCells ( row ) ) ;
1731+ } ) ;
16171732
16181733 // Check data row cells
16191734 const rows = getRows ( tableElement ) . map ( row => getCells ( row ) ) ;
16201735 actualTableContent = actualTableContent . concat ( rows ) ;
16211736
1622- if ( getFooterRow ( tableElement ) ) {
1623- actualTableContent . push ( getFooterCells ( tableElement ) ) ;
1624- }
1737+ getFooterRows ( tableElement ) . forEach ( row => {
1738+ actualTableContent . push ( getFooterCells ( row ) ) ;
1739+ } ) ;
16251740
16261741 // Convert the nodes into their text content;
16271742 return actualTableContent . map ( row => row . map ( cell => cell . textContent ! . trim ( ) ) ) ;
0 commit comments