@acpaas-ui/ngx-forms 6.1.9 → 6.1.10

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 (161) hide show
  1. package/.eslintrc.json +42 -0
  2. package/LICENSE.md +21 -0
  3. package/dist/README.md +23 -0
  4. package/dist/esm2020/lib/datepicker/components/datepicker/datepicker.component.mjs +232 -0
  5. package/{fesm2015 → dist/fesm2015}/acpaas-ui-ngx-forms.mjs +7 -4
  6. package/dist/fesm2015/acpaas-ui-ngx-forms.mjs.map +1 -0
  7. package/{fesm2020 → dist/fesm2020}/acpaas-ui-ngx-forms.mjs +7 -4
  8. package/dist/fesm2020/acpaas-ui-ngx-forms.mjs.map +1 -0
  9. package/dist/package.json +44 -0
  10. package/karma.conf.js +38 -0
  11. package/ng-package.json +8 -0
  12. package/package.json +6 -27
  13. package/src/lib/auto-complete/README.md +148 -0
  14. package/src/lib/auto-complete/auto-complete.module.ts +15 -0
  15. package/src/lib/auto-complete/components/auto-complete/auto-complete.component.html +51 -0
  16. package/src/lib/auto-complete/components/auto-complete/auto-complete.component.scss +4 -0
  17. package/src/lib/auto-complete/components/auto-complete/auto-complete.component.spec.ts +378 -0
  18. package/src/lib/auto-complete/components/auto-complete/auto-complete.component.ts +281 -0
  19. package/src/lib/auto-complete/public-api.ts +2 -0
  20. package/src/lib/datepicker/README.md +110 -0
  21. package/src/lib/datepicker/components/datepicker/datepicker.component.html +47 -0
  22. package/src/lib/datepicker/components/datepicker/datepicker.component.scss +13 -0
  23. package/src/lib/datepicker/components/datepicker/datepicker.component.spec.ts +204 -0
  24. package/src/lib/datepicker/components/datepicker/datepicker.component.ts +251 -0
  25. package/src/lib/datepicker/datepicker.conf.ts +11 -0
  26. package/src/lib/datepicker/datepicker.module.ts +50 -0
  27. package/src/lib/datepicker/public-api.ts +8 -0
  28. package/src/lib/datepicker/types/datepicker.types.ts +8 -0
  29. package/src/lib/range-slider/README.md +56 -0
  30. package/src/lib/range-slider/components/range-slider/range-slider.component.html +46 -0
  31. package/src/lib/range-slider/components/range-slider/range-slider.component.scss +12 -0
  32. package/src/lib/range-slider/components/range-slider/range-slider.component.spec.ts +216 -0
  33. package/src/lib/range-slider/components/range-slider/range-slider.component.ts +301 -0
  34. package/src/lib/range-slider/public-api.ts +3 -0
  35. package/src/lib/range-slider/range-slider.module.ts +11 -0
  36. package/src/lib/range-slider/types/range-slider.types.ts +4 -0
  37. package/src/lib/search-filter/README.md +86 -0
  38. package/src/lib/search-filter/components/search-filter/search-filter.component.html +66 -0
  39. package/src/lib/search-filter/components/search-filter/search-filter.component.scss +23 -0
  40. package/src/lib/search-filter/components/search-filter/search-filter.component.spec.ts +264 -0
  41. package/src/lib/search-filter/components/search-filter/search-filter.component.ts +140 -0
  42. package/src/lib/search-filter/public-api.ts +3 -0
  43. package/src/lib/search-filter/search-filter.module.ts +13 -0
  44. package/src/lib/search-filter/types/search-filter.types.ts +4 -0
  45. package/src/lib/shared/services/search.service.spec.ts +78 -0
  46. package/src/lib/shared/services/search.service.ts +32 -0
  47. package/src/lib/shared/types/search.types.ts +6 -0
  48. package/src/lib/timepicker/README.md +84 -0
  49. package/src/lib/timepicker/classes/timepicker.validators.spec.ts +54 -0
  50. package/src/lib/timepicker/classes/timepicker.validators.ts +61 -0
  51. package/src/lib/timepicker/components/timepicker/timepicker.component.html +37 -0
  52. package/src/lib/timepicker/components/timepicker/timepicker.component.scss +3 -0
  53. package/src/lib/timepicker/components/timepicker/timepicker.component.spec.ts +161 -0
  54. package/src/lib/timepicker/components/timepicker/timepicker.component.ts +128 -0
  55. package/src/lib/timepicker/public-api.ts +4 -0
  56. package/src/lib/timepicker/timepicker.module.ts +13 -0
  57. package/src/lib/timepicker/types/timepicker.types.ts +5 -0
  58. package/src/lib/upload/README.md +283 -0
  59. package/src/lib/upload/classes/uploader.class.spec.ts +100 -0
  60. package/src/lib/upload/classes/uploader.class.ts +144 -0
  61. package/src/lib/upload/components/upload/upload.component.html +28 -0
  62. package/src/lib/upload/components/upload/upload.component.scss +3 -0
  63. package/src/lib/upload/components/upload/upload.component.spec.ts +117 -0
  64. package/src/lib/upload/components/upload/upload.component.ts +50 -0
  65. package/src/lib/upload/components/upload-input/upload-input.component.html +11 -0
  66. package/src/lib/upload/components/upload-input/upload-input.component.spec.ts +55 -0
  67. package/src/lib/upload/components/upload-input/upload-input.component.ts +35 -0
  68. package/src/lib/upload/components/upload-queue/upload-queue.component.html +16 -0
  69. package/src/lib/upload/components/upload-queue/upload-queue.component.spec.ts +99 -0
  70. package/src/lib/upload/components/upload-queue/upload-queue.component.ts +36 -0
  71. package/src/lib/upload/components/upload-zone/upload-zone.component.html +55 -0
  72. package/src/lib/upload/components/upload-zone/upload-zone.component.scss +3 -0
  73. package/src/lib/upload/components/upload-zone/upload-zone.component.spec.ts +144 -0
  74. package/src/lib/upload/components/upload-zone/upload-zone.component.ts +142 -0
  75. package/src/lib/upload/components/validation-list/validation-list.component.html +15 -0
  76. package/src/lib/upload/components/validation-list/validation-list.component.spec.ts +57 -0
  77. package/src/lib/upload/components/validation-list/validation-list.component.ts +29 -0
  78. package/src/lib/upload/public-api.ts +10 -0
  79. package/src/lib/upload/services/validation-messages.service.spec.ts +66 -0
  80. package/src/lib/upload/services/validation-messages.service.ts +27 -0
  81. package/src/lib/upload/types/upload.types.ts +20 -0
  82. package/src/lib/upload/upload.conf.ts +15 -0
  83. package/src/lib/upload/upload.module.ts +34 -0
  84. package/src/public-api.ts +6 -0
  85. package/src/test.ts +9 -0
  86. package/tsconfig.lib.json +26 -0
  87. package/tsconfig.spec.json +17 -0
  88. package/esm2020/lib/datepicker/components/datepicker/datepicker.component.mjs +0 -229
  89. package/fesm2015/acpaas-ui-ngx-forms.mjs.map +0 -1
  90. package/fesm2020/acpaas-ui-ngx-forms.mjs.map +0 -1
  91. /package/{esm2020 → dist/esm2020}/acpaas-ui-ngx-forms.mjs +0 -0
  92. /package/{esm2020 → dist/esm2020}/lib/auto-complete/auto-complete.module.mjs +0 -0
  93. /package/{esm2020 → dist/esm2020}/lib/auto-complete/components/auto-complete/auto-complete.component.mjs +0 -0
  94. /package/{esm2020 → dist/esm2020}/lib/auto-complete/public-api.mjs +0 -0
  95. /package/{esm2020 → dist/esm2020}/lib/datepicker/datepicker.conf.mjs +0 -0
  96. /package/{esm2020 → dist/esm2020}/lib/datepicker/datepicker.module.mjs +0 -0
  97. /package/{esm2020 → dist/esm2020}/lib/datepicker/public-api.mjs +0 -0
  98. /package/{esm2020 → dist/esm2020}/lib/datepicker/types/datepicker.types.mjs +0 -0
  99. /package/{esm2020 → dist/esm2020}/lib/range-slider/components/range-slider/range-slider.component.mjs +0 -0
  100. /package/{esm2020 → dist/esm2020}/lib/range-slider/public-api.mjs +0 -0
  101. /package/{esm2020 → dist/esm2020}/lib/range-slider/range-slider.module.mjs +0 -0
  102. /package/{esm2020 → dist/esm2020}/lib/range-slider/types/range-slider.types.mjs +0 -0
  103. /package/{esm2020 → dist/esm2020}/lib/search-filter/components/search-filter/search-filter.component.mjs +0 -0
  104. /package/{esm2020 → dist/esm2020}/lib/search-filter/public-api.mjs +0 -0
  105. /package/{esm2020 → dist/esm2020}/lib/search-filter/search-filter.module.mjs +0 -0
  106. /package/{esm2020 → dist/esm2020}/lib/search-filter/types/search-filter.types.mjs +0 -0
  107. /package/{esm2020 → dist/esm2020}/lib/shared/services/search.service.mjs +0 -0
  108. /package/{esm2020 → dist/esm2020}/lib/shared/types/search.types.mjs +0 -0
  109. /package/{esm2020 → dist/esm2020}/lib/timepicker/classes/timepicker.validators.mjs +0 -0
  110. /package/{esm2020 → dist/esm2020}/lib/timepicker/components/timepicker/timepicker.component.mjs +0 -0
  111. /package/{esm2020 → dist/esm2020}/lib/timepicker/public-api.mjs +0 -0
  112. /package/{esm2020 → dist/esm2020}/lib/timepicker/timepicker.module.mjs +0 -0
  113. /package/{esm2020 → dist/esm2020}/lib/timepicker/types/timepicker.types.mjs +0 -0
  114. /package/{esm2020 → dist/esm2020}/lib/upload/classes/uploader.class.mjs +0 -0
  115. /package/{esm2020 → dist/esm2020}/lib/upload/components/upload/upload.component.mjs +0 -0
  116. /package/{esm2020 → dist/esm2020}/lib/upload/components/upload-input/upload-input.component.mjs +0 -0
  117. /package/{esm2020 → dist/esm2020}/lib/upload/components/upload-queue/upload-queue.component.mjs +0 -0
  118. /package/{esm2020 → dist/esm2020}/lib/upload/components/upload-zone/upload-zone.component.mjs +0 -0
  119. /package/{esm2020 → dist/esm2020}/lib/upload/components/validation-list/validation-list.component.mjs +0 -0
  120. /package/{esm2020 → dist/esm2020}/lib/upload/public-api.mjs +0 -0
  121. /package/{esm2020 → dist/esm2020}/lib/upload/services/validation-messages.service.mjs +0 -0
  122. /package/{esm2020 → dist/esm2020}/lib/upload/types/upload.types.mjs +0 -0
  123. /package/{esm2020 → dist/esm2020}/lib/upload/upload.conf.mjs +0 -0
  124. /package/{esm2020 → dist/esm2020}/lib/upload/upload.module.mjs +0 -0
  125. /package/{esm2020 → dist/esm2020}/public-api.mjs +0 -0
  126. /package/{index.d.ts → dist/index.d.ts} +0 -0
  127. /package/{lib → dist/lib}/auto-complete/auto-complete.module.d.ts +0 -0
  128. /package/{lib → dist/lib}/auto-complete/components/auto-complete/auto-complete.component.d.ts +0 -0
  129. /package/{lib → dist/lib}/auto-complete/public-api.d.ts +0 -0
  130. /package/{lib → dist/lib}/datepicker/components/datepicker/datepicker.component.d.ts +0 -0
  131. /package/{lib → dist/lib}/datepicker/datepicker.conf.d.ts +0 -0
  132. /package/{lib → dist/lib}/datepicker/datepicker.module.d.ts +0 -0
  133. /package/{lib → dist/lib}/datepicker/public-api.d.ts +0 -0
  134. /package/{lib → dist/lib}/datepicker/types/datepicker.types.d.ts +0 -0
  135. /package/{lib → dist/lib}/range-slider/components/range-slider/range-slider.component.d.ts +0 -0
  136. /package/{lib → dist/lib}/range-slider/public-api.d.ts +0 -0
  137. /package/{lib → dist/lib}/range-slider/range-slider.module.d.ts +0 -0
  138. /package/{lib → dist/lib}/range-slider/types/range-slider.types.d.ts +0 -0
  139. /package/{lib → dist/lib}/search-filter/components/search-filter/search-filter.component.d.ts +0 -0
  140. /package/{lib → dist/lib}/search-filter/public-api.d.ts +0 -0
  141. /package/{lib → dist/lib}/search-filter/search-filter.module.d.ts +0 -0
  142. /package/{lib → dist/lib}/search-filter/types/search-filter.types.d.ts +0 -0
  143. /package/{lib → dist/lib}/shared/services/search.service.d.ts +0 -0
  144. /package/{lib → dist/lib}/shared/types/search.types.d.ts +0 -0
  145. /package/{lib → dist/lib}/timepicker/classes/timepicker.validators.d.ts +0 -0
  146. /package/{lib → dist/lib}/timepicker/components/timepicker/timepicker.component.d.ts +0 -0
  147. /package/{lib → dist/lib}/timepicker/public-api.d.ts +0 -0
  148. /package/{lib → dist/lib}/timepicker/timepicker.module.d.ts +0 -0
  149. /package/{lib → dist/lib}/timepicker/types/timepicker.types.d.ts +0 -0
  150. /package/{lib → dist/lib}/upload/classes/uploader.class.d.ts +0 -0
  151. /package/{lib → dist/lib}/upload/components/upload/upload.component.d.ts +0 -0
  152. /package/{lib → dist/lib}/upload/components/upload-input/upload-input.component.d.ts +0 -0
  153. /package/{lib → dist/lib}/upload/components/upload-queue/upload-queue.component.d.ts +0 -0
  154. /package/{lib → dist/lib}/upload/components/upload-zone/upload-zone.component.d.ts +0 -0
  155. /package/{lib → dist/lib}/upload/components/validation-list/validation-list.component.d.ts +0 -0
  156. /package/{lib → dist/lib}/upload/public-api.d.ts +0 -0
  157. /package/{lib → dist/lib}/upload/services/validation-messages.service.d.ts +0 -0
  158. /package/{lib → dist/lib}/upload/types/upload.types.d.ts +0 -0
  159. /package/{lib → dist/lib}/upload/upload.conf.d.ts +0 -0
  160. /package/{lib → dist/lib}/upload/upload.module.d.ts +0 -0
  161. /package/{public-api.d.ts → dist/public-api.d.ts} +0 -0
