@swimlane/ngx-datatable 11.1.7 → 11.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/assets/app.css +5 -6
  2. package/config/deploy.js +2 -2
  3. package/config/karma.conf.js +5 -0
  4. package/config/webpack.dev.js +1 -1
  5. package/package.json +8 -7
  6. package/release/assets/app.css +5 -6
  7. package/release/components/body/body-group-header.directive.d.ts +4 -5
  8. package/release/components/body/body-group-header.directive.js +4 -5
  9. package/release/components/body/body-group-header.directive.js.map +1 -1
  10. package/release/components/body/body-row.component.js +3 -2
  11. package/release/components/body/body-row.component.js.map +1 -1
  12. package/release/components/body/body-row.component.metadata.json +1 -1
  13. package/release/components/body/body.component.d.ts +4 -1
  14. package/release/components/body/body.component.js +22 -7
  15. package/release/components/body/body.component.js.map +1 -1
  16. package/release/components/body/body.component.metadata.json +1 -1
  17. package/release/components/body/index.d.ts +1 -0
  18. package/release/components/body/index.js +1 -0
  19. package/release/components/body/index.js.map +1 -1
  20. package/release/components/body/index.metadata.json +1 -1
  21. package/release/components/body/summary/index.d.ts +1 -0
  22. package/release/components/body/summary/index.js +7 -0
  23. package/release/components/body/summary/index.js.map +1 -0
  24. package/release/components/body/summary/index.metadata.json +1 -0
  25. package/release/components/body/summary/summary-row.component.d.ts +19 -0
  26. package/release/components/body/summary/summary-row.component.js +85 -0
  27. package/release/components/body/summary/summary-row.component.js.map +1 -0
  28. package/release/components/body/summary/summary-row.component.metadata.json +1 -0
  29. package/release/components/columns/column.directive.d.ts +2 -0
  30. package/release/components/columns/column.directive.js +8 -0
  31. package/release/components/columns/column.directive.js.map +1 -1
  32. package/release/components/columns/column.directive.metadata.json +1 -1
  33. package/release/components/datatable.component.css +7 -2
  34. package/release/components/datatable.component.d.ts +14 -1
  35. package/release/components/datatable.component.js +34 -7
  36. package/release/components/datatable.component.js.map +1 -1
  37. package/release/components/datatable.component.metadata.json +1 -1
  38. package/release/components/footer/pager.component.js +1 -1
  39. package/release/components/footer/pager.component.js.map +1 -1
  40. package/release/components/footer/pager.component.metadata.json +1 -1
  41. package/release/components/header/header-cell.component.js +2 -1
  42. package/release/components/header/header-cell.component.js.map +1 -1
  43. package/release/components/header/header-cell.component.metadata.json +1 -1
  44. package/release/components/header/header.component.js +1 -0
  45. package/release/components/header/header.component.js.map +1 -1
  46. package/release/datatable.module.js +2 -1
  47. package/release/datatable.module.js.map +1 -1
  48. package/release/datatable.module.metadata.json +1 -1
  49. package/release/directives/resizeable.directive.js +5 -2
  50. package/release/directives/resizeable.directive.js.map +1 -1
  51. package/release/events.js +3 -3
  52. package/release/events.js.map +1 -1
  53. package/release/events.metadata.json +1 -1
  54. package/release/index.css +8 -3
  55. package/release/index.js +201 -42
  56. package/release/index.min.js +1 -1
  57. package/release/index.min.js.map +1 -1
  58. package/release/themes/bootstrap.css +2 -0
  59. package/release/themes/dark.css +6 -0
  60. package/release/themes/material.css +6 -0
  61. package/release/types/table-column.type.d.ts +14 -0
  62. package/release/utils/column-helper.js +6 -0
  63. package/release/utils/column-helper.js.map +1 -1
  64. package/release/utils/column.d.ts +0 -4
  65. package/release/utils/column.js +0 -10
  66. package/release/utils/column.js.map +1 -1
  67. package/release/utils/column.metadata.json +1 -1
  68. package/release/utils/math.js +1 -1
  69. package/release/utils/math.js.map +1 -1
  70. package/src/components/body/body-group-header.directive.ts +5 -6
  71. package/src/components/body/body-row.component.ts +8 -7
  72. package/src/components/body/body.component.spec.ts +8 -7
  73. package/src/components/body/body.component.ts +27 -6
  74. package/src/components/body/index.ts +1 -0
  75. package/src/components/body/summary/index.ts +1 -0
  76. package/src/components/body/summary/summary-row.component.spec.ts +131 -0
  77. package/src/components/body/summary/summary-row.component.ts +74 -0
  78. package/src/components/columns/column.directive.ts +4 -2
  79. package/src/components/datatable.component.scss +14 -1
  80. package/src/components/datatable.component.spec.ts +55 -7
  81. package/src/components/datatable.component.ts +31 -9
  82. package/src/components/footer/footer.component.spec.ts +329 -47
  83. package/src/components/footer/pager.component.ts +10 -0
  84. package/src/components/header/header-cell.component.ts +2 -1
  85. package/src/components/header/header.component.ts +1 -0
  86. package/src/datatable.module.ts +8 -6
  87. package/src/directives/resizeable.directive.ts +4 -2
  88. package/src/events.ts +3 -3
  89. package/src/themes/bootstrap.scss +10 -1
  90. package/src/themes/dark.scss +14 -0
  91. package/src/themes/material.scss +20 -5
  92. package/src/types/table-column.type.ts +43 -28
  93. package/src/utils/column-helper.ts +9 -1
  94. package/src/utils/column-prop-getters.spec.ts +44 -0
  95. package/src/utils/column.ts +0 -12
  96. package/src/utils/math.ts +1 -1
  97. package/test/index.ts +1 -0
  98. package/test/jasmine-matchers.d.ts +12 -0
  99. package/test/jasmine-matchers.ts +70 -0
  100. package/tslint.json +1 -1
