@swimlane/ngx-datatable 11.1.4 → 11.2.0

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 (196) hide show
  1. package/.npmignore +6 -0
  2. package/README.md +2 -1
  3. package/config/deploy.js +2 -2
  4. package/config/karma.conf.js +5 -0
  5. package/config/webpack.package.js +4 -0
  6. package/package.json +15 -14
  7. package/release/components/body/body-cell.component.js.map +1 -1
  8. package/release/components/body/body-cell.component.metadata.json +1 -1
  9. package/release/components/body/body-group-header-template.directive.js.map +1 -1
  10. package/release/components/body/body-group-header-template.directive.metadata.json +1 -1
  11. package/release/components/body/body-group-header.directive.d.ts +4 -5
  12. package/release/components/body/body-group-header.directive.js +4 -5
  13. package/release/components/body/body-group-header.directive.js.map +1 -1
  14. package/release/components/body/body-group-header.directive.metadata.json +1 -1
  15. package/release/components/body/body-row-wrapper.component.js.map +1 -1
  16. package/release/components/body/body-row-wrapper.component.metadata.json +1 -1
  17. package/release/components/body/body-row.component.js +5 -1
  18. package/release/components/body/body-row.component.js.map +1 -1
  19. package/release/components/body/body-row.component.metadata.json +1 -1
  20. package/release/components/body/body.component.d.ts +2 -1
  21. package/release/components/body/body.component.js +31 -16
  22. package/release/components/body/body.component.js.map +1 -1
  23. package/release/components/body/body.component.metadata.json +1 -1
  24. package/release/components/body/index.js.map +1 -1
  25. package/release/components/body/index.metadata.json +1 -1
  26. package/release/components/body/progress-bar.component.js.map +1 -1
  27. package/release/components/body/progress-bar.component.metadata.json +1 -1
  28. package/release/components/body/scroller.component.d.ts +3 -2
  29. package/release/components/body/scroller.component.js +5 -3
  30. package/release/components/body/scroller.component.js.map +1 -1
  31. package/release/components/body/scroller.component.metadata.json +1 -1
  32. package/release/components/body/selection.component.js.map +1 -1
  33. package/release/components/body/selection.component.metadata.json +1 -1
  34. package/release/components/columns/column-cell.directive.js.map +1 -1
  35. package/release/components/columns/column-cell.directive.metadata.json +1 -1
  36. package/release/components/columns/column-header.directive.js.map +1 -1
  37. package/release/components/columns/column-header.directive.metadata.json +1 -1
  38. package/release/components/columns/column.directive.js.map +1 -1
  39. package/release/components/columns/column.directive.metadata.json +1 -1
  40. package/release/components/columns/index.js.map +1 -1
  41. package/release/components/columns/index.metadata.json +1 -1
  42. package/release/components/datatable.component.css +7 -2
  43. package/release/components/datatable.component.d.ts +8 -3
  44. package/release/components/datatable.component.js +29 -11
  45. package/release/components/datatable.component.js.map +1 -1
  46. package/release/components/datatable.component.metadata.json +1 -1
  47. package/release/components/footer/footer-template.directive.js.map +1 -1
  48. package/release/components/footer/footer-template.directive.metadata.json +1 -1
  49. package/release/components/footer/footer.component.js.map +1 -1
  50. package/release/components/footer/footer.component.metadata.json +1 -1
  51. package/release/components/footer/footer.directive.js.map +1 -1
  52. package/release/components/footer/footer.directive.metadata.json +1 -1
  53. package/release/components/footer/index.js.map +1 -1
  54. package/release/components/footer/index.metadata.json +1 -1
  55. package/release/components/footer/pager.component.js +1 -1
  56. package/release/components/footer/pager.component.js.map +1 -1
  57. package/release/components/footer/pager.component.metadata.json +1 -1
  58. package/release/components/header/header-cell.component.js +2 -1
  59. package/release/components/header/header-cell.component.js.map +1 -1
  60. package/release/components/header/header-cell.component.metadata.json +1 -1
  61. package/release/components/header/header.component.js +1 -0
  62. package/release/components/header/header.component.js.map +1 -1
  63. package/release/components/header/header.component.metadata.json +1 -1
  64. package/release/components/header/index.js.map +1 -1
  65. package/release/components/header/index.metadata.json +1 -1
  66. package/release/components/index.js.map +1 -1
  67. package/release/components/index.metadata.json +1 -1
  68. package/release/components/row-detail/index.js.map +1 -1
  69. package/release/components/row-detail/index.metadata.json +1 -1
  70. package/release/components/row-detail/row-detail-template.directive.js.map +1 -1
  71. package/release/components/row-detail/row-detail-template.directive.metadata.json +1 -1
  72. package/release/components/row-detail/row-detail.directive.js.map +1 -1
  73. package/release/components/row-detail/row-detail.directive.metadata.json +1 -1
  74. package/release/datatable.module.d.ts +0 -1
  75. package/release/datatable.module.js +2 -2
  76. package/release/datatable.module.js.map +1 -1
  77. package/release/datatable.module.metadata.json +1 -1
  78. package/release/directives/draggable.directive.js +3 -3
  79. package/release/directives/draggable.directive.js.map +1 -1
  80. package/release/directives/draggable.directive.metadata.json +1 -1
  81. package/release/directives/index.js.map +1 -1
  82. package/release/directives/index.metadata.json +1 -1
  83. package/release/directives/long-press.directive.js +3 -3
  84. package/release/directives/long-press.directive.js.map +1 -1
  85. package/release/directives/long-press.directive.metadata.json +1 -1
  86. package/release/directives/orderable.directive.js.map +1 -1
  87. package/release/directives/orderable.directive.metadata.json +1 -1
  88. package/release/directives/resizeable.directive.d.ts +3 -2
  89. package/release/directives/resizeable.directive.js +13 -8
  90. package/release/directives/resizeable.directive.js.map +1 -1
  91. package/release/directives/resizeable.directive.metadata.json +1 -1
  92. package/release/directives/visibility.directive.js.map +1 -1
  93. package/release/directives/visibility.directive.metadata.json +1 -1
  94. package/release/events.d.ts +1 -0
  95. package/release/events.js +1 -0
  96. package/release/events.js.map +1 -1
  97. package/release/events.metadata.json +1 -1
  98. package/release/index.css +8 -3
  99. package/release/index.d.ts +1 -0
  100. package/release/index.js +198 -14804
  101. package/release/index.js.map +1 -1
  102. package/release/index.metadata.json +1 -1
  103. package/release/index.min.js +1 -1
  104. package/release/index.min.js.map +1 -1
  105. package/release/services/dimensions-helper.service.d.ts +7 -0
  106. package/release/services/dimensions-helper.service.js +26 -0
  107. package/release/services/dimensions-helper.service.js.map +1 -0
  108. package/release/services/dimensions-helper.service.metadata.json +1 -0
  109. package/release/services/index.d.ts +1 -0
  110. package/release/services/index.js +1 -0
  111. package/release/services/index.js.map +1 -1
  112. package/release/services/index.metadata.json +1 -1
  113. package/release/services/scrollbar-helper.service.js.map +1 -1
  114. package/release/services/scrollbar-helper.service.metadata.json +1 -1
  115. package/release/types/click.type.js.map +1 -1
  116. package/release/types/click.type.metadata.json +1 -1
  117. package/release/types/column-mode.type.js.map +1 -1
  118. package/release/types/column-mode.type.metadata.json +1 -1
  119. package/release/types/contextmenu.type.js.map +1 -1
  120. package/release/types/contextmenu.type.metadata.json +1 -1
  121. package/release/types/index.js.map +1 -1
  122. package/release/types/index.metadata.json +1 -1
  123. package/release/types/selection.type.js.map +1 -1
  124. package/release/types/selection.type.metadata.json +1 -1
  125. package/release/types/sort-direction.type.js.map +1 -1
  126. package/release/types/sort-direction.type.metadata.json +1 -1
  127. package/release/types/sort-prop-dir.type.js.map +1 -1
  128. package/release/types/sort-prop-dir.type.metadata.json +1 -1
  129. package/release/types/sort.type.js.map +1 -1
  130. package/release/types/sort.type.metadata.json +1 -1
  131. package/release/types/table-column.type.js.map +1 -1
  132. package/release/types/table-column.type.metadata.json +1 -1
  133. package/release/utils/camel-case.js.map +1 -1
  134. package/release/utils/camel-case.metadata.json +1 -1
  135. package/release/utils/column-helper.js.map +1 -1
  136. package/release/utils/column-helper.metadata.json +1 -1
  137. package/release/utils/column-prop-getters.js.map +1 -1
  138. package/release/utils/column-prop-getters.metadata.json +1 -1
  139. package/release/utils/column.d.ts +0 -4
  140. package/release/utils/column.js +0 -10
  141. package/release/utils/column.js.map +1 -1
  142. package/release/utils/column.metadata.json +1 -1
  143. package/release/utils/elm-from-point.js.map +1 -1
  144. package/release/utils/elm-from-point.metadata.json +1 -1
  145. package/release/utils/id.js.map +1 -1
  146. package/release/utils/id.metadata.json +1 -1
  147. package/release/utils/index.js.map +1 -1
  148. package/release/utils/index.metadata.json +1 -1
  149. package/release/utils/keys.js.map +1 -1
  150. package/release/utils/keys.metadata.json +1 -1
  151. package/release/utils/math.js +1 -1
  152. package/release/utils/math.js.map +1 -1
  153. package/release/utils/math.metadata.json +1 -1
  154. package/release/utils/prefixes.js +4 -6
  155. package/release/utils/prefixes.js.map +1 -1
  156. package/release/utils/prefixes.metadata.json +1 -1
  157. package/release/utils/row-height-cache.js.map +1 -1
  158. package/release/utils/row-height-cache.metadata.json +1 -1
  159. package/release/utils/selection.js.map +1 -1
  160. package/release/utils/selection.metadata.json +1 -1
  161. package/release/utils/sort.d.ts +2 -1
  162. package/release/utils/sort.js +6 -2
  163. package/release/utils/sort.js.map +1 -1
  164. package/release/utils/sort.metadata.json +1 -1
  165. package/release/utils/throttle.js.map +1 -1
  166. package/release/utils/throttle.metadata.json +1 -1
  167. package/release/utils/translate.js.map +1 -1
  168. package/release/utils/translate.metadata.json +1 -1
  169. package/src/components/body/body-group-header.directive.ts +5 -6
  170. package/src/components/body/body-row.component.ts +5 -5
  171. package/src/components/body/body.component.ts +46 -36
  172. package/src/components/body/scroller.component.ts +7 -5
  173. package/src/components/body/selection.component.ts +1 -1
  174. package/src/components/datatable.component.scss +14 -1
  175. package/src/components/datatable.component.spec.ts +383 -220
  176. package/src/components/datatable.component.ts +26 -13
  177. package/src/components/footer/footer.component.spec.ts +329 -47
  178. package/src/components/footer/pager.component.ts +10 -0
  179. package/src/components/header/header-cell.component.ts +2 -1
  180. package/src/components/header/header.component.ts +1 -0
  181. package/src/datatable.module.ts +6 -3
  182. package/src/directives/draggable.directive.ts +3 -2
  183. package/src/directives/long-press.directive.ts +3 -3
  184. package/src/directives/resizeable.directive.ts +11 -7
  185. package/src/events.ts +1 -0
  186. package/src/index.ts +1 -0
  187. package/src/services/dimensions-helper.service.ts +14 -0
  188. package/src/services/index.ts +1 -0
  189. package/src/utils/column-prop-getters.spec.ts +44 -0
  190. package/src/utils/column.ts +0 -12
  191. package/src/utils/facade/browser.ts +26 -0
  192. package/src/utils/math.ts +1 -1
  193. package/src/utils/sort.ts +7 -3
  194. package/test/index.ts +1 -0
  195. package/test/jasmine-matchers.d.ts +12 -0
  196. package/test/jasmine-matchers.ts +70 -0