@@ -0,0 +1,281 @@
1
+ import {
2
+ Component,
3
+ ContentChild,
4
+ ElementRef,
5
+ EventEmitter,
6
+ forwardRef,
7
+ Input,
8
+ OnChanges,
9
+ OnInit,
10
+ Output,
11
+ SimpleChanges,
12
+ TemplateRef,
13
+ ViewChild,
14
+ } from '@angular/core';
15
+ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
16
+ import { get, isEqual } from 'lodash-es';
17
+ import { FlyoutDirective, FlyoutZoneDirective } from '@acpaas-ui/ngx-flyout';
18
+ import { SearchService } from '../../../shared/services/search.service';
19
+
20
+ @Component({
21
+ selector: 'aui-auto-complete',
22
+ styleUrls: ['./auto-complete.component.scss'],
23
+ templateUrl: './auto-complete.component.html',
24
+ providers: [
25
+ {
26
+ provide: NG_VALUE_ACCESSOR,
27
+ useExisting: forwardRef(() => AutoCompleteComponent), // eslint-disable-line
28
+ multi: true,
29
+ },
30
+ ],
31
+ })
32
+ export class AutoCompleteComponent implements ControlValueAccessor, OnInit, OnChanges {
33
+ @Input() id: string;
34
+ @Input() placeholder: string;
35
+ @Input() description: string;
36
+ @Input() inputLabel: string;
37
+ @Input() results: any[] = []; // The values for the selectable list
38
+ @Input() data: any[] = []; // The values to search in when remote search is disabled
39
+ @Input() remote = false; // Disable or enamble remote search
40
+ @Input() minCharacters = 0;
41
+ @Input() clearInvalid = false;
42
+ @Input() searchIncentiveText: string;
43
+ @Input() loadingText: string;
44
+ @Input() noResultsText: string;
45
+ @Input() showAllByDefault = false;
46
+ @Input() autoComplete = 'off';
47
+
48
+ // specify which label/value props to use
49
+ @Input() label: string;
50
+ @Input() value: string;
51
+
52
+ // Eventemitter for searchvalue (parent object should update the results with this param)
53
+ @Output() search: EventEmitter<string> = new EventEmitter();
54
+ // eslint-disable-next-line @angular-eslint/no-output-native
55
+ @Output() select: EventEmitter<any> = new EventEmitter();
56
+
57
+ @ViewChild(FlyoutDirective, { static: true }) flyout: FlyoutDirective;
58
+ @ViewChild(FlyoutZoneDirective, { static: true }) flyoutZone: FlyoutZoneDirective;
59
+
60
+ @ContentChild(TemplateRef, { static: true }) public template: TemplateRef<any>;
61
+
62
+ public query = '';
63
+ public index = -1; // index for active element in selectable list, by default -1 (so it starts in the input field)
64
+ public selectedItem: any = null; // keep a backup of the selectedItem
65
+ public searching = false; // track remote search state
66
+ public focused = false;
67
+ public isDisabled = false;
68
+
69
+ private remoteValue = false;
70
+
71
+ constructor(private ref: ElementRef, private searchService: SearchService) {}
72
+
73
+ public updateModel = (_: any) => {};
74
+
75
+ // CONTROL_VALUE_ACCESSOR interface
76
+ public writeValue(value = '') {
77
+ if (this.value) {
78
+ const selected = this.data.find((item: any) => item[this.value] === value);
79
+
80
+ if (selected) {
81
+ return (this.query = selected[this.label]);
82
+ }
83
+
84
+ if (this.remote && !!value) {
85
+ this.remoteValue = true;
86
+ }
87
+ }
88
+
89
+ this.query = value;
90
+ }
91
+
92
+ // CONTROL_VALUE_ACCESSOR interface
93
+ public registerOnChange(fn) {
94
+ this.updateModel = fn;
95
+ }
96
+
97
+ // CONTROL_VALUE_ACCESSOR interface
98
+ public registerOnTouched() {}
99
+
100
+ public setDisabledState(isDisabled: boolean): void {
101
+ this.isDisabled = isDisabled;
102
+ }
103
+
104
+ public ngOnInit(): void {
105
+ if (Array.isArray(this.data) && this.data.length > 0 && !this.query && this.showAllByDefault) {
106
+ this.results = [...this.data];
107
+ }
108
+ }
109
+
110
+ // OnChanges interface
111
+ public ngOnChanges(changes: SimpleChanges): void {
112
+ if (!changes) {
113
+ return;
114
+ }
115
+
116
+ const newData = get(changes, 'data.currentValue', []);
117
+ if (!isEqual(newData, get(changes, 'data.previousValue', []))) {
118
+ if (this.remote) {
119
+ this.remoteSearch();
120
+ } else {
121
+ this.localSearch();
122
+ }
123
+ }
124
+
125
+ if (changes.results && changes.results.currentValue) {
126
+ this.searching = false;
127
+ }
128
+ }
129
+
130
+ public propagateChange(item: any) {
131
+ this.query = item !== null ? (this.label ? item[this.label] : item) : '';
132
+ this.select.emit(item);
133
+
134
+ if (!item) {
135
+ return;
136
+ }
137
+
138
+ const key = this.value ? this.value : this.label ? this.label : null;
139
+ this.updateModel(key ? item[key] || '' : item);
140
+ this.selectedItem = item;
141
+ }
142
+
143
+ /**
144
+ * triggers on input value change
145
+ */
146
+ public doSearch(): void {
147
+ this.index = -1; // reset index
148
+ this.searching = true;
149
+
150
+ if (this.remote) {
151
+ this.search.emit(this.query); // ask for new remote data
152
+ } else {
153
+ this.localSearch();
154
+ }
155
+
156
+ this.openFlyout(); // open the flyout when there is a change
157
+ }
158
+
159
+ /**
160
+ * triggers on selectable-list:select -> onClick event in selectable-list
161
+ */
162
+ public onSelect(item: any): void {
163
+ this.propagateChange(item);
164
+ this.closeFlyout(); // Close the flyout manually
165
+ }
166
+
167
+ public onFlyoutClosed(): void {
168
+ // there is only 1 result, select it
169
+ if (this.index >= 0 && this.results.length === 1) {
170
+ return this.onSelect(this.results[0]);
171
+ }
172
+
173
+ // there is no query nor selected item, clear the selected item
174
+ if (!this.query && this.index < 0) {
175
+ return this.onSelect(null);
176
+ }
177
+
178
+ // reset the query for an invalid query if clearInvalid is true
179
+ if (this.clearInvalid && this.query && !this.results.length && this.index < 0) {
180
+ this.query = this.selectedItem ? (this.label ? this.selectedItem[this.label] : this.selectedItem) : '';
181
+ }
182
+ }
183
+
184
+ public onKeyArrowDown(): void {
185
+ if (this.index < this.results.length - 1) {
186
+ this.scrollList(1);
187
+ }
188
+
189
+ this.openFlyout();
190
+ }
191
+
192
+ public onKeyArrowUp(): void {
193
+ if (this.index >= 0) {
194
+ this.scrollList(-1);
195
+ }
196
+ }
197
+
198
+ public onKeyEnter(event: Event): void {
199
+ event.preventDefault(); // Do not submit form when selecting an item.
200
+
201
+ const query = this.index >= 0 ? this.results[this.index] : this.query;
202
+
203
+ this.propagateChange(query);
204
+ this.closeFlyout();
205
+ }
206
+
207
+ public onKeyEscape(): void {
208
+ this.closeFlyout();
209
+ }
210
+
211
+ public onFocus(): void {
212
+ this.focused = true;
213
+ this.openFlyout();
214
+ }
215
+
216
+ public openFlyout(): void {
217
+ if (this.flyout) {
218
+ this.flyout.open();
219
+ }
220
+ }
221
+
222
+ public closeFlyout(): void {
223
+ if (this.flyout) {
224
+ this.flyout.close();
225
+ }
226
+
227
+ this.focused = false;
228
+ }
229
+
230
+ public localSearch(): void {
231
+ this.results = this.searchService.search(this.data, {
232
+ minLength: this.minCharacters,
233
+ key: this.label,
234
+ query: this.query,
235
+ showAllByDefault: this.showAllByDefault,
236
+ });
237
+
238
+ if (this.results.length === 1 && this.query === this.results[0][this.label]) {
239
+ this.index = 0;
240
+ }
241
+
242
+ this.searching = false;
243
+ }
244
+
245
+ public remoteSearch(): void {
246
+ if (!this.remoteValue || !this.data) {
247
+ return;
248
+ }
249
+
250
+ const selected = this.data.find((item: any) => {
251
+ if (this.value) {
252
+ return item[this.value] === this.query;
253
+ }
254
+
255
+ return item === this.query;
256
+ });
257
+
258
+ if (selected) {
259
+ this.query = this.label ? selected[this.label] : selected;
260
+ } else {
261
+ this.query = '';
262
+ }
263
+
264
+ this.remoteValue = false;
265
+ }
266
+
267
+ public scrollList(factor: number): void {
268
+ this.index += factor;
269
+
270
+ if (!this.flyoutZone) {
271
+ return;
272
+ }
273
+
274
+ const liItems = this.flyoutZone.element.getElementsByTagName('li');
275
+ const liHeight = liItems[1] ? liItems[1].offsetHeight : liItems[0].offsetHeight;
276
+ const zoneHeight = this.flyoutZone.element.offsetHeight;
277
+ const offset = zoneHeight / liHeight / 2;
278
+
279
+ this.flyoutZone.element.scrollTop = this.index * liHeight - offset * liHeight;
280
+ }
281
+ }
@@ -0,0 +1,2 @@
1
+ export { AutoCompleteModule } from './auto-complete.module';
2
+ export { AutoCompleteComponent } from './components/auto-complete/auto-complete.component';
@@ -0,0 +1,110 @@
1
+ # @acpaas-ui/ngx-forms
2
+
3
+ The package creates a custom input component allowing the user to select a date either by input or by picking one in the calendar flyout.
4
+
5
+ ## Usage
6
+
7
+ ```typescript
8
+ import { DatepickerModule } from '@acpaas-ui/ngx-forms';
9
+ ```
10
+
11
+ ## Documentation
12
+
13
+ Visit our [documentation site](https://antwerp-ui.digipolis.be/) for full how-to docs and guidelines
14
+
15
+ ### Flyout module
16
+
17
+ #### API
18
+
19
+ | Name | Default value | Description |
20
+ | -------------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
21
+ | `@Input() id: string;` | - | The id to use on the input field. |
22
+ | `@Input() name: string;` | - | The name to use on the input field. |
23
+ | `@Input() label: string;` | - | The label to use on the input field. |
24
+ | `@Input() description: string;` | - | The description to use on the input field. |
25
+ | `@Input() placeholder: string;` | `'dd/mm/yyyy'` | The placeholder to use on the input field. |
26
+ | `@Input() autocomplete: string;` | `'off'` | Turn the browsers autocompletion on or off. |
27
+ | `@Input() range: DateRange;` | - | A range of dates or weekdays to disable (see the [@acpaas-ui/js-date-utils](https://github.com/digipolisantwerp/antwerp-ui_js/blob/master/packages/date-utils/README.md) package for more info on date ranges). |
28
+
29
+ #### Example
30
+
31
+ You can provide custom month and weekday labels as wel as error labels via the `forChild` method.
32
+
33
+ ```typescript
34
+ import { DatepickerModule } from '@acpaas-ui/ngx-forms';
35
+
36
+ @NgModule({
37
+ imports: [
38
+ DatepickerModule.forChild(
39
+ ['Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrijdag', 'Zaterdag', 'Zondag'],
40
+ [
41
+ 'Januari',
42
+ 'Februari',
43
+ 'Maart',
44
+ 'April',
45
+ 'Mei',
46
+ 'Juni',
47
+ 'Juli',
48
+ 'Augustus',
49
+ 'September',
50
+ 'Oktober',
51
+ 'November',
52
+ 'December',
53
+ ],
54
+ {
55
+ ERRORS_INVALID_DATE: 'Ongeldige datum.',
56
+ ERRORS_INVALID_RANGE: 'Deze datum kan niet gekozen worden.',
57
+ }
58
+ ),
59
+ ],
60
+ })
61
+ export class AppModule {}
62
+ ```
63
+
64
+ You can use the component in template driven, as well as reactive forms. The value is always an ISO string of the Date.
65
+ In the example below we use a reactive form.
66
+
67
+ ```typescript
68
+ import { FormBuilder, FormGroup } from '@angular/forms';
69
+
70
+ import { DateRange } from '@acpaas-ui/ngx-utils';
71
+
72
+ constructor(private fb: FormBuilder) { }
73
+
74
+ public dateRange: DateRange = [5, 6];
75
+ public dateForm: FormGroup;
76
+
77
+ this.dateForm = this.fb.group({
78
+ inputDate: [''],
79
+ });
80
+ ```
81
+
82
+ ```html
83
+ <form [formGroup]="dateForm">
84
+ <div
85
+ class="a-input has-icon-right"
86
+ [ngClass]="{'has-error': dateForm.controls.inputDate.dirty && dateForm.controls.inputDate.invalid}"
87
+ >
88
+ <label class="a-input__label" for="input-datepicker">Pick a date</label>
89
+ <aui-datepicker
90
+ data-id="input-datepicker"
91
+ name="input-datepicker"
92
+ autocomplete="off"
93
+ label="Pick date"
94
+ description="Description"
95
+ placeholder="dd/mm/jjjj"
96
+ formControlName="inputDate"
97
+ [range]="dateRange"
98
+ >
99
+ </aui-datepicker>
100
+ <div *ngIf="dateForm.controls['inputDate'].errors">
101
+ <p *ngIf="dateForm.controls['inputDate'].errors.format">{{ dateForm.controls['inputDate'].errors.format }}</p>
102
+ <p *ngIf="dateForm.controls['inputDate'].errors.range">{{ dateForm.controls['inputDate'].errors.range }}</p>
103
+ </div>
104
+ </div>
105
+ </form>
106
+ ```
107
+
108
+ ## Contributing
109
+
110
+ Visit our [Contribution Guidelines](../../../../../CONTRIBUTING.md) for more information on how to contribute.
@@ -0,0 +1,47 @@
1
+ <div aria-haspopup="grid" auiFlyout class="aui-datepicker a-input has-icon-right">
2
+ <label class="a-input__label" for="{{ id }}" *ngIf="label">{{ label }}</label>
3
+ <small class="a-input__description" *ngIf="description"> {{ description }}</small>
4
+ <div class="a-input__wrapper">
5
+ <input
6
+ (blur)="handleBlur($event)"
7
+ [attr.disabled]="isDisabled ? true : null"
8
+ [autocomplete]="autocomplete"
9
+ [formControl]="formControl"
10
+ id="{{ id }}"
11
+ label="Pick date"
12
+ description="Description"
13
+ name="{{ name }}"
14
+ placeholder="{{ placeholder }}"
15
+ type="text"
16
+ />
17
+ <ng-container *ngIf="isDisabled">
18
+ <aui-icon
19
+ name="ai-calendar"
20
+ />
21
+ </ng-container>
22
+ <ng-container *ngIf="!isDisabled">
23
+ <aui-icon
24
+ auiFlyoutAction
25
+ [openOnFocus]="false"
26
+ name="ai-calendar"
27
+ className="is-clickable"
28
+ role="button"
29
+ [attr.aria-label]="ariaOpenDatepickerLabel"
30
+ tabindex="0"
31
+ />
32
+ </ng-container>
33
+
34
+ <ng-container *ngIf="!isDisabled">
35
+ <div auiFlyoutZone class="m-datepicker m-datepicker--fixed" role="dialog">
36
+ <aui-calendar
37
+ (selectDate)="selectDateFromCalendar($event)"
38
+ [range]="range"
39
+ [selectedDate]="selectedDate"
40
+ [interval]="interval"
41
+ [weekdayLabels]="weekdayLabels"
42
+ [monthLabels]="monthLabels"
43
+ ></aui-calendar>
44
+ </div>
45
+ </ng-container>
46
+ </div>
47
+ </div>
@@ -0,0 +1,13 @@
1
+ :host,
2
+ .aui-datepicker {
3
+ display: block;
4
+ }
5
+
6
+ .m-flyout.is-open {
7
+ .m-datepicker {
8
+ opacity: 1;
9
+ transform: translateY(calc(var(--BORDER-WIDTH)*-1));
10
+ transition-delay: 0s;
11
+ visibility: visible;
12
+ }
13
+ }
@@ -0,0 +1,204 @@
1
+ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
2
+ import { Component, OnInit } from '@angular/core';
3
+ import {
4
+ UntypedFormBuilder,
5
+ UntypedFormControl,
6
+ UntypedFormGroup,
7
+ FormsModule,
8
+ ReactiveFormsModule,
9
+ } from '@angular/forms';
10
+ import { DateRange, DateHelper } from '@acpaas-ui/ngx-utils';
11
+ import { CalendarModule } from '@acpaas-ui/ngx-calendar';
12
+ import { FlyoutModule } from '@acpaas-ui/ngx-flyout';
13
+ import { IconModule } from '@acpaas-ui/ngx-icon';
14
+
15
+ import { DATEPICKER_DEFAULT_ERROR_LABELS, DATEPICKER_ERROR_LABELS } from '../../datepicker.conf';
16
+ import { DatepickerComponent } from './datepicker.component';
17
+
18
+ @Component({
19
+ selector: 'aui-test-one',
20
+ template: `
21
+ <form #testForm="ngForm" (ngSubmit)="submit(testForm.value)">
22
+ <aui-datepicker
23
+ id="test"
24
+ name="test"
25
+ placeholder="dd/mm/jjjj"
26
+ autocomplete="off"
27
+ [range]="range"
28
+ [(ngModel)]="dateModel"
29
+ ></aui-datepicker>
30
+ </form>
31
+ `,
32
+ })
33
+ export class TestComponent {
34
+ public range: DateRange;
35
+ public dateModel: Date;
36
+
37
+ submit(form) {}
38
+ }
39
+
40
+ @Component({
41
+ selector: 'aui-test-two',
42
+ template: `
43
+ <form [formGroup]="testForm" (ngSubmit)="submit(testForm.value)">
44
+ <aui-datepicker
45
+ id="test"
46
+ name="test"
47
+ placeholder="dd/mm/jjjj"
48
+ autocomplete="off"
49
+ [range]="range"
50
+ formControlName="date"
51
+ ></aui-datepicker>
52
+ </form>
53
+ `,
54
+ })
55
+ export class ReactiveTestComponent implements OnInit {
56
+ public range: DateRange;
57
+ public dateModel: Date;
58
+ public testForm: UntypedFormGroup;
59
+
60
+ constructor(private fb: UntypedFormBuilder) {}
61
+
62
+ public ngOnInit() {
63
+ this.testForm = this.fb.group({
64
+ date: '',
65
+ });
66
+ }
67
+
68
+ submit(form) {}
69
+ }
70
+
71
+ describe('The Datepicker Component', () => {
72
+ // waitForAsync beforeEach
73
+ beforeEach(waitForAsync(() => {
74
+ TestBed.configureTestingModule({
75
+ imports: [FormsModule, ReactiveFormsModule, FlyoutModule, IconModule, CalendarModule],
76
+ declarations: [TestComponent, ReactiveTestComponent, DatepickerComponent],
77
+ providers: [
78
+ {
79
+ provide: DATEPICKER_ERROR_LABELS,
80
+ useValue: DATEPICKER_DEFAULT_ERROR_LABELS,
81
+ },
82
+ ],
83
+ }).compileComponents();
84
+ }));
85
+
86
+ // describe('Template driven', () => {
87
+ // let comp: TestComponent;
88
+ // let fixture: ComponentFixture<TestComponent>;
89
+ // let picker: DatepickerComponent;
90
+
91
+ // // synchronous beforeEach
92
+ // beforeEach(() => {
93
+ // fixture = TestBed.createComponent(TestComponent);
94
+
95
+ // comp = fixture.componentInstance;
96
+
97
+ // picker = fixture.debugElement.children[0].children[0].componentInstance;
98
+ // });
99
+
100
+ // it('should exist', () => {
101
+ // fixture.detectChanges();
102
+ // expect(picker).toBeDefined();
103
+ // });
104
+ // });
105
+
106
+ describe('Reactive', () => {
107
+ let comp: ReactiveTestComponent;
108
+ let fixture: ComponentFixture<ReactiveTestComponent>;
109
+ let picker: DatepickerComponent;
110
+
111
+ // synchronous beforeEach
112
+ beforeEach(() => {
113
+ fixture = TestBed.createComponent(ReactiveTestComponent);
114
+
115
+ comp = fixture.componentInstance;
116
+
117
+ picker = fixture.debugElement.children[0].children[0].componentInstance;
118
+ picker.ngOnInit();
119
+ });
120
+
121
+ describe('writeValue', () => {
122
+ let accessor;
123
+
124
+ beforeEach(() => {
125
+ accessor = {
126
+ update: () => {},
127
+ };
128
+
129
+ spyOn(accessor, 'update');
130
+
131
+ picker.registerOnChange(accessor.update);
132
+ });
133
+
134
+ it('should update the model if the value is a valid date', () => {
135
+ const date = new Date('2018-01-10T00:00:00Z');
136
+
137
+ picker.writeValue(date.toISOString());
138
+
139
+ expect(picker.formControl.value).toBeTruthy();
140
+ });
141
+ });
142
+
143
+ describe('selectDateFromCalendar', () => {
144
+ beforeEach(() => {
145
+ spyOn(picker.formControl, 'setValue').and.stub();
146
+ });
147
+
148
+ it('should update the values', () => {
149
+ const date = new Date('2018-01-10T00:00:00+01:00');
150
+ picker.selectDateFromCalendar({
151
+ date,
152
+ complete: true,
153
+ });
154
+
155
+ expect(picker.formControl.setValue).toHaveBeenCalledWith('10/01/2018');
156
+ });
157
+ });
158
+
159
+ describe('validate', () => {
160
+ it('should return null if the control has no value', () => {
161
+ const ctrl = new UntypedFormControl();
162
+
163
+ expect(picker.validate(ctrl)).toEqual(null);
164
+ });
165
+
166
+ it('should return the invalid date error if the date is invalid', () => {
167
+ const ctrl = new UntypedFormControl(false);
168
+
169
+ expect(picker.validate(ctrl)).toEqual({
170
+ format: DATEPICKER_DEFAULT_ERROR_LABELS.ERRORS_INVALID_DATE,
171
+ });
172
+ });
173
+
174
+ it('should return null if the date is valid and no range was set', () => {
175
+ const ctrl = new UntypedFormControl(new Date());
176
+
177
+ expect(picker.validate(ctrl)).toEqual(null);
178
+ });
179
+
180
+ it('should return null if the date is valid and outside of the set range', () => {
181
+ spyOn(picker.calendarService, 'getRangeForDate').and.callFake(() => []);
182
+ picker.range = [1];
183
+
184
+ const ctrl = new UntypedFormControl(new Date().toISOString());
185
+
186
+ expect(picker.validate(ctrl)).toEqual(null);
187
+ });
188
+
189
+ it('should return the invalid range error if the date was valid and in the set range', () => {
190
+ const testDateISO = new Date('2018-01-15T12:00:00Z').toISOString();
191
+ const parsedDate = DateHelper.parseDate(testDateISO);
192
+ const range = [parsedDate.getDate()];
193
+ spyOn(picker.calendarService, 'getRangeForDate').and.callFake(() => range);
194
+ picker.range = range;
195
+
196
+ const ctrl = new UntypedFormControl(testDateISO);
197
+
198
+ expect(picker.validate(ctrl)).toEqual({
199
+ range: DATEPICKER_DEFAULT_ERROR_LABELS.ERRORS_INVALID_RANGE,
200
+ });
201
+ });
202
+ });
203
+ });
204
+ });