@@ -24,13 +24,15 @@ export class DataTableColumnDirective {
24
24
  @Input() headerCheckboxable: boolean;
25
25
  @Input() headerClass: string | ((data: any) => string|any);
26
26
  @Input() cellClass: string | ((data: any) => string|any);
27
+ @Input() summaryFunc: (cells: any[]) => any;
28
+ @Input() summaryTemplate: TemplateRef<any>;
27
29
 
28
30
  @Input()
29
- @ContentChild(DataTableColumnCellDirective, { read: TemplateRef })
31
+ @ContentChild(DataTableColumnCellDirective, { read: TemplateRef })
30
32
  cellTemplate: TemplateRef<any>;
31
33
 
32
34
  @Input()
33
- @ContentChild(DataTableColumnHeaderDirective, { read: TemplateRef })
35
+ @ContentChild(DataTableColumnHeaderDirective, { read: TemplateRef })
34
36
  headerTemplate: TemplateRef<any>;
35
37
 
36
38
  }
@@ -156,7 +156,7 @@
156
156
  cursor: pointer;
157
157
  }
158
158
 
159
- .resize-handle{
159
+ .resize-handle, .resize-handle--not-resizable {
160
160
  display: inline-block;
161
161
  position: absolute;
162
162
  right: 0;
@@ -165,6 +165,9 @@
165
165
  width: 5px;
166
166
  padding: 0 4px;
167
167
  visibility: hidden;
168
+ }
169
+
170
+ .resize-handle {
168
171
  cursor: ew-resize;
169
172
  }
170
173
 
@@ -173,6 +176,16 @@
173
176
  visibility: visible;
174
177
  }
175
178
  }
179
+
180
+ &:hover {
181
+ .resize-handle--not-resizable {
182
+ visibility: visible;
183
+ }
184
+ }
185
+
186
+ .datatable-header-cell-template-wrap {
187
+ height: inherit;
188
+ }
176
189
  }
177
190
  }
178
191
 
@@ -10,11 +10,11 @@ import {
10
10
  } from '.';