@@ -3,14 +3,14 @@ import {
3
3
  HostListener, ContentChildren, OnInit, QueryList, AfterViewInit,
4
4
  HostBinding, ContentChild, TemplateRef, IterableDiffer,
5
5
  DoCheck, KeyValueDiffers, KeyValueDiffer, ViewEncapsulation,
6
- ChangeDetectionStrategy, ChangeDetectorRef
6
+ ChangeDetectionStrategy, ChangeDetectorRef, SkipSelf
7
7
  } from '@angular/core';
8
8
 
9
9
  import {
10
10
  forceFillColumnWidths, adjustColumnWidths, sortRows,
11
11
  setColumnDefaults, throttleable, translateTemplates
12
12
  } from '../utils';
13
- import { ScrollbarHelper } from '../services';
13
+ import { ScrollbarHelper, DimensionsHelper } from '../services';
14
14
  import { ColumnMode, SortType, SelectionType, TableColumn, ContextmenuType } from '../types';
15
15
  import { DataTableBodyComponent } from './body';
16
16
  import { DatatableGroupHeaderDirective } from './body/body-group-header.directive';
@@ -55,6 +55,7 @@ import { BehaviorSubject } from 'rxjs/BehaviorSubject';
55
55
  [groupExpansionDefault]="groupExpansionDefault"
