@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
@@ -1,253 +1,416 @@
1
- import {TestBed, async} from '@angular/core/testing';
2
- import {DatatableComponent} from './datatable.component';
3
- import {NgxDatatableModule} from '../datatable.module';
4
- describe('Datatable component', () => {
5
-
6
- beforeEach(() => {
7
- TestBed.configureTestingModule({
8
- imports: [NgxDatatableModule]
9
- });
1
+ import { Component, DebugElement } from '@angular/core';
2
+ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
3
+ import { By } from '@angular/platform-browser';
4
+
5
+ import {
6
+ DatatableComponent,
7
+ DataTableHeaderCellComponent,
8
+ DataTableBodyRowComponent,
9
+ DataTableBodyCellComponent
10
+ } from '.';
11
+ import { NgxDatatableModule } from '../datatable.module';
12
+
13
+ let fixture: ComponentFixture<TestFixtureComponent>;
14
+ let component: TestFixtureComponent;
15
+
16
+ describe('DatatableComponent', () => {
17
+ beforeEach(async(setupTest));
18
+
19
+ it('should sort date values', () => {
20
+ const initialRows = [
21
+ { birthDate: new Date(1980, 11, 1) },
22
+ { birthDate: new Date(1978, 8, 5) },
23
+ { birthDate: new Date(1995, 4, 3) }
24
+ ];
25
+
26
+ const columns = [
27
+ {
28
+ prop: 'birthDate'
29
+ }
30
+ ];
31
+
32
+ component.rows = initialRows;
33
+ component.columns = columns;
34
+ fixture.detectChanges();
35
+
36
+ // sort by `birthDate` ascending
37
+ sortBy({ column: 1 });
38
+ fixture.detectChanges();
39
+
40
+ expect(textContent({ row: 1, column: 1 })).toContain('1978', 'Ascending');
41
+ expect(textContent({ row: 2, column: 1 })).toContain('1980', 'Ascending');
42
+ expect(textContent({ row: 3, column: 1 })).toContain('1995', 'Ascending');
43
+
44
+ // sort by `birthDate` descending
45
+ sortBy({ column: 1 });
46
+ fixture.detectChanges();
47
+
48
+ expect(textContent({ row: 1, column: 1 })).toContain('1995', 'Descending');
49
+ expect(textContent({ row: 2, column: 1 })).toContain('1980', 'Descending');
50
+ expect(textContent({ row: 3, column: 1 })).toContain('1978', 'Descending');
10
51
  });
11
52
 
12
- beforeEach(async(() => {
13
- TestBed.compileComponents();
14
- }));
15
-
16
- describe('When the column is sorted', () => {
17
- it('should sort a column with Date values', () => {
18
- const fixture = TestBed.createComponent(DatatableComponent);
19
- const initialRows = [
20
- {birthDate: new Date(1980, 12, 1)},
21
- {birthDate: new Date(1978, 8, 5)},
22
- {birthDate: new Date(1995, 4, 3)}
23
- ];
24
-
25
- const columns = [
26
- {
27
- prop: 'birthDate'
28
- }
29
- ];
30
-
31
- fixture.componentInstance.rows = initialRows;
32
- fixture.componentInstance.columns = columns;
33
-
34
- fixture.detectChanges();
35
-
36
- fixture.componentInstance.onColumnSort({
37
- sorts: [{prop: 'birthDate', dir: 'desc'}]
38
- });
39
-
40
- expect(fixture.componentInstance._internalRows[0]).toBe(initialRows[2]);
41
- expect(fixture.componentInstance._internalRows[1]).toBe(initialRows[0]);
42
- expect(fixture.componentInstance._internalRows[2]).toBe(initialRows[1]);
43
- });
44
-
45
- it('should sort a column with number values', () => {
46
- const fixture = TestBed.createComponent(DatatableComponent);
47
- const initialRows = [
48
- {id: 5},
49
- {id: 20},
50
- {id: 12}
51
- ];
52
-
53
- const columns = [
54
- {
55
- prop: 'id'
56
- }
57
- ];
58
-
59
- fixture.componentInstance.rows = initialRows;
60
- fixture.componentInstance.columns = columns;
61
-
62
- fixture.detectChanges();
63
-
64
- fixture.componentInstance.onColumnSort({
65
- sorts: [{prop: 'id', dir: 'desc'}]
66
- });
67
-
68
- expect(fixture.componentInstance._internalRows[0]).toBe(initialRows[1]);
69
- expect(fixture.componentInstance._internalRows[1]).toBe(initialRows[2]);
70
- expect(fixture.componentInstance._internalRows[2]).toBe(initialRows[0]);
71
- });
72
-
73
- it('should sort a column with string values', () => {
74
- const fixture = TestBed.createComponent(DatatableComponent);
75
- const initialRows = [
76
- {product: 'Computers'},
77
- {product: 'Bikes'},
78
- {product: 'Smartphones'}
79
- ];
80
-
81
- const columns = [
82
- {
83
- prop: 'product'
84
- }
85
- ];
86
-
87
- fixture.componentInstance.rows = initialRows;
88
- fixture.componentInstance.columns = columns;
89
-
90
- fixture.detectChanges();
91
-
92
- fixture.componentInstance.onColumnSort({
93
- sorts: [{prop: 'product', dir: 'desc'}]
94
- });
95
-
96
- expect(fixture.componentInstance._internalRows[0]).toBe(initialRows[2]);
97
- expect(fixture.componentInstance._internalRows[1]).toBe(initialRows[0]);
98
- expect(fixture.componentInstance._internalRows[2]).toBe(initialRows[1]);
99
- });
100
-
101
- it('should use a stable sorting algorithm', () => {
102
- const fixture = TestBed.createComponent(DatatableComponent);
103
- /**
104
- * the following `initialRows`, when sorted by the character length
105
- * of the value of the `name` property would result in the following
106
- * (unstable sort) in Chrome:
107
- * [
108
- * { name: 'cat' },
109
- * { name: 'sed' },
110
- * { name: 'man' },
111
- * { name: 'foo' },
112
- * { name: 'bar' },
113
- * { name: 'sit' },
114
- * { name: 'amet' },
115
- * { name: 'dolor' },
116
- * { name: 'ipsum' },
117
- * { name: 'lorem' },
118
- * { name: 'maecennas' }
119
- * ]
120
- */
121
- const initialRows = [
122
- { name: 'sed' },
123
- { name: 'dolor' },
124
- { name: 'ipsum' },
125
- { name: 'foo' },
126
- { name: 'bar' },
127
- { name: 'cat' },
128
- { name: 'sit' },
129
- { name: 'man' },
130
- { name: 'lorem' },
131
- { name: 'amet' },
132
- { name: 'maecennas' }
133
- ];
134
-
135
- const columns = [
136
- {
137
- prop: 'name',
138
- comparator: (nameA: string, nameB: string) => {
139
- return nameA.length - nameB.length;
140
- }
141
- }
142
- ];
143
-
144
- fixture.componentInstance.rows = initialRows;
145
- fixture.componentInstance.columns = columns;
146
-
147
- fixture.detectChanges();
148
-
149
- fixture.componentInstance.onColumnSort({
150
- sorts: [{prop: 'name', dir: 'asc'}]
151
- });
152
-
153
- expect(fixture.componentInstance._internalRows[0]).toBe(initialRows[0]);
154
- expect(fixture.componentInstance._internalRows[1]).toBe(initialRows[3]);
155
- expect(fixture.componentInstance._internalRows[2]).toBe(initialRows[4]);
156
- expect(fixture.componentInstance._internalRows[3]).toBe(initialRows[5]);
157
- expect(fixture.componentInstance._internalRows[4]).toBe(initialRows[6]);
158
- expect(fixture.componentInstance._internalRows[5]).toBe(initialRows[7]);
159
- expect(fixture.componentInstance._internalRows[6]).toBe(initialRows[9]);
160
- expect(fixture.componentInstance._internalRows[7]).toBe(initialRows[1]);
161
- expect(fixture.componentInstance._internalRows[8]).toBe(initialRows[2]);
162
- expect(fixture.componentInstance._internalRows[9]).toBe(initialRows[8]);
163
- expect(fixture.componentInstance._internalRows[10]).toBe(initialRows[10]);
164
- });
53
+ it('should sort number values', () => {
54
+ const initialRows = [
55
+ { id: 5 },
56
+ { id: 20 },
57
+ { id: 12 }
58
+ ];
59
+
60
+ const columns = [
61
+ {
62
+ prop: 'id'
63
+ }
64
+ ];
65
+
66
+ component.rows = initialRows;
67
+ component.columns = columns;
68
+ fixture.detectChanges();
69
+
70
+ // sort by `id` ascending
71
+ sortBy({ column: 1 });
72
+ fixture.detectChanges();
73
+
74
+ expect(textContent({ row: 1, column: 1 })).toContain('5', 'Ascending');
75
+ expect(textContent({ row: 2, column: 1 })).toContain('12', 'Ascending');
76
+ expect(textContent({ row: 3, column: 1 })).toContain('20', 'Ascending');
77
+
78
+ // sort by `id` descending
79
+ sortBy({ column: 1 });
80
+ fixture.detectChanges();
81
+
82
+ expect(textContent({ row: 1, column: 1 })).toContain('20', 'Descending');
83
+ expect(textContent({ row: 2, column: 1 })).toContain('12', 'Descending');
84
+ expect(textContent({ row: 3, column: 1 })).toContain('5', 'Descending');
165
85
  });
166
86
 
167
- describe('When the column is sorted with a custom comparator', () => {
168
-
169
- xit('should return a new array', () => {
170
- const fixture = TestBed.createComponent(DatatableComponent);
171
- const initialRows = [
172
- {id: 1},
173
- {id: 2},
174
- {id: 3}
175
- ];
176
-
177
- const columns = [
178
- {
179
- prop: 'foo',
180
- comparator: (propA: string, propB: string) => {
181
- if (propA.toLowerCase() > propB.toLowerCase()) return -1;
182
- if (propA.toLowerCase() < propB.toLowerCase()) return 1;
183
- }
184
- }
185
- ];
87
+ it('should sort string values', () => {
88
+ const initialRows = [
89
+ { product: 'Computers' },
90
+ { product: 'Bikes' },
91
+ { product: 'Smartphones'}
92
+ ];
186
93
 
187
- fixture.componentInstance.rows = initialRows;
188
- fixture.componentInstance.columns = columns;
94
+ const columns = [
95
+ {
96
+ prop: 'product'
97
+ }
98
+ ];
189
99
 
190
- fixture.detectChanges();
100
+ component.rows = initialRows;
101
+ component.columns = columns;
102
+ fixture.detectChanges();
191
103
 
192
- expect(fixture.componentInstance._internalRows).toBe(initialRows);
104
+ // sort by `product` ascending
105
+ sortBy({ column: 1 });
106
+ fixture.detectChanges();
193
107
 
194
- fixture.componentInstance.onColumnSort({
195
- sorts: [{prop: 'foo', dir: 'desc'}]
196
- });
108
+ expect(textContent({ row: 1, column: 1 })).toContain('Bikes', 'Ascending');
109
+ expect(textContent({ row: 2, column: 1 })).toContain('Computers', 'Ascending');
110
+ expect(textContent({ row: 3, column: 1 })).toContain('Smartphones', 'Ascending');
197
111
 
198
- fixture.componentInstance.sort
199
- .subscribe();
112
+ // sort by `product` descending
113
+ sortBy({ column: 1 });
114
+ fixture.detectChanges();
200
115
 
201
- expect(fixture.componentInstance._internalRows).not.toBe(initialRows);
202
- });
116
+ expect(textContent({ row: 1, column: 1 })).toContain('Smartphones', 'Descending');
117
+ expect(textContent({ row: 2, column: 1 })).toContain('Computers', 'Descending');
118
+ expect(textContent({ row: 3, column: 1 })).toContain('Bikes', 'Descending');
203
119
  });
204
120
 
205
- it('should set offset to 0 when sorting by a column', () => {
206
- const fixture = TestBed.createComponent(DatatableComponent);
121
+ it('should sort with a custom comparator', () => {
207
122
  const initialRows = [
208
- {id: 1},
209
- {id: 2},
210
- {id: 3}
123
+ { product: 'Smartphones'},
124
+ { product: 'Cars' },
125
+ { product: 'Bikes' }
211
126
  ];
212
127
 
213
128
  const columns = [
214
129
  {
215
- prop: 'id'
130
+ prop: 'product',
131
+ comparator: (productA: string, productB: string) => {
132
+ return productA.length - productB.length;
133
+ }
216
134
  }
217
135
  ];
218
136
 
219
- fixture.componentInstance.rows = initialRows;
220
- fixture.componentInstance.columns = columns;
221
- fixture.componentInstance.offset = 1;
137
+ component.rows = initialRows;
138
+ component.columns = columns;
139
+ fixture.detectChanges();
222
140
 
141
+ // sort by `product` ascending
142
+ sortBy({ column: 1 });
223
143
  fixture.detectChanges();
224
144
 
225
- fixture.componentInstance.onColumnSort({
226
- sorts: [{prop: 'id', dir: 'desc'}]
227
- });
145
+ expect(textContent({ row: 1, column: 1 })).toContain('Cars', 'Ascending');
146
+ expect(textContent({ row: 2, column: 1 })).toContain('Bikes', 'Ascending');
147
+ expect(textContent({ row: 3, column: 1 })).toContain('Smartphones', 'Ascending');
228
148
 
229
- expect(fixture.componentInstance.offset).toBe(0);
149
+ // sort by `product` descending
150
+ sortBy({ column: 1 });
151
+ fixture.detectChanges();
152
+
153
+ expect(textContent({ row: 1, column: 1 })).toContain('Smartphones', 'Descending');
154
+ expect(textContent({ row: 2, column: 1 })).toContain('Bikes', 'Descending');
155
+ expect(textContent({ row: 3, column: 1 })).toContain('Cars', 'Descending');
230
156
  });
231
157
 
232
- describe('table with numeric prop', () => {
233
- it('should support array data', () => {
234
- const fixture = TestBed.createComponent(DatatableComponent);
158
+ it('should sort using a stable sorting algorithm', () => {
159
+ const initialRows = [
160
+ { name: 'sed', state: 'CA' },
161
+ { name: 'dolor', state: 'NY' },
162
+ { name: 'ipsum', state: 'NY' },
163
+ { name: 'foo', state: 'CA' },
164
+ { name: 'bar', state: 'CA' },
165
+ { name: 'cat', state: 'CA' },
166
+ { name: 'sit', state: 'CA' },
167
+ { name: 'man', state: 'CA' },
168
+ { name: 'lorem', state: 'NY' },
169
+ { name: 'amet', state: 'NY' },
170
+ { name: 'maecennas', state: 'NY' }
171
+ ];
172
+
173
+ /**
174
+ * assume the following sort operations take place on `initialRows`:
175
+ * 1) initialRows.sort(byLengthOfNameProperty) (Ascending)
176
+ * 2) initialRows.sort(byState) (Descending)
177
+ *
178
+ * in browsers that do not natively implement stable sort (such as Chrome),
179
+ * the result could be:
180
+ *
181
+ * [
182
+ * { name: 'maecennas', state: 'NY' },
183
+ * { name: 'amet', state: 'NY' },
184
+ * { name: 'dolor', state: 'NY' },
185
+ * { name: 'ipsum', state: 'NY' },
186
+ * { name: 'lorem', state: 'NY' },
187
+ * { name: 'sed', state: 'CA' },
188
+ * { name: 'cat', state: 'CA' },
189
+ * { name: 'man', state: 'CA' },
190
+ * { name: 'foo', state: 'CA' },
191
+ * { name: 'bar', state: 'CA' },
192
+ * { name: 'sit', state: 'CA' }
193
+ * ]
194
+ *
195
+ * in browsers that natively implement stable sort the result is guaranteed
196
+ * to be:
197
+ *
198
+ * [
199
+ * { name: 'amet', state: 'NY' },
200
+ * { name: 'dolor', state: 'NY' },
201
+ * { name: 'ipsum', state: 'NY' },
202
+ * { name: 'lorem', state: 'NY' },
203
+ * { name: 'maecennas', state: 'NY' },
204
+ * { name: 'sed', state: 'CA' },
205
+ * { name: 'foo', state: 'CA' },
206
+ * { name: 'bar', state: 'CA' },
207
+ * { name: 'cat', state: 'CA' },
208
+ * { name: 'sit', state: 'CA' },
209
+ * { name: 'man', state: 'CA' }
210
+ * ]
211
+ */
212
+
213
+ const columns = [
214
+ {
215
+ prop: 'name',
216
+ comparator: (nameA: string, nameB: string) => {
217
+ return nameA.length - nameB.length;
218
+ }
219
+ },
220
+ {
221
+ prop: 'state'
222
+ }
223
+ ];
235
224
 
236
- const tableInstance = fixture.componentInstance;
237
- tableInstance.rows = [
238
- ['Hello', 123]
239
- ];
225
+ component.rows = initialRows;
226
+ component.columns = columns;
227
+ fixture.detectChanges();
240
228
 
241
- tableInstance.columns = [
242
- { prop: 0 },
243
- { prop: 1 }
244
- ];
229
+ // sort by `name` ascending
230
+ sortBy({ column: 1 });
231
+ fixture.detectChanges();
245
232
 
246
- // previously, an exception was thrown from column-helper.ts setColumnDefaults()
247
- fixture.detectChanges();
233
+ // sort by `state` descending
234
+ sortBy({ column: 2 });
235
+ fixture.detectChanges();
236
+ sortBy({ column: 2 });
237
+ fixture.detectChanges();
248
238
 
249
- expect(tableInstance.columns).toBeTruthy();
250
- });
239
+ expect(textContent({ row: 1, column: 1 })).toContain('amet');
240
+ expect(textContent({ row: 2, column: 1 })).toContain('dolor');
241
+ expect(textContent({ row: 3, column: 1 })).toContain('ipsum');
242
+ expect(textContent({ row: 4, column: 1 })).toContain('lorem');
243
+ expect(textContent({ row: 5, column: 1 })).toContain('maecennas');
244
+ expect(textContent({ row: 6, column: 1 })).toContain('sed');
245
+ expect(textContent({ row: 7, column: 1 })).toContain('foo');
246
+ expect(textContent({ row: 8, column: 1 })).toContain('bar');
247
+ expect(textContent({ row: 9, column: 1 })).toContain('cat');
248
+ expect(textContent({ row: 10, column: 1 })).toContain('sit');
249
+ expect(textContent({ row: 11, column: 1 })).toContain('man');
251
250
  });
251
+
252
+ it('should sort correctly after push events', () => {
253
+ const initialRows = [
254
+ { name: 'sed', state: 'CA' },
255
+ { name: 'dolor', state: 'NY' },
256
+ { name: 'ipsum', state: 'NY' },
257
+ { name: 'foo', state: 'CA' },
258
+ { name: 'bar', state: 'CA' },
259
+ { name: 'cat', state: 'CA' },
260
+ { name: 'sit', state: 'CA' },
261
+ { name: 'man', state: 'CA' },
262
+ { name: 'lorem', state: 'NY' },
263
+ { name: 'amet', state: 'NY' },
264
+ { name: 'maecennas', state: 'NY' }
265
+ ];
266
+ const additionalRows = [ ...initialRows ];
267
+
268
+ const columns = [
269
+ {
270
+ prop: 'name',
271
+ comparator: (nameA: string, nameB: string) => {
272
+ return nameA.length - nameB.length;
273
+ }
274
+ },
275
+ {
276
+ prop: 'state'
277
+ }
278
+ ];
279
+
280
+ component.rows = initialRows;
281
+ component.columns = columns;
282
+ fixture.detectChanges();
252
283
 
284
+ // sort by `state` descending
285
+ sortBy({ column: 2 });
286
+ fixture.detectChanges();
287
+ sortBy({ column: 2 });
288
+ fixture.detectChanges();
289
+
290
+ // sort by `name` ascending
291
+ sortBy({ column: 1 });
292
+ fixture.detectChanges();
293
+
294
+ // mimic new `rows` data pushed to component
295
+ component.rows = additionalRows;
296
+ fixture.detectChanges();
297
+
298
+ // sort by `state` descending
299
+ sortBy({ column: 2 });
300
+ fixture.detectChanges();
301
+ sortBy({ column: 2 });
302
+ fixture.detectChanges();
303
+
304
+ expect(textContent({ row: 1, column: 1 })).toContain('amet');
305
+ expect(textContent({ row: 2, column: 1 })).toContain('dolor');
306
+ expect(textContent({ row: 3, column: 1 })).toContain('ipsum');
307
+ expect(textContent({ row: 4, column: 1 })).toContain('lorem');
308
+ expect(textContent({ row: 5, column: 1 })).toContain('maecennas');
309
+ expect(textContent({ row: 6, column: 1 })).toContain('sed');
310
+ expect(textContent({ row: 7, column: 1 })).toContain('foo');
311
+ expect(textContent({ row: 8, column: 1 })).toContain('bar');
312
+ expect(textContent({ row: 9, column: 1 })).toContain('cat');
313
+ expect(textContent({ row: 10, column: 1 })).toContain('sit');
314
+ expect(textContent({ row: 11, column: 1 })).toContain('man');
315
+ });
316
+
317
+ it('should set offset to 0 when sorting by a column', () => {
318
+ const initialRows = [
319
+ {id: 1},
320
+ {id: 2},
321
+ {id: 3}
322
+ ];
323
+
324
+ const columns = [
325
+ {
326
+ prop: 'id'
327
+ }
328
+ ];
329
+
330
+ component.rows = initialRows;
331
+ component.columns = columns;
332
+ fixture.detectChanges();
333
+
334
+ const datatableComponent = fixture.debugElement
335
+ .query(By.directive(DatatableComponent))
336
+ .componentInstance;
337
+ datatableComponent.offset = 1;
338
+
339
+ // sort by `id` descending
340
+ sortBy({ column: 1 });
341
+ fixture.detectChanges();
342
+ sortBy({ column: 1 });
343
+ fixture.detectChanges();
344
+
345
+ expect(datatableComponent.offset).toBe(0);
346
+ });
347
+
348
+ it('should support array data', () => {
349
+ const initialRows = [
350
+ ['Hello', 123]
351
+ ];
352
+
353
+ const columns = [
354
+ { prop: 0 },
355
+ { prop: 1 }
356
+ ];
357
+
358
+ // previously, an exception was thrown from column-helper.ts setColumnDefaults()
359
+ component.rows = initialRows;
360
+ component.columns = columns;
361
+ fixture.detectChanges();
362
+
363
+ expect(textContent({ row: 1, column: 1 })).toContain('Hello');
364
+ expect(textContent({ row: 1, column: 2 })).toContain('123');
365
+ });
253
366
  });
367
+
368
+ @Component({
369
+ template: `
370
+ <ngx-datatable
371
+ [columns]="columns"
372
+ [rows]="rows">
373
+ </ngx-datatable>
374
+ `
375
+ })
376
+ class TestFixtureComponent {
377
+ columns: any[] = [];
378
+ rows: any[] = [];
379
+ }
380
+
381
+ function setupTest() {
382
+ return TestBed.configureTestingModule({
383
+ declarations: [ TestFixtureComponent ],
384
+ imports: [ NgxDatatableModule ]
385
+ })
386
+ .compileComponents()
387
+ .then(() => {
388
+ fixture = TestBed.createComponent(TestFixtureComponent);
389
+ component = fixture.componentInstance;
390
+ });
391
+ }
392
+
393
+ /**
394
+ * mimics the act of a user clicking a column to sort it
395
+ */
396
+ function sortBy({ column }: { column: number }) {
397
+ const columnIndex = column - 1;
398
+ const headerCellDe = fixture.debugElement
399
+ .queryAll(By.css('datatable-header-cell'))[columnIndex];
400
+ const de = headerCellDe.query(By.css('span:last-child'));
401
+ de.triggerEventHandler('click', null);
402
+ }
403
+
404
+ /**
405
+ * test helper function to return text content of a cell within the
406
+ * body of the ngx-datatable component
407
+ */
408
+ function textContent({ row, column }: { row: number, column: number }) {
409
+ const [ rowIndex, columnIndex ] = [ row - 1, column - 1];
410
+ const bodyRowDe = fixture.debugElement
411
+ .queryAll(By.directive(DataTableBodyRowComponent))[rowIndex];
412
+ const bodyCellDe = bodyRowDe
413
+ .queryAll(By.directive(DataTableBodyCellComponent))[columnIndex];
414
+
415
+ return bodyCellDe.nativeElement.textContent;
416
+ }