11
11
  import { NgxDatatableModule } from '../datatable.module';
12
12
 
13
- let fixture: ComponentFixture<TestFixtureComponent>;
14
- let component: TestFixtureComponent;
13
+ let fixture: ComponentFixture<any>;
14
+ let component: any;
15
15
 
16
16
  describe('DatatableComponent', () => {
17
- beforeEach(async(setupTest));
17
+ beforeEach(async(() => setupTest(TestFixtureComponent)));
18
18
 
19
19
  it('should sort date values', () => {
20
20
  const initialRows = [
@@ -365,27 +365,75 @@ describe('DatatableComponent', () => {
365
365
  });
366
366
  });
367
367
 
368
+ describe('DatatableComponent With Custom Templates', () => {
369
+ beforeEach(async(() => setupTest(TestFixtureComponentWithCustomTemplates)));
370
+
371
+ it('should sort when the table is initially rendered if `sorts` are provided', () => {
372
+ const initialRows = [
373
+ { id: 5 },
374
+ { id: 20 },
375
+ { id: 12 }
376
+ ];
377
+
378
+ const sorts = [
379
+ {
380
+ prop: 'id',
381
+ dir: 'asc'
382
+ }
383
+ ];
384
+
385
+ component.rows = initialRows;
386
+ component.sorts = sorts;
387
+ fixture.detectChanges();
388
+
389
+ expect(textContent({ row: 1, column: 1 })).toContain('5', 'Ascending');
390
+ expect(textContent({ row: 2, column: 1 })).toContain('12', 'Ascending');
391
+ expect(textContent({ row: 3, column: 1 })).toContain('20', 'Ascending');
392
+ });
393
+ });
394
+
368
395
  @Component({
369
396
  template: `
370
397
  <ngx-datatable
371
398
  [columns]="columns"
372
- [rows]="rows">
399
+ [rows]="rows"
400
+ [sorts]="sorts">
373
401
  </ngx-datatable>
374
402
  `
375
403
  })
376
404
  class TestFixtureComponent {
377
405
  columns: any[] = [];
378
406
  rows: any[] = [];
407
+ sorts: any[] = [];
408
+ }
409
+
410
+ @Component({
411
+ template: `
412
+ <ngx-datatable [rows]="rows" [sorts]="sorts">
413
+ <ngx-datatable-column name="Id" prop="id">
414
+ <ng-template let-column="column" ngx-datatable-header-template>
415
+ {{ column.name }}
416
+ </ng-template>
417
+ <ng-template let-row="row" ngx-datatable-cell-template>
418
+ {{ row.id }}
419
+ </ng-template>
420
+ </ngx-datatable-column>
421
+ </ngx-datatable>
422
+ `
423
+ })
424
+ class TestFixtureComponentWithCustomTemplates {
425
+ rows: any[] = [];
426
+ sorts: any[] = [];
379
427
  }
380
428
 
381
- function setupTest() {
429
+ function setupTest(componentClass) {
382
430
  return TestBed.configureTestingModule({
383
- declarations: [ TestFixtureComponent ],
431
+ declarations: [ componentClass ],
384
432
  imports: [ NgxDatatableModule ]
385
433
  })
386
434
  .compileComponents()
387
435
  .then(() => {
388
- fixture = TestBed.createComponent(TestFixtureComponent);
436
+ fixture = TestBed.createComponent(componentClass);
389
437
  component = fixture.componentInstance;
390
438
  });
391
439
  }
@@ -76,6 +76,9 @@ import { BehaviorSubject } from 'rxjs/BehaviorSubject';
76
76
  [rowClass]="rowClass"
77
77
  [selectCheck]="selectCheck"
78
78
  [displayCheck]="displayCheck"
79
+ [summaryRow]="summaryRow"
80
+ [summaryHeight]="summaryHeight"
81
+ [summaryPosition]="summaryPosition"
79
82
  (page)="onBodyPage($event)"
80
83
  (activate)="activate.emit($event)"
81
84
  (rowContextmenu)="onRowContextmenu($event)"
@@ -118,10 +121,10 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
118
121
  if (val) {
119
122
  this._internalRows = [...val];
120
123
  }
121
-
124
+
122
125
  // auto sort on new updates
123
126
  if (!this.externalSorting) {
124
- this._internalRows = sortRows(this._internalRows, this._internalColumns, this.sorts);
127
+ this.sortInternalRows();
125
128
  }
126
129
 
127
130
  // recalculate sizes/etc
@@ -307,7 +310,7 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
307
310
  *
308
311
  * - `single`
309
312
  * - `multi`
310
- * - `chkbox`
313
+ * - `checkbox`
311
314
  * - `multiClick`
312
315
  * - `cell`
313
316
  *
@@ -428,6 +431,21 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
428
431
  */
429
432
  @Input() virtualization: boolean = true;
430
433
 
434
+ /**
435
+ * A flag for switching summary row on / off
436
+ */
437
+ @Input() summaryRow: boolean = false;
438
+
439
+ /**
440
+ * A height of summary row
441
+ */
442
+ @Input() summaryHeight: number = this.rowHeight;
443
+
444
+ /**
445
+ * A property holds a summary row position: top/bottom
446
+ */
447
+ @Input() summaryPosition: string = 'top';
448
+
431
449
  /**
432
450
  * Body was scrolled typically in a `scrollbarV:true` scenario.
433
451
  */
@@ -673,7 +691,7 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
673
691
  */
674
692
  ngAfterViewInit(): void {
675
693
  if (!this.externalSorting) {
676
- this._internalRows = sortRows(this._internalRows, this._internalColumns, this.sorts);
694
+ this.sortInternalRows();
677
695
  }
678
696
 
679
697
  // this has to be done to prevent the change detection
@@ -681,7 +699,7 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
681
699
  if (typeof requestAnimationFrame === 'undefined') {
682
700
  return;
683
701
  }
684
-
702
+
685
703
  requestAnimationFrame(() => {
686
704
  this.recalculate();
687
705
 
@@ -716,6 +734,7 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
716
734
  this._internalColumns = translateTemplates(arr);
717
735
  setColumnDefaults(this._internalColumns);
718
736
  this.recalculateColumns();
737
+ this.sortInternalRows();
719
738
  this.cd.markForCheck();
720
739
  }
721
740
  }
@@ -756,7 +775,7 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
756
775
  ngDoCheck(): void {
757
776
  if (this.rowDiffer.diff(this.rows)) {
758
777
  if (!this.externalSorting) {
759
- this._internalRows = sortRows(this._internalRows, this._internalColumns, this.sorts);
778
+ this.sortInternalRows();
760
779
  } else {
761
780
  this._internalRows = [...this.rows];
762
781
  }
@@ -1012,16 +1031,15 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
1012
1031
  });
1013
1032
  }
1014
1033
 
1015
- const { sorts } = event;
1034
+ this.sorts = event.sorts;
1016
1035
 
1017
1036
  // this could be optimized better since it will resort
1018
1037
  // the rows again on the 'push' detection...
1019
1038
  if (this.externalSorting === false) {
1020
1039
  // don't use normal setter so we don't resort
1021
- this._internalRows = sortRows(this._internalRows, this._internalColumns, sorts);
1040
+ this.sortInternalRows();
1022
1041
  }
1023
1042
 
1024
- this.sorts = sorts;
1025
1043
  // Always go to first page when sorting to see the newly sorted data
1026
1044
  this.offset = 0;
1027
1045
  this.bodyComponent.updateOffsetY(this.offset);
@@ -1068,4 +1086,8 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
1068
1086
  onBodySelect(event: any): void {
1069
1087
  this.select.emit(event);
1070
1088
  }
1089
+
1090
+ private sortInternalRows(): void {
1091
+ this._internalRows = sortRows(this._internalRows, this._internalColumns, this.sorts);
1092
+ }
1071
1093
  }
@@ -1,76 +1,358 @@
1
1
  import {
2
- async,
3
- TestBed
4
- } from '@angular/core/testing';
2
+ Component,
3
+ DebugElement,
4
+ Input,
5
+ Output,
6
+ EventEmitter,
7
+ ViewChild,
8
+ TemplateRef
9
+ } from '@angular/core';
10
+ import { async, TestBed, ComponentFixture } from '@angular/core/testing';
11
+ import { By } from '@angular/platform-browser';
5
12
 
6
- import {
7
- DataTableFooterComponent,
8
- DataTablePagerComponent
9
- } from '.';
10
- import {By} from "@angular/platform-browser";
13
+ import { DataTableFooterComponent, DataTablePagerComponent } from '.';
14
+ import { addMatchers } from '../../../test';
15
+
16
+ let fixture: ComponentFixture<TestFixtureComponent>;
17
+ let component: TestFixtureComponent;
18
+ let page: Page;
11
19
 
12
20
  describe('DataTableFooterComponent', () => {
13
- let fixture: any;
14
- let component: DataTableFooterComponent;
15
- let element;
16
-
17
- // provide our implementations or mocks to the dependency injector
18
- beforeEach(() => {
19
- TestBed.configureTestingModule({
20
- declarations: [
21
- DataTableFooterComponent,
22
- DataTablePagerComponent
23
- ]
21
+ beforeAll(addMatchers);
22
+
23
+ beforeEach(async(setupTest));
24
+
25
+ describe('div.datatable-footer-inner', () => {
26
+ it(`should have a height`, () => {
27
+ component.footerHeight = 123;
28
+ page.detectChangesAndRunQueries();
29
+
30
+ expect(page.datatableFooterInner.nativeElement.style.height).toEqual(
31
+ '123px'
32
+ );
24
33
  });
25
- });
26
34
 
27
- beforeEach(async(() => {
28
- TestBed.compileComponents().then(() => {
29
- fixture = TestBed.createComponent(DataTableFooterComponent);
30
- component = fixture.componentInstance;
31
- element = fixture.nativeElement;
35
+ it('should have `.selected-count` class when selectedMessage is set', () => {
36
+ component.selectedMessage = 'selected';
37
+ component.selectedCount = 1;
38
+ page.detectChangesAndRunQueries();
39
+
40
+ expect(page.datatableFooterInner.nativeElement).toHaveCssClass(
41
+ 'selected-count'
42
+ );
32
43
  });
33
- }));
34
44
 
35
- describe('fixture', () => {
36
- it('component is created', () => {
37
- expect(component).toBeTruthy();
45
+ it('should not have `.selected-count` class if selectedMessage is not set', () => {
46
+ component.selectedMessage = undefined;
47
+ page.detectChangesAndRunQueries();
48
+
49
+ expect(page.datatableFooterInner.nativeElement).not.toHaveCssClass(
50
+ 'selected-count'
51
+ );
38
52
  });
39
53
  });
40
54
 
41
- describe('when the component has a selectionMessage set', () => {
55
+ describe('when there is no template', () => {
56
+ it('should not render a template', () => {
57
+ component.footerTemplate = undefined;
58
+ page.detectChangesAndRunQueries();
42
59
 
43
- beforeEach(() => {
44
- // setup for the template
45
- component.rowCount = 9;
60
+ expect(page.templateList).toBeNull();
61
+ });
46
62
 
63
+ it('should display the selected count and total if selectedMessage set', () => {
64
+ component.footerTemplate = undefined;
47
65
  component.selectedMessage = 'selected';
48
- component.selectedCount = 3;
66
+ component.selectedCount = 7;
67
+ component.rowCount = 10;
68
+ component.totalMessage = 'total';
69
+ page.detectChangesAndRunQueries();
70
+
71
+ expect(page.pageCount.nativeElement.innerText).toEqual(
72
+ '7 selected / 10 total'
73
+ );
74
+ });
75
+
76
+ it('should display only the total if selectedMessage is not set', () => {
77
+ component.footerTemplate = undefined;
78
+ component.selectedMessage = undefined;
79
+ component.rowCount = 100;
80
+ component.totalMessage = 'total';
81
+ page.detectChangesAndRunQueries();
82
+
83
+ expect(page.pageCount.nativeElement.innerText).toEqual('100 total');
84
+ });
85
+
86
+ it('should render a DataTablePagerComponent', () => {
87
+ component.footerTemplate = undefined;
88
+ page.detectChangesAndRunQueries();
89
+
90
+ expect(page.datatablePager).not.toBeNull();
91
+ });
92
+
93
+ it('should propagate page change events upward from the DataTablePagerComponent', () => {
94
+ component.footerTemplate = undefined;
95
+ page.detectChangesAndRunQueries();
96
+ const spy = spyOn(component, 'onPageEvent');
97
+ const pageChangeEvent = { page: 7 };
98
+ const datatablePagerComponent: DataTablePagerComponent =
99
+ page.datatablePager.componentInstance;
100
+ // mimic the act of changing the page through the datatable pager
101
+ datatablePagerComponent.change.emit(pageChangeEvent);
102
+
103
+ expect(spy).toHaveBeenCalledWith(pageChangeEvent);
104
+ });
105
+
106
+ it('should bind to DataTablePagerComponent pagerLeftArrowIcon input', () => {
107
+ component.pagerLeftArrowIcon = 'pager-left-arrow-icon';
108
+ page.detectChangesAndRunQueries();
109
+ const datatablePagerComponent: DataTablePagerComponent =
110
+ page.datatablePager.componentInstance;
111
+
112
+ expect(datatablePagerComponent.pagerLeftArrowIcon).toBe(
113
+ component.pagerLeftArrowIcon
114
+ );
115
+ });
116
+
117
+ it('should bind to DataTablePagerComponent pagerRightArrowIcon input', () => {
118
+ component.pagerRightArrowIcon = 'pager-right-arrow-icon';
119
+ page.detectChangesAndRunQueries();
120
+ const datatablePagerComponent: DataTablePagerComponent =
121
+ page.datatablePager.componentInstance;
122
+
123
+ expect(datatablePagerComponent.pagerRightArrowIcon).toBe(
124
+ component.pagerRightArrowIcon
125
+ );
126
+ });
127
+
128
+ it('should bind to DataTablePagerComponent pagerNextIcon input', () => {
129
+ component.pagerNextIcon = 'pager-next-icon';
130
+ page.detectChangesAndRunQueries();
131
+ const datatablePagerComponent: DataTablePagerComponent =
132
+ page.datatablePager.componentInstance;
49
133
 
50
- fixture.detectChanges();
134
+ expect(datatablePagerComponent.pagerNextIcon).toBe(
135
+ component.pagerNextIcon
136
+ );
51
137
  });
52
138
 
53
- it('then the selectionCount is shown', () => {
54
- let selectedElement = fixture.debugElement.query(By.css('.page-count>span'));
139
+ it('should bind to DataTablePagerComponent pagerPreviousIcon input', () => {
140
+ component.pagerPreviousIcon = 'pager-previous-icon';
141
+ page.detectChangesAndRunQueries();
142
+ const datatablePagerComponent: DataTablePagerComponent =
143
+ page.datatablePager.componentInstance;
55
144
 
56
- expect(selectedElement.nativeElement.innerHTML.trim()).toBe('3 selected /');
145
+ expect(datatablePagerComponent.pagerPreviousIcon).toBe(
146
+ component.pagerPreviousIcon
147
+ );
148
+ });
149
+
150
+ it('should bind to DataTablePagerComponent size input', () => {
151
+ component.pageSize = 4;
152
+ page.detectChangesAndRunQueries();
153
+ const datatablePagerComponent: DataTablePagerComponent =
154
+ page.datatablePager.componentInstance;
155
+
156
+ expect(datatablePagerComponent.size).toBe(component.pageSize);
157
+ });
158
+
159
+ it('should bind to DataTablePagerComponent count input', () => {
160
+ component.rowCount = 40;
161
+ page.detectChangesAndRunQueries();
162
+ const datatablePagerComponent: DataTablePagerComponent =
163
+ page.datatablePager.componentInstance;
164
+
165
+ expect(datatablePagerComponent.count).toBe(component.rowCount);
166
+ });
167
+
168
+ it('should bind to DataTablePagerComponent page input', () => {
169
+ component.offset = 200;
170
+ page.detectChangesAndRunQueries();
171
+ const datatablePagerComponent: DataTablePagerComponent =
172
+ page.datatablePager.componentInstance;
173
+
174
+ expect(datatablePagerComponent.page).toBe(201);
175
+ });
176
+
177
+ it('should show & hide the DataTablePagerComponent', () => {
178
+ component.rowCount = 200;
179
+ component.pageSize = 5;
180
+ page.detectChangesAndRunQueries();
181
+
182
+ expect(page.datatablePager.nativeElement.hidden).toBe(
183
+ false,
184
+ 'DataTablePagerComponent should be hidden'
185
+ );
186
+
187
+ component.rowCount = 1;
188
+ component.pageSize = 2;
189
+ page.detectChangesAndRunQueries();
190
+
191
+ expect(page.datatablePager.nativeElement.hidden).toBe(
192
+ true,
193
+ 'DataTablePagerComponent should not be hidden'
194
+ );
57
195
  });
58
196
  });
59
197
 
60
- describe('when the component does not have a selectionMessage set', () => {
198
+ describe('when there is a template', () => {
199
+ it('should not render div.page-count or DatatablePagerComponent', () => {
200
+ component.footerTemplate = { template: component.testTemplate };
201
+ page.detectChangesAndRunQueries();
61
202
 
62
- beforeEach(() => {
63
- // setup for the template
64
- component.rowCount = 9;
65
- component.selectedCount = 3;
203
+ expect(page.pageCount).toBeNull();
204
+ expect(page.datatablePager).toBeNull();
205
+ });
206
+
207
+ it('should render the template', () => {
208
+ page.detectChangesAndRunQueries();
209
+ component.footerTemplate = { template: component.testTemplate };
210
+ page.detectChangesAndRunQueries();
66
211
 
67
- fixture.detectChanges();
212
+ expect(page.templateList).not.toBeNull();
68
213
  });
69
214
 
70
- it('then the selectionCount is shown', () => {
71
- let selectedElement = fixture.debugElement.query(By.css('.page-count>span'));
215
+ it('should give the template proper context', () => {
216
+ component.footerTemplate = { template: component.testTemplate };
217
+ component.rowCount = 12;
218
+ component.pageSize = 1;
219
+ component.selectedCount = 4;
220
+ component.offset = 0;
221
+ page.detectChangesAndRunQueries();
222
+ const listItems = page.templateList.queryAll(By.css('li'));
72
223
 
73
- expect(selectedElement).toBeNull();
224
+ expect(listItems[0].nativeElement).toHaveText('rowCount 12');
225
+ expect(listItems[1].nativeElement).toHaveText('pageSize 1');
226
+ expect(listItems[2].nativeElement).toHaveText('selectedCount 4');
227
+ expect(listItems[3].nativeElement).toHaveText('curPage 1');
228
+ expect(listItems[4].nativeElement).toHaveText('offset 0');
74
229
  });
75
230
  });
76
231
  });
232
+
233
+ /**
234
+ * we test DatatableFooterComponent by embedding it in a
235
+ * test host component
236
+ */
237
+ @Component({
238
+ template: `
239
+ <datatable-footer
240
+ [rowCount]="rowCount"
241
+ [pageSize]="pageSize"
242
+ [offset]="offset"
243
+ [footerHeight]="footerHeight"
244
+ [footerTemplate]="footerTemplate"
245
+ [totalMessage]="totalMessage"
246
+ [pagerLeftArrowIcon]="pagerLeftArrowIcon"
247
+ [pagerRightArrowIcon]="pagerRightArrowIcon"
248
+ [pagerPreviousIcon]="pagerPreviousIcon"
249
+ [selectedCount]="selectedCount"
250
+ [selectedMessage]="selectedMessage"
251
+ [pagerNextIcon]="pagerNextIcon"
252
+ (page)="onPageEvent($event)">
253
+ </datatable-footer>
254
+
255
+ <ng-template
256
+ #testTemplate
257
+ let-rowCount="rowCount"
258
+ let-pageSize="pageSize"
259
+ let-selectedCount="selectedCount"
260
+ let-curPage="curPage"
261
+ let-offset="offset">
262
+ <ul id="template-list">
263
+ <li>rowCount {{rowCount}}</li>
264
+ <li>pageSize {{pageSize}}</li>
265
+ <li>selectedCount {{selectedCount}}</li>
266
+ <li>curPage {{curPage}}</li>
267
+ <li>offset {{offset}}</li>
268
+ </ul>
269
+ </ng-template>
270
+ `
271
+ })
272
+ class TestFixtureComponent {
273
+ footerHeight: number;
274
+ rowCount: number = 100;
275
+ pageSize = 1;
276
+ offset = 0;
277
+ pagerLeftArrowIcon: string;
278
+ pagerRightArrowIcon: string;
279
+ pagerPreviousIcon: string;
280
+ pagerNextIcon: string;
281
+ totalMessage: string;
282
+ footerTemplate: { template: TemplateRef<any> };
283
+ selectedCount: number;
284
+ selectedMessage: string;
285
+
286
+ /**
287
+ * establishes a reference to a test template that can
288
+ * selectively be passed to the DatatableFooterComponent
289
+ * in these unit tests
290
+ */
291
+ @ViewChild('testTemplate', { read: TemplateRef })
292
+ testTemplate: TemplateRef<any>;
293
+
294
+ onPageEvent() {
295
+ return;
296
+ }
297
+ }
298
+
299
+ /**
300
+ * we use a mock DataTablePagerComponent when testing
301
+ * the DataTableFooterComponent
302
+ */
303
+ @Component({
304
+ selector: 'datatable-pager',
305
+ template: ''
306
+ })
307
+ class DataTablePagerComponentMock {
308
+ @Input() pagerLeftArrowIcon: string;
309
+ @Input() pagerRightArrowIcon: string;
310
+ @Input() pagerPreviousIcon: string;
311
+ @Input() pagerNextIcon: string;
312
+ @Input() page: number;
313
+ @Input() size: number;
314
+ @Input() count: number;
315
+
316
+ @Output() change: EventEmitter<any> = new EventEmitter();
317
+ }
318
+
319
+ function setupTest() {
320
+ return TestBed.configureTestingModule({
321
+ declarations: [
322
+ TestFixtureComponent,
323
+ DataTableFooterComponent,
324
+ DataTablePagerComponentMock
325
+ ]
326
+ })
327
+ .compileComponents()
328
+ .then(() => {
329
+ fixture = TestBed.createComponent(TestFixtureComponent);
330
+ component = fixture.componentInstance;
331
+ page = new Page();
332
+ page.detectChangesAndRunQueries();
333
+ });
334
+ }
335
+
336
+ /**
337
+ * a Page is a collection of references to DebugElements. it
338
+ * makes for cleaner testing
339
+ */
340
+ class Page {
341
+ datatableFooter: DebugElement;
342
+ datatableFooterInner: DebugElement;
343
+ templateList: DebugElement;
344
+ pageCount: DebugElement;
345
+ datatablePager: DebugElement;
346
+
347
+ detectChangesAndRunQueries() {
348
+ fixture.detectChanges();
349
+
350
+ const de = fixture.debugElement;
351
+
352
+ this.datatableFooter = de.query(By.css('datatable-footer'));
353
+ this.datatableFooterInner = de.query(By.css('.datatable-footer-inner'));
354
+ this.templateList = de.query(By.css('#template-list'));
355
+ this.pageCount = de.query(By.css('.page-count'));
356
+ this.datatablePager = de.query(By.css('datatable-pager'));
357
+ }
358
+ }