56
56
  [scrollbarV]="scrollbarV"
57
57
  [scrollbarH]="scrollbarH"
58
+ [virtualization]="virtualization"
58
59
  [loadingIndicator]="loadingIndicator"
59
60
  [externalPaging]="externalPaging"
60
61
  [rowHeight]="rowHeight"
@@ -114,11 +115,13 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
114
115
  @Input() set rows(val: any) {
115
116
  this._rows = val;
116
117
 
118
+ if (val) {
119
+ this._internalRows = [...val];
120
+ }
121
+
117
122
  // auto sort on new updates
118
123
  if (!this.externalSorting) {
119
- this._internalRows = sortRows(val, this._internalColumns, this.sorts);
120
- } else {
121
- this._internalRows = [...val];
124
+ this._internalRows = sortRows(this._internalRows, this._internalColumns, this.sorts);
122
125
  }
123
126
 
124
127
  // recalculate sizes/etc
@@ -304,7 +307,7 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
304
307
  *
305
308
  * - `single`
306
309
  * - `multi`
307
- * - `chkbox`
310
+ * - `checkbox`
308
311
  * - `multiClick`
309
312
  * - `cell`
310
313
  *
@@ -420,6 +423,11 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
420
423
  */
421
424
  @Input() selectAllRowsOnPage = false;
422
425
 
426
+ /**
427
+ * A flag for row virtualization on / off
428
+ */
429
+ @Input() virtualization: boolean = true;
430
+
423
431
  /**
424
432
  * Body was scrolled typically in a `scrollbarV:true` scenario.
425
433
  */
@@ -606,7 +614,7 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
606
614
  * Returns if all rows are selected.
607
615
  */
608
616
  get allRowsSelected(): boolean {
609
- let allRowsSelected = (this.selected.length === this.rows.length);
617
+ let allRowsSelected = (this.rows && this.selected && this.selected.length === this.rows.length);
610
618
 
611
619
  if (this.selectAllRowsOnPage) {
612
620
  const indexes = this.bodyComponent.indexes;
@@ -637,7 +645,8 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
637
645
  _columnTemplates: QueryList<DataTableColumnDirective>;
638
646
 
639
647
  constructor(
640
- private scrollbarHelper: ScrollbarHelper,
648
+ @SkipSelf() private scrollbarHelper: ScrollbarHelper,
649
+ @SkipSelf() private dimensionsHelper: DimensionsHelper,
641
650
  private cd: ChangeDetectorRef,
642
651
  element: ElementRef,
643
652
  differs: KeyValueDiffers) {
@@ -664,11 +673,15 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
664
673
  */
665
674
  ngAfterViewInit(): void {
666
675
  if (!this.externalSorting) {
667
- this._internalRows = sortRows(this._rows, this._internalColumns, this.sorts);
676
+ this._internalRows = sortRows(this._internalRows, this._internalColumns, this.sorts);
668
677
  }
669
678
 
670
679
  // this has to be done to prevent the change detection
671
680
  // tree from freaking out because we are readjusting
681
+ if (typeof requestAnimationFrame === 'undefined') {
682
+ return;
683
+ }
684
+
672
685
  requestAnimationFrame(() => {
673
686
  this.recalculate();
674
687
 
@@ -710,7 +723,7 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
710
723
 
711
724
  /**
712
725
  * Creates a map with the data grouped by the user choice of grouping index
713
- *
726
+ *
714
727
  * @param originalArray the original array passed via parameter
715
728
  * @param groupByIndex the index of the column to group the data by
716
729
  */
@@ -743,7 +756,7 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
743
756
  ngDoCheck(): void {
744
757
  if (this.rowDiffer.diff(this.rows)) {
745
758
  if (!this.externalSorting) {
746
- this._internalRows = sortRows(this._rows, this._internalColumns, this.sorts);
759
+ this._internalRows = sortRows(this._internalRows, this._internalColumns, this.sorts);
747
760
  } else {
748
761
  this._internalRows = [...this.rows];
749
762
  }
@@ -809,7 +822,7 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
809
822
  *
810
823
  */
811
824
  recalculateDims(): void {
812
- const dims = this.element.getBoundingClientRect();
825
+ const dims = this.dimensionsHelper.getDimensions(this.element);
813
826
  this._innerWidth = Math.floor(dims.width);
814
827
 
815
828
  if (this.scrollbarV) {
@@ -1005,7 +1018,7 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit {
1005
1018
  // the rows again on the 'push' detection...
1006
1019
  if (this.externalSorting === false) {
1007
1020
  // don't use normal setter so we don't resort
1008
- this._internalRows = sortRows(this.rows, this._internalColumns, sorts);
1021
+ this._internalRows = sortRows(this._internalRows, this._internalColumns, sorts);
1009
1022
  }
1010
1023
 
1011
1024
  this.sorts = sorts;
@@ -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
+ }
@@ -8,6 +8,8 @@ import {
8
8
  <ul class="pager">
9
9
  <li [class.disabled]="!canPrevious()">
10
10
  <a
11
+ role="button"
12
+ aria-label="go to first page"
11
13
  href="javascript:void(0)"
12
14
  (click)="selectPage(1)">
13
15
  <i class="{{pagerPreviousIcon}}"></i>
@@ -15,12 +17,16 @@ import {
15
17
  </li>
16
18
  <li [class.disabled]="!canPrevious()">
17
19
  <a
20
+ role="button"
21
+ aria-label="go to previous page"
18
22
  href="javascript:void(0)"
19
23
  (click)="prevPage()">
20
24
  <i class="{{pagerLeftArrowIcon}}"></i>
21
25
  </a>
22
26
  </li>
23
27
  <li
28
+ role="button"
29
+ [attr.aria-label]="'page ' + pg.number"
24
30
  class="pages"
25
31
  *ngFor="let pg of pages"
26
32
  [class.active]="pg.number === page">
@@ -32,6 +38,8 @@ import {
32
38
  </li>
33
39
  <li [class.disabled]="!canNext()">
34
40
  <a
41
+ role="button"
42
+ aria-label="go to next page"
35
43
  href="javascript:void(0)"
36
44
  (click)="nextPage()">
37
45
  <i class="{{pagerRightArrowIcon}}"></i>
@@ -39,6 +47,8 @@ import {
39
47
  </li>
40
48
  <li [class.disabled]="!canNext()">
41
49
  <a
50
+ role="button"
51
+ aria-label="go to last page"
42
52
  href="javascript:void(0)"
43
53
  (click)="selectPage(totalPages)">
44
54
  <i class="{{pagerNextIcon}}"></i>
@@ -9,7 +9,7 @@ import { MouseEvent } from '../../events';
9
9
  @Component({
10
10
  selector: 'datatable-header-cell',
11
11
  template: `
12
- <div>
12
+ <div class="datatable-header-cell-template-wrap">
13
13
  <label
14
14
  *ngIf="isCheckboxable"
15
15
  class="datatable-checkbox">
@@ -79,6 +79,7 @@ export class DataTableHeaderCellComponent {
79
79
  @Input() set sorts(val: any[]) {
80
80
  this._sorts = val;
81
81
  this.sortDir = this.calcSortDir(val);
82
+ this.cellContext.sortDir = this.sortDir;
82
83
  this.sortClass = this.calcSortClass(this.sortDir);
83
84
  this.cd.markForCheck();
84
85
  }
@@ -101,6 +101,7 @@ export class DataTableHeaderComponent {
101
101
  const colsByPin = columnsByPin(val);
102
102
  this._columnsByPin = columnsByPinArr(val);
103
103
  this._columnGroupWidths = columnGroupWidths(colsByPin, val);
104
+ this.setStylesByGroup();
104
105
  }
105
106
 
106
107
  get columns(): any[] {
@@ -1,6 +1,5 @@
1
1
  import { NgModule } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
- import 'rxjs/add/observable/fromEvent';
4
3
 
5
4
  import {
6
5
  DatatableComponent,
@@ -34,14 +33,18 @@ import {
34
33
  DraggableDirective
35
34
  } from './directives';
36
35
 
37
- import { ScrollbarHelper } from './services';
36
+ import {
37
+ ScrollbarHelper,
38
+ DimensionsHelper
39
+ } from './services';
38
40
 
39
41
  @NgModule({
40
42
  imports: [
41
43
  CommonModule
42
44
  ],
43
45
  providers: [
44
- ScrollbarHelper
46
+ ScrollbarHelper,
47
+ DimensionsHelper
45
48
  ],
46
49
  declarations: [
47
50
  DataTableFooterTemplateDirective,
@@ -5,6 +5,7 @@ import { Observable } from 'rxjs/Observable';
5
5
  import { Subscription } from 'rxjs/Subscription';
6
6
  import { takeUntil } from 'rxjs/operators';
7
7
  import { MouseEvent } from '../events';
8
+ import { fromEvent } from 'rxjs/observable/fromEvent';
8
9
 
9
10
  /**
10
11
  * Draggable Directive for Angular2
@@ -70,11 +71,11 @@ export class DraggableDirective implements OnDestroy, OnChanges {
70
71
 
71
72
  const mouseDownPos = { x: event.clientX, y: event.clientY };
72
73
 
73
- const mouseup = Observable.fromEvent(document, 'mouseup');
74
+ const mouseup = fromEvent(document, 'mouseup');
74
75
  this.subscription = mouseup
75
76
  .subscribe((ev: MouseEvent) => this.onMouseup(ev));
76
77
 
77
- const mouseMoveSub = Observable.fromEvent(document, 'mousemove')
78
+ const mouseMoveSub = fromEvent(document, 'mousemove')
78
79
  .pipe(takeUntil(mouseup))
79
80
  .subscribe((ev: MouseEvent) => this.move(ev, mouseDownPos));
80
81
 
@@ -5,7 +5,7 @@ import {
5
5
  import { Observable } from 'rxjs/Observable';
6
6
  import { Subscription } from 'rxjs/Subscription';
7
7
  import { takeUntil } from 'rxjs/operators';
8
-
8
+ import { fromEvent } from 'rxjs/observable/fromEvent';
9
9
  import { MouseEvent } from '../events';
10
10
 
11
11
  @Directive({ selector: '[long-press]' })
@@ -50,7 +50,7 @@ export class LongPressDirective implements OnDestroy {
50
50
  this.pressing = true;
51
51
  this.isLongPressing = false;
52
52
 
53
- const mouseup = Observable.fromEvent(document, 'mouseup');
53
+ const mouseup = fromEvent(document, 'mouseup');
54
54
  this.subscription = mouseup.subscribe((ev: MouseEvent) => this.onMouseup());
55
55
 
56
56
  this.timeout = setTimeout(() => {
@@ -61,7 +61,7 @@ export class LongPressDirective implements OnDestroy {
61
61
  });
62
62
 
63
63
  this.subscription.add(
64
- Observable.fromEvent(document, 'mousemove')
64
+ fromEvent(document, 'mousemove')
65
65
  .pipe(takeUntil(mouseup))
66
66
  .subscribe((mouseEvent: MouseEvent) => this.onMouseMove(mouseEvent))
67
67
  );