ngx-material-entity 0.1.3 → 1.0.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 (163) hide show
  1. package/README.md +914 -336
  2. package/capsulation/lodash.utilities.d.ts +62 -0
  3. package/capsulation/reflect.utilities.d.ts +56 -0
  4. package/classes/{base-builder.class.d.ts → base.builder.d.ts} +2 -1
  5. package/classes/date.utilities.d.ts +70 -0
  6. package/classes/entity.model.d.ts +20 -0
  7. package/classes/entity.service.d.ts +108 -0
  8. package/classes/{entity-utilities.class.d.ts → entity.utilities.d.ts} +52 -16
  9. package/classes/file.utilities.d.ts +52 -0
  10. package/components/confirm-dialog/confirm-dialog-data.builder.d.ts +1 -1
  11. package/components/input/add-array-item-dialog-data.builder.d.ts +4 -4
  12. package/components/input/add-array-item-dialog-data.d.ts +2 -2
  13. package/components/input/array/array-date-input/array-date-input.component.d.ts +11 -0
  14. package/components/input/array/array-date-range-input/array-date-range-input.component.d.ts +20 -0
  15. package/components/input/array/array-date-time-input/array-date-time-input.component.d.ts +22 -0
  16. package/components/input/array/array-string-autocomplete-chips/array-string-autocomplete-chips.component.d.ts +51 -0
  17. package/components/input/array/array-string-chips-input/array-string-chips-input.component.d.ts +44 -0
  18. package/components/input/array/array-table.class.d.ts +49 -0
  19. package/components/input/base-input.component.d.ts +31 -0
  20. package/components/input/boolean/boolean-checkbox-input/boolean-checkbox-input.component.d.ts +10 -0
  21. package/components/input/boolean/boolean-dropdown-input/boolean-dropdown-input.component.d.ts +9 -0
  22. package/components/input/boolean/boolean-toggle-input/boolean-toggle-input.component.d.ts +10 -0
  23. package/components/input/custom/custom.component.d.ts +13 -0
  24. package/components/input/date/date-input/date-input.component.d.ts +13 -0
  25. package/components/input/date/date-range-input/date-range-input.component.d.ts +20 -0
  26. package/components/input/date/date-time-input/date-time-input.component.d.ts +31 -0
  27. package/components/input/file/file-default-input/file-default-input.component.d.ts +13 -0
  28. package/components/input/file/file-image-input/file-image-input.component.d.ts +22 -0
  29. package/components/input/file/file-input/dragDrop.directive.d.ts +32 -0
  30. package/components/input/file/file-input/file-input.component.d.ts +32 -0
  31. package/components/input/input.component.d.ts +49 -73
  32. package/components/input/input.module.d.ts +38 -15
  33. package/components/input/number/number-dropdown-input/number-dropdown-input.component.d.ts +9 -0
  34. package/components/input/number/number-input/number-input.component.d.ts +9 -0
  35. package/components/input/string/string-autocomplete-input/string-autocomplete-input.component.d.ts +18 -0
  36. package/components/input/string/string-dropdown-input/string-dropdown-input.component.d.ts +9 -0
  37. package/components/input/string/string-input/string-input.component.d.ts +9 -0
  38. package/components/input/string/string-textbox-input/string-textbox-input.component.d.ts +9 -0
  39. package/components/table/create-dialog/create-dialog-data.builder.d.ts +1 -1
  40. package/components/table/create-dialog/create-entity-dialog-data.builder.d.ts +5 -5
  41. package/components/table/create-dialog/create-entity-dialog-data.d.ts +3 -3
  42. package/components/table/create-dialog/create-entity-dialog.component.d.ts +9 -5
  43. package/components/table/edit-dialog/edit-dialog-data.builder.d.ts +4 -4
  44. package/components/table/edit-dialog/edit-entity-dialog-data.d.ts +3 -3
  45. package/components/table/edit-dialog/edit-entity-dialog.builder.d.ts +5 -5
  46. package/components/table/edit-dialog/edit-entity-dialog.component.d.ts +7 -5
  47. package/components/table/table-data.builder.d.ts +9 -9
  48. package/components/table/table-data.d.ts +8 -8
  49. package/components/table/table.component.d.ts +2 -2
  50. package/decorators/array/array-decorator-internal.data.d.ts +72 -7
  51. package/decorators/array/array-decorator.data.d.ts +179 -13
  52. package/decorators/array/array.decorator.d.ts +3 -3
  53. package/decorators/base/base-property.decorator.d.ts +2 -3
  54. package/decorators/base/decorator-types.enum.d.ts +15 -4
  55. package/decorators/base/dropdown-value.interface.d.ts +14 -0
  56. package/decorators/custom/custom-decorator-internal.data.d.ts +17 -0
  57. package/decorators/custom/custom-decorator.data.d.ts +33 -0
  58. package/decorators/custom/custom.decorator.d.ts +11 -0
  59. package/decorators/date/date-decorator-internal.data.d.ts +44 -0
  60. package/decorators/date/date-decorator.data.d.ts +129 -0
  61. package/decorators/date/date.decorator.d.ts +8 -0
  62. package/decorators/file/file-decorator-internal.data.d.ts +92 -0
  63. package/decorators/file/file-decorator.data.d.ts +92 -0
  64. package/decorators/file/file.decorator.d.ts +9 -0
  65. package/decorators/number/number-decorator-internal.data.d.ts +2 -4
  66. package/decorators/number/number-decorator.data.d.ts +2 -4
  67. package/decorators/number/number.decorator.d.ts +2 -2
  68. package/decorators/object/object-decorator-internal.data.d.ts +3 -3
  69. package/decorators/object/object-decorator.data.d.ts +5 -5
  70. package/decorators/object/object.decorator.d.ts +2 -2
  71. package/decorators/string/string-decorator-internal.data.d.ts +2 -4
  72. package/decorators/string/string-decorator.data.d.ts +2 -4
  73. package/esm2020/capsulation/lodash.utilities.mjs +75 -0
  74. package/esm2020/capsulation/reflect.utilities.mjs +69 -0
  75. package/esm2020/classes/base.builder.mjs +42 -0
  76. package/esm2020/classes/date.utilities.mjs +158 -0
  77. package/esm2020/classes/entity.model.mjs +23 -0
  78. package/esm2020/classes/entity.service.mjs +180 -0
  79. package/esm2020/classes/entity.utilities.mjs +686 -0
  80. package/esm2020/classes/file.utilities.mjs +123 -0
  81. package/esm2020/components/confirm-dialog/confirm-dialog-data.builder.mjs +5 -5
  82. package/esm2020/components/confirm-dialog/confirm-dialog.component.mjs +3 -3
  83. package/esm2020/components/input/add-array-item-dialog-data.builder.mjs +4 -4
  84. package/esm2020/components/input/add-array-item-dialog-data.mjs +1 -1
  85. package/esm2020/components/input/array/array-date-input/array-date-input.component.mjs +26 -0
  86. package/esm2020/components/input/array/array-date-range-input/array-date-range-input.component.mjs +50 -0
  87. package/esm2020/components/input/array/array-date-time-input/array-date-time-input.component.mjs +50 -0
  88. package/esm2020/components/input/array/array-string-autocomplete-chips/array-string-autocomplete-chips.component.mjs +119 -0
  89. package/esm2020/components/input/array/array-string-chips-input/array-string-chips-input.component.mjs +104 -0
  90. package/esm2020/components/input/array/array-table.class.mjs +107 -0
  91. package/esm2020/components/input/base-input.component.mjs +39 -0
  92. package/esm2020/components/input/boolean/boolean-checkbox-input/boolean-checkbox-input.component.mjs +23 -0
  93. package/esm2020/components/input/boolean/boolean-dropdown-input/boolean-dropdown-input.component.mjs +17 -0
  94. package/esm2020/components/input/boolean/boolean-toggle-input/boolean-toggle-input.component.mjs +23 -0
  95. package/esm2020/components/input/custom/custom.component.mjs +25 -0
  96. package/esm2020/components/input/date/date-input/date-input.component.mjs +23 -0
  97. package/esm2020/components/input/date/date-range-input/date-range-input.component.mjs +51 -0
  98. package/esm2020/components/input/date/date-time-input/date-time-input.component.mjs +63 -0
  99. package/esm2020/components/input/file/file-default-input/file-default-input.component.mjs +24 -0
  100. package/esm2020/components/input/file/file-image-input/file-image-input.component.mjs +79 -0
  101. package/esm2020/components/input/file/file-input/dragDrop.directive.mjs +64 -0
  102. package/esm2020/components/input/file/file-input/file-input.component.mjs +152 -0
  103. package/esm2020/components/input/input.component.mjs +143 -179
  104. package/esm2020/components/input/input.module.mjs +76 -6
  105. package/esm2020/components/input/number/number-dropdown-input/number-dropdown-input.component.mjs +18 -0
  106. package/esm2020/components/input/number/number-input/number-input.component.mjs +16 -0
  107. package/esm2020/components/input/string/string-autocomplete-input/string-autocomplete-input.component.mjs +37 -0
  108. package/esm2020/components/input/string/string-dropdown-input/string-dropdown-input.component.mjs +18 -0
  109. package/esm2020/components/input/string/string-input/string-input.component.mjs +16 -0
  110. package/esm2020/components/input/string/string-textbox-input/string-textbox-input.component.mjs +17 -0
  111. package/esm2020/components/table/create-dialog/create-dialog-data.builder.mjs +3 -3
  112. package/esm2020/components/table/create-dialog/create-entity-dialog-data.builder.mjs +2 -2
  113. package/esm2020/components/table/create-dialog/create-entity-dialog-data.mjs +1 -1
  114. package/esm2020/components/table/create-dialog/create-entity-dialog.component.mjs +16 -9
  115. package/esm2020/components/table/edit-dialog/edit-dialog-data.builder.mjs +3 -3
  116. package/esm2020/components/table/edit-dialog/edit-entity-dialog-data.mjs +1 -1
  117. package/esm2020/components/table/edit-dialog/edit-entity-dialog.builder.mjs +3 -3
  118. package/esm2020/components/table/edit-dialog/edit-entity-dialog.component.mjs +19 -11
  119. package/esm2020/components/table/table-data.builder.mjs +4 -4
  120. package/esm2020/components/table/table-data.mjs +1 -1
  121. package/esm2020/components/table/table.component.mjs +21 -23
  122. package/esm2020/decorators/array/array-decorator-internal.data.mjs +102 -14
  123. package/esm2020/decorators/array/array-decorator.data.mjs +2 -2
  124. package/esm2020/decorators/array/array.decorator.mjs +8 -2
  125. package/esm2020/decorators/base/base-property.decorator.mjs +4 -3
  126. package/esm2020/decorators/base/decorator-types.enum.mjs +10 -1
  127. package/esm2020/decorators/base/dropdown-value.interface.mjs +2 -0
  128. package/esm2020/decorators/base/property-decorator-internal.data.mjs +10 -10
  129. package/esm2020/decorators/base/property-decorator.data.mjs +1 -1
  130. package/esm2020/decorators/boolean/boolean-decorator-internal.data.mjs +3 -3
  131. package/esm2020/decorators/custom/custom-decorator-internal.data.mjs +26 -0
  132. package/esm2020/decorators/custom/custom-decorator.data.mjs +2 -0
  133. package/esm2020/decorators/custom/custom.decorator.mjs +13 -0
  134. package/esm2020/decorators/date/date-decorator-internal.data.mjs +48 -0
  135. package/esm2020/decorators/date/date-decorator.data.mjs +7 -0
  136. package/esm2020/decorators/date/date.decorator.mjs +21 -0
  137. package/esm2020/decorators/file/file-decorator-internal.data.mjs +98 -0
  138. package/esm2020/decorators/file/file-decorator.data.mjs +7 -0
  139. package/esm2020/decorators/file/file.decorator.mjs +22 -0
  140. package/esm2020/decorators/number/number-decorator-internal.data.mjs +1 -1
  141. package/esm2020/decorators/number/number-decorator.data.mjs +1 -1
  142. package/esm2020/decorators/number/number.decorator.mjs +3 -3
  143. package/esm2020/decorators/object/object-decorator-internal.data.mjs +2 -2
  144. package/esm2020/decorators/object/object-decorator.data.mjs +1 -1
  145. package/esm2020/decorators/object/object.decorator.mjs +1 -1
  146. package/esm2020/decorators/string/string-decorator-internal.data.mjs +1 -1
  147. package/esm2020/decorators/string/string-decorator.data.mjs +1 -1
  148. package/esm2020/decorators/string/string.decorator.mjs +1 -1
  149. package/esm2020/mocks/placeholder-data.png.mjs +3 -0
  150. package/esm2020/public-api.mjs +15 -5
  151. package/fesm2015/ngx-material-entity.mjs +2649 -422
  152. package/fesm2015/ngx-material-entity.mjs.map +1 -1
  153. package/fesm2020/ngx-material-entity.mjs +2537 -397
  154. package/fesm2020/ngx-material-entity.mjs.map +1 -1
  155. package/mocks/placeholder-data.png.d.ts +1 -0
  156. package/package.json +7 -1
  157. package/public-api.d.ts +15 -4
  158. package/classes/entity-model.class.d.ts +0 -9
  159. package/classes/entity-service.class.d.ts +0 -66
  160. package/esm2020/classes/base-builder.class.mjs +0 -43
  161. package/esm2020/classes/entity-model.class.mjs +0 -19
  162. package/esm2020/classes/entity-service.class.mjs +0 -76
  163. package/esm2020/classes/entity-utilities.class.mjs +0 -377
@@ -1,43 +1,114 @@
1
1
  import 'reflect-metadata';
2
2
  import { __decorate, __metadata } from 'tslib';
3
+ import { isEqual, cloneDeep, omit, isNil, omitBy, isArray } from 'lodash';
3
4
  import { BehaviorSubject, firstValueFrom, Subject, takeUntil } from 'rxjs';
4
- import { isEqual, omit, omitBy, isNil, cloneDeep } from 'lodash';
5
5
  import * as i0 from '@angular/core';
6
- import { Component, Inject, NgModule, Input, ViewChild } from '@angular/core';
6
+ import { Component, Inject, NgModule, EventEmitter, Input, Output, Directive, HostListener, ViewChild } from '@angular/core';
7
7
  import * as i1 from '@angular/material/dialog';
8
8
  import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
9
- import * as i6 from '@angular/material/checkbox';
9
+ import * as i2 from '@angular/material/checkbox';
10
10
  import { MatCheckboxModule } from '@angular/material/checkbox';
11
11
  import * as i3 from '@angular/material/button';
12
12
  import { MatButtonModule } from '@angular/material/button';
13
- import * as i11 from '@angular/common';
13
+ import * as i4 from '@angular/common';
14
14
  import { CommonModule } from '@angular/common';
15
- import * as i13 from '@angular/forms';
15
+ import * as i3$1 from '@angular/forms';
16
16
  import { FormsModule } from '@angular/forms';
17
- import * as i9 from '@angular/material/table';
17
+ import * as i4$2 from '@angular/material/table';
18
18
  import { MatTableDataSource, MatTableModule } from '@angular/material/table';
19
19
  import { SelectionModel } from '@angular/cdk/collections';
20
- import * as i2 from '@angular/material/form-field';
20
+ import * as i1$1 from '@angular/material/form-field';
21
21
  import { MatFormFieldModule } from '@angular/material/form-field';
22
- import * as i3$1 from '@angular/material/autocomplete';
22
+ import * as i4$1 from '@angular/material/input';
23
+ import { MatInputModule } from '@angular/material/input';
24
+ import * as i3$2 from '@angular/cdk/text-field';
25
+ import * as i2$1 from '@angular/material/autocomplete';
23
26
  import { MatAutocompleteModule } from '@angular/material/autocomplete';
24
- import * as i4 from '@angular/material/core';
25
- import * as i5 from '@angular/material/select';
27
+ import * as i3$3 from '@angular/material/core';
28
+ import * as i2$2 from '@angular/material/select';
26
29
  import { MatSelectModule } from '@angular/material/select';
27
- import * as i7 from '@angular/material/slide-toggle';
30
+ import * as i2$3 from '@angular/material/slide-toggle';
28
31
  import { MatSlideToggleModule } from '@angular/material/slide-toggle';
29
- import * as i10 from '@angular/material/chips';
32
+ import * as i2$4 from '@angular/material/datepicker';
33
+ import { MatDatepickerModule } from '@angular/material/datepicker';
34
+ import * as i2$5 from '@angular/material/chips';
30
35
  import { MatChipsModule } from '@angular/material/chips';
31
- import * as i12 from '@angular/material/input';
32
- import { MatInputModule } from '@angular/material/input';
33
- import * as i14 from '@angular/cdk/text-field';
34
36
  import { MatIconModule } from '@angular/material/icon';
35
- import * as i7$1 from '@angular/material/paginator';
37
+ import * as i7 from '@angular/material/paginator';
36
38
  import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
37
39
  import { MatSort } from '@angular/material/sort';
38
- import * as i4$1 from '@angular/material/menu';
40
+ import * as i4$3 from '@angular/material/menu';
39
41
  import { MatMenuModule } from '@angular/material/menu';
40
42
 
43
+ /**
44
+ * Encapsulates all functionality of Reflect.
45
+ */
46
+ class ReflectUtilities {
47
+ /**
48
+ * Gets the metadata value for the provided metadata key on the target object or its prototype chain.
49
+ *
50
+ * @param metadataKey - A key used to store and retrieve metadata.
51
+ * @param target - The target object on which the metadata is defined.
52
+ * @param propertyKey - The property key for the target.
53
+ * @returns The metadata value for the metadata key if found; otherwise, undefined.
54
+ */
55
+ static getMetadata(metadataKey, target, propertyKey) {
56
+ return Reflect.getMetadata(metadataKey, target, propertyKey);
57
+ }
58
+ /**
59
+ * Returns the string and symbol keys of the own properties of an object. The own properties of an object
60
+ * are those that are defined directly on that object, and are not inherited from the object's prototype.
61
+ *
62
+ * @param target - Object that contains the own properties.
63
+ * @returns The keys of the given object.
64
+ */
65
+ static ownKeys(target) {
66
+ return Reflect.ownKeys(target);
67
+ }
68
+ /**
69
+ * Gets the property of target, equivalent to `target[propertyKey]`.
70
+ *
71
+ * @param target - Object that contains the property on itself or in its prototype chain.
72
+ * @param propertyKey - The property name.
73
+ * @returns The property of the target of the given key.
74
+ */
75
+ static get(target, propertyKey) {
76
+ return Reflect.get(target, propertyKey);
77
+ }
78
+ /**
79
+ * Sets the property of target, equivalent to `target[propertyKey] = value`.
80
+ *
81
+ * @param target - Object that contains the property on itself or in its prototype chain.
82
+ * @param propertyKey - The property name.
83
+ * @param value - The value to set the property to.
84
+ * @returns If setting the value was successful.
85
+ */
86
+ static set(target, propertyKey, value) {
87
+ return Reflect.set(target, propertyKey, value);
88
+ }
89
+ /**
90
+ * Equivalent to `propertyKey in target`.
91
+ *
92
+ * @param target - Object that contains the property on itself or in its prototype chain.
93
+ * @param propertyKey - Name of the property.
94
+ * @returns Whether or not the given target has the key.
95
+ */
96
+ static has(target, propertyKey) {
97
+ return Reflect.has(target, propertyKey);
98
+ }
99
+ /**
100
+ * Define a unique metadata entry on the target.
101
+ *
102
+ * @param metadataKey - A key used to store and retrieve metadata.
103
+ * @param metadataValue - A value that contains attached metadata.
104
+ * @param target - The target object on which to define metadata.
105
+ * @param propertyKey - The property key for the target.
106
+ */
107
+ static defineMetadata(metadataKey, metadataValue, target, propertyKey) {
108
+ Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey);
109
+ }
110
+ }
111
+
41
112
  /**
42
113
  * The base decorator for setting metadata on properties.
43
114
  *
@@ -47,8 +118,8 @@ import { MatMenuModule } from '@angular/material/menu';
47
118
  */
48
119
  function baseProperty(metadata, type) {
49
120
  return function (target, propertyKey) {
50
- Reflect.defineMetadata('metadata', metadata, target, propertyKey);
51
- Reflect.defineMetadata('type', type, target, propertyKey);
121
+ ReflectUtilities.defineMetadata('metadata', metadata, target, propertyKey);
122
+ ReflectUtilities.defineMetadata('type', type, target, propertyKey);
52
123
  };
53
124
  }
54
125
 
@@ -68,8 +139,17 @@ var DecoratorTypes;
68
139
  DecoratorTypes["BOOLEAN_DROPDOWN"] = "booleanDropdown";
69
140
  DecoratorTypes["OBJECT"] = "object";
70
141
  DecoratorTypes["ARRAY"] = "array";
142
+ DecoratorTypes["ARRAY_DATE"] = "arrayDate";
143
+ DecoratorTypes["ARRAY_DATE_TIME"] = "arrayDateTime";
144
+ DecoratorTypes["ARRAY_DATE_RANGE"] = "arrayDateRange";
71
145
  DecoratorTypes["ARRAY_STRING_CHIPS"] = "arrayStringChips";
72
146
  DecoratorTypes["ARRAY_STRING_AUTOCOMPLETE_CHIPS"] = "arrayStringAutocompleteChips";
147
+ DecoratorTypes["DATE"] = "date";
148
+ DecoratorTypes["DATE_RANGE"] = "dateRange";
149
+ DecoratorTypes["DATE_TIME"] = "dateTime";
150
+ DecoratorTypes["FILE_DEFAULT"] = "fileDefault";
151
+ DecoratorTypes["FILE_IMAGE"] = "fileImage";
152
+ DecoratorTypes["CUSTOM"] = "custom";
73
153
  })(DecoratorTypes || (DecoratorTypes = {}));
74
154
 
75
155
  /**
@@ -78,11 +158,11 @@ var DecoratorTypes;
78
158
  class PositionInternal {
79
159
  constructor(data) {
80
160
  this.validateInput(data);
81
- this.row = data?.row ? data.row : -1;
82
- this.order = data?.order ? data.order : -1;
161
+ this.row = data?.row ?? -1;
162
+ this.order = data?.order ?? -1;
83
163
  }
84
164
  validateInput(data) {
85
- if (data?.order) {
165
+ if (data?.order != null) {
86
166
  if (data.order < 1) {
87
167
  throw new Error('order must be at least 1');
88
168
  }
@@ -90,7 +170,7 @@ class PositionInternal {
90
170
  throw new Error('order cannot be bigger than 12 (the minimum value for a bootstrap column)');
91
171
  }
92
172
  }
93
- if (data?.row && (data.row < 1)) {
173
+ if (data?.row != null && data.row < 1) {
94
174
  throw new Error('row must be at least 1');
95
175
  }
96
176
  }
@@ -100,12 +180,12 @@ class PositionInternal {
100
180
  */
101
181
  class PropertyDecoratorConfigInternal {
102
182
  constructor(data) {
103
- this.display = data.display != undefined ? data.display : true;
183
+ this.display = data.display ?? true;
104
184
  this.displayName = data.displayName;
105
- this.required = data.required != undefined ? data.required : true;
106
- this.omitForCreate = data.omitForCreate != undefined ? data.omitForCreate : false;
107
- this.omitForUpdate = data.omitForUpdate != undefined ? data.omitForUpdate : false;
108
- this.defaultWidths = data.defaultWidths ? data.defaultWidths : [6, 6, 12];
185
+ this.required = data.required ?? true;
186
+ this.omitForCreate = data.omitForCreate ?? false;
187
+ this.omitForUpdate = data.omitForUpdate ?? false;
188
+ this.defaultWidths = data.defaultWidths ?? [6, 6, 12];
109
189
  this.position = new PositionInternal(data.position);
110
190
  }
111
191
  }
@@ -179,23 +259,359 @@ function string(metadata) {
179
259
  }
180
260
 
181
261
  /**
182
- * The base Entity class.
262
+ * Encapsulates all functionality of lodash.
183
263
  */
184
- class Entity {
264
+ class LodashUtilities {
265
+ /**
266
+ * Performs a deep comparison between two values to determine if they are
267
+ * equivalent.
268
+ *
269
+ * **Note:** This method supports comparing arrays, array buffers, booleans,
270
+ * date objects, error objects, maps, numbers, `Object` objects, regexps,
271
+ * sets, strings, symbols, and typed arrays. `Object` objects are compared
272
+ * by their own, not inherited, enumerable properties. Functions and DOM
273
+ * nodes are **not** supported.
274
+ *
275
+ * @param value - The value to compare.
276
+ * @param other - The other value to compare.
277
+ * @returns Returns `true` if the values are equivalent, else `false`.
278
+ */
279
+ static isEqual(value, other) {
280
+ return isEqual(value, other);
281
+ }
282
+ /**
283
+ * This method is like _.clone except that it recursively clones value.
284
+ *
285
+ * @param value - The value to recursively clone.
286
+ * @returns Returns the deep cloned value.
287
+ */
288
+ static cloneDeep(value) {
289
+ return cloneDeep(value);
290
+ }
291
+ /**
292
+ * The opposite of `_.pick`; this method creates an object composed of the
293
+ * own and inherited enumerable properties of `object` that are not omitted.
294
+ *
295
+ * @param object - The source object.
296
+ * @param paths - The property names to omit, specified
297
+ * individually or in arrays.
298
+ * @returns Returns the new object.
299
+ */
300
+ static omit(object, ...paths) {
301
+ return omit(object, ...paths);
302
+ }
303
+ /**
304
+ * Checks if `value` is `null` or `undefined`.
305
+ *
306
+ * @param value - The value to check.
307
+ * @returns Returns `true` if `value` is nullish, else `false`.
308
+ */
309
+ static isNil(value) {
310
+ return isNil(value);
311
+ }
312
+ /**
313
+ * The opposite of `_.pickBy`; this method creates an object composed of the
314
+ * own and inherited enumerable properties of `object` that `predicate`
315
+ * doesn't return truthy for.
316
+ *
317
+ * @param object - The source object.
318
+ * @param predicate - The function invoked per property.
319
+ * @returns Returns the new object.
320
+ */
321
+ static omitBy(object, predicate) {
322
+ return omitBy(object, predicate);
323
+ }
324
+ /**
325
+ * Checks if value is classified as an Array object.
326
+ *
327
+ * @param value - The value to check.
328
+ * @returns Returns true if value is correctly classified, else false.
329
+ */
330
+ static isArray(value) {
331
+ return isArray(value);
332
+ }
333
+ }
334
+
335
+ const DAY_IN_MS = 1000 * 60 * 60 * 24;
336
+ /**
337
+ * Contains Helper Functions for handling date properties.
338
+ */
339
+ class DateUtilities {
340
+ /**
341
+ * Gets the given value as a date value.
342
+ *
343
+ * @param value - The value to get as a date.
344
+ * @returns The given value as a date.
345
+ */
346
+ static asDate(value) {
347
+ return value;
348
+ }
349
+ /**
350
+ * Gets the default times used by the DateTime picker when nothing is specified by the user.
351
+ *
352
+ * @param format - The time format. Defaults to 24.
353
+ * @param minuteSteps - The steps from one time value to the next. Defaults to 30.
354
+ * @returns Times in the 24 hour format from 0:00 until 23:30 in 30 minute steps.
355
+ */
356
+ static getDefaultTimes(format = 24, minuteSteps = 30) {
357
+ const res = [{ displayName: '-', value: undefined }];
358
+ for (let hour = 0; hour < 24; hour++) {
359
+ for (let minute = 0; minute < 60; minute += minuteSteps) {
360
+ res.push(DateUtilities.getTimeDropdownValue(format, hour, minute));
361
+ }
362
+ }
363
+ return res;
364
+ }
365
+ static getTimeDropdownValue(format, hour, minute) {
366
+ const displayHour = DateUtilities.getFormattedHour(format, LodashUtilities.cloneDeep(hour));
367
+ const displayMinute = DateUtilities.getFormattedMinute(format, hour, minute);
368
+ return {
369
+ displayName: `${displayHour}:${displayMinute}`,
370
+ value: {
371
+ hours: hour,
372
+ minutes: minute
373
+ }
374
+ };
375
+ }
376
+ static getFormattedHour(format, hour) {
377
+ if (format === 12 && hour > 12) {
378
+ hour -= 12;
379
+ }
380
+ return hour;
381
+ }
382
+ static getFormattedMinute(format, hour, minute) {
383
+ let res = `${minute}`;
384
+ if (format === 12) {
385
+ if (hour > 12) {
386
+ res = `${minute} PM`;
387
+ }
388
+ else {
389
+ res = `${minute} AM`;
390
+ }
391
+ }
392
+ if (minute.toString().length === 1) {
393
+ res = '0'.concat(res);
394
+ }
395
+ return res;
396
+ }
397
+ /**
398
+ * Gets the Time object from the given date.
399
+ *
400
+ * @param value - The date to get the time object from.
401
+ * @returns The Time object build from the date value.
402
+ */
403
+ static getTimeFromDate(value) {
404
+ if (!value) {
405
+ return undefined;
406
+ }
407
+ else {
408
+ return {
409
+ hours: new Date(value).getHours(),
410
+ minutes: new Date(value).getMinutes()
411
+ };
412
+ }
413
+ }
414
+ /**
415
+ * Gets the dates between the two given gates. Does additional filtering based on the provided DateRange metadata.
416
+ *
417
+ * @param startDate - The start date.
418
+ * @param endDate - The end date.
419
+ * @param filter - The custom filter from the metadata.
420
+ * @returns All dates between the two provided dates. Includes start and end date.
421
+ */
422
+ static getDatesBetween(startDate, endDate, filter) {
423
+ const res = [];
424
+ while (startDate.getFullYear() < endDate.getFullYear()
425
+ || startDate.getMonth() < endDate.getMonth()
426
+ || startDate.getDate() <= endDate.getDate()) {
427
+ res.push(new Date(startDate));
428
+ startDate.setTime(startDate.getTime() + DAY_IN_MS);
429
+ }
430
+ if (filter) {
431
+ return res.filter(d => filter(d));
432
+ }
433
+ else {
434
+ return res;
435
+ }
436
+ }
437
+ /**
438
+ * Get all valid times for the dropdown of a datetime property.
439
+ *
440
+ * @param date - The date of the datetime.
441
+ * @param times - All given times to filter.
442
+ * @param min - The function that defines the minimum time.
443
+ * @param max - The function that defines the maximum time.
444
+ * @param filter - A filter function to do more specific time filtering. This could be e.g. The removal of lunch breaks.
445
+ * @returns All valid dropdown values for the datetime property.
446
+ */
447
+ static getValidTimesForDropdown(date, times, min, max, filter) {
448
+ if (min) {
449
+ const minTime = min(date);
450
+ times = times.filter(t => !t.value
451
+ || t.value.hours > minTime.hours
452
+ || (t.value.hours === minTime.hours
453
+ && t.value.minutes >= minTime.minutes));
454
+ }
455
+ if (max) {
456
+ const maxTime = max(date);
457
+ times = times.filter(t => !t.value
458
+ || t.value.hours < maxTime.hours
459
+ || (t.value.hours === maxTime.hours
460
+ && t.value.minutes <= maxTime.minutes));
461
+ }
462
+ if (filter) {
463
+ times = times.filter(t => !t.value || filter(t.value));
464
+ }
465
+ return times;
466
+ }
467
+ /**
468
+ * Checks if the time object has processable hours and minutes properties.
469
+ * Doesn't check custom validators like min/max from the metadata configuration.
470
+ *
471
+ * @param time - The time to check.
472
+ * @returns Whether or not the time object is unprocessable.
473
+ */
474
+ static timeIsUnprocessable(time) {
475
+ if (!time
476
+ || time.hours == null
477
+ || typeof time.hours !== 'number'
478
+ || Number.isNaN(time.hours)
479
+ || time.minutes == null
480
+ || typeof time.minutes !== 'number'
481
+ || Number.isNaN(time.minutes)) {
482
+ return true;
483
+ }
484
+ return false;
485
+ }
486
+ }
487
+ /**
488
+ * The default filter function to user when none was provided by the user.
489
+ */
490
+ DateUtilities.defaultDateFilter = () => true;
491
+
492
+ /**
493
+ * Provides functionality regarding files.
494
+ */
495
+ class FileUtilities {
496
+ /**
497
+ * Gets the accept value for the html input.
498
+ *
499
+ * @param mimeTypes - The mimeTypes to get the accept string from.
500
+ * @returns A comma separated string of all the provided mime types.
501
+ */
502
+ static getAcceptString(mimeTypes) {
503
+ if (!mimeTypes?.length) {
504
+ return '*';
505
+ }
506
+ return mimeTypes.join(', ');
507
+ }
508
+ // TODO: Find a way to use blobs with jest
509
+ /* istanbul ignore next */
510
+ /**
511
+ * Reads a url to display the given file.
512
+ *
513
+ * @param file - The file to get the url from.
514
+ * @returns A promise of the url. Undefined if no file was provided.
515
+ */
516
+ static async getDataURLFromFile(file) {
517
+ if (!file) {
518
+ return undefined;
519
+ }
520
+ return new Promise((resolve, reject) => {
521
+ const reader = new FileReader();
522
+ reader.onload = e => resolve(e.target?.result);
523
+ reader.onerror = e => reject(e);
524
+ reader.readAsDataURL(file);
525
+ });
526
+ }
527
+ // TODO: Find a way to use blobs with jest
528
+ /* istanbul ignore next */
529
+ /**
530
+ * Gets a file from the given url.
531
+ *
532
+ * @param url - The url to get the file from.
533
+ * @returns A promise of the File.
534
+ */
535
+ static async getFileFromUrl(url) {
536
+ const res = await fetch(url);
537
+ if (!res.ok) {
538
+ // TODO make error more robust
539
+ throw new Error(`Error fetching the file from the url ${url}`);
540
+ }
541
+ return await res.blob();
542
+ }
543
+ // TODO: Find a way to use blobs with jest
544
+ /* istanbul ignore next */
545
+ /**
546
+ * Gets the file data with the blob from the given File Data.
547
+ *
548
+ * @param data - The File Data to get the file data with blob from.
549
+ * @returns FileDataWithFile.
550
+ */
551
+ static async getFileData(data) {
552
+ if (data.file) {
553
+ return {
554
+ file: data.file,
555
+ name: data.name,
556
+ url: data.url,
557
+ type: data.type,
558
+ size: data.size
559
+ };
560
+ }
561
+ else {
562
+ return {
563
+ file: await FileUtilities.getFileFromUrl(data.url),
564
+ name: data.name,
565
+ url: data.url,
566
+ type: data.type,
567
+ size: data.size
568
+ };
569
+ }
570
+ }
571
+ /**
572
+ * Checks if the given file has a valid mime type.
573
+ *
574
+ * @param type - The type of the file to check.
575
+ * @param allowedMimeTypes - The allowed mime types.
576
+ * @returns Whether or not the given file has a valid mime type.
577
+ */
578
+ static isMimeTypeValid(type, allowedMimeTypes) {
579
+ if (allowedMimeTypes.includes('*')) {
580
+ return true;
581
+ }
582
+ for (const t of allowedMimeTypes) {
583
+ if (t === type) {
584
+ return true;
585
+ }
586
+ if (t.endsWith('*') && type.startsWith(t.split('*')[0])) {
587
+ return true;
588
+ }
589
+ }
590
+ return false;
591
+ }
592
+ /**
593
+ * Transform the given value to Megabytes.
594
+ *
595
+ * @param value - The original value.
596
+ * @param unit - If the value is B, KB or GB.
597
+ * @returns The given value as bytes.
598
+ */
599
+ static transformToMegaBytes(value, unit) {
600
+ const bytes = this.transformToBytes(value, unit);
601
+ return bytes / 1000000;
602
+ }
603
+ static transformToBytes(value, unit) {
604
+ switch (unit) {
605
+ case 'B':
606
+ return value;
607
+ case 'KB':
608
+ return value * 1000;
609
+ case 'GB':
610
+ return value * 1000000000;
611
+ }
612
+ }
185
613
  }
186
- __decorate([
187
- string({
188
- omitForCreate: true,
189
- omitForUpdate: true,
190
- display: false,
191
- displayStyle: 'line',
192
- displayName: 'ID',
193
- required: true
194
- }),
195
- __metadata("design:type", String)
196
- ], Entity.prototype, "id", void 0);
197
614
 
198
- var _a;
199
615
  /**
200
616
  * Contains HelperMethods around handling Entities and their property-metadata.
201
617
  */
@@ -232,6 +648,26 @@ class EntityUtilities {
232
648
  }
233
649
  return res;
234
650
  }
651
+ /**
652
+ * Gets all properties on the given entity which are files.
653
+ *
654
+ * @param entity - The entity to check for file properties.
655
+ * @param omit - Whether to leave out values that are omitted for create or delete.
656
+ * @returns The keys of all file properties on the given entity.
657
+ */
658
+ static getFileProperties(entity, omit) {
659
+ const res = [];
660
+ for (const key of EntityUtilities.keysOf(entity)) {
661
+ const type = EntityUtilities.getPropertyType(entity, key);
662
+ if (type === DecoratorTypes.FILE_DEFAULT || type === DecoratorTypes.FILE_IMAGE) {
663
+ const metadata = EntityUtilities.getPropertyMetadata(entity, key);
664
+ if (!(metadata.omitForCreate && omit === 'create') && !(metadata.omitForUpdate && omit === 'update')) {
665
+ res.push(key);
666
+ }
667
+ }
668
+ }
669
+ return res;
670
+ }
235
671
  /**
236
672
  * Gets the metadata included in an property.
237
673
  *
@@ -244,16 +680,11 @@ class EntityUtilities {
244
680
  static getPropertyMetadata(entity, propertyKey,
245
681
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
246
682
  type) {
247
- try {
248
- const metadata = Reflect.getMetadata('metadata', entity, propertyKey);
249
- if (!metadata) {
250
- throw new Error(`Could not find metadata for property ${String(propertyKey)} on the entity ${JSON.stringify(entity)}`);
251
- }
252
- return metadata;
253
- }
254
- catch (error) {
683
+ const metadata = ReflectUtilities.getMetadata('metadata', entity, propertyKey);
684
+ if (metadata == null) {
255
685
  throw new Error(`Could not find metadata for property ${String(propertyKey)} on the entity ${JSON.stringify(entity)}`);
256
686
  }
687
+ return metadata;
257
688
  }
258
689
  /**
259
690
  * Gets the type of the property-metadata.
@@ -265,8 +696,8 @@ class EntityUtilities {
265
696
  */
266
697
  static getPropertyType(entity, propertyKey) {
267
698
  try {
268
- const propertyType = Reflect.getMetadata('type', entity, propertyKey);
269
- if (!propertyType) {
699
+ const propertyType = ReflectUtilities.getMetadata('type', entity, propertyKey);
700
+ if (propertyType == null) {
270
701
  throw new Error(`Could not find type metadata for property ${String(propertyKey)} on the entity ${JSON.stringify(entity)}`);
271
702
  }
272
703
  return propertyType;
@@ -287,13 +718,11 @@ class EntityUtilities {
287
718
  static new(target, entity) {
288
719
  for (const key in target) {
289
720
  const type = EntityUtilities.getPropertyType(target, key);
290
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
291
- let value = entity ? Reflect.get(entity, key) : undefined;
721
+ let value = entity ? ReflectUtilities.get(entity, key) : undefined;
292
722
  switch (type) {
293
723
  case DecoratorTypes.OBJECT:
294
724
  const objectMetadata = EntityUtilities.getPropertyMetadata(target, key, DecoratorTypes.OBJECT);
295
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
296
- value = new objectMetadata.type(value);
725
+ value = new objectMetadata.EntityClass(value);
297
726
  break;
298
727
  case DecoratorTypes.ARRAY:
299
728
  const inputArray = value;
@@ -310,7 +739,7 @@ class EntityUtilities {
310
739
  default:
311
740
  break;
312
741
  }
313
- Reflect.set(target, key, value);
742
+ ReflectUtilities.set(target, key, value);
314
743
  }
315
744
  }
316
745
  /**
@@ -323,7 +752,7 @@ class EntityUtilities {
323
752
  */
324
753
  static isEntityValid(entity, omit) {
325
754
  for (const key in entity) {
326
- if (!this.isPropertyValid(entity, key, omit)) {
755
+ if (!EntityUtilities.isPropertyValid(entity, key, omit)) {
327
756
  return false;
328
757
  }
329
758
  }
@@ -339,76 +768,107 @@ class EntityUtilities {
339
768
  * @throws Throws when it extracts an unknown metadata type.
340
769
  */
341
770
  static isPropertyValid(entity, key, omit) {
342
- const type = this.getPropertyType(entity, key);
343
- const metadata = this.getPropertyMetadata(entity, key, type);
344
- const metadataDefaultString = metadata;
345
- const metadataTextboxString = metadata;
346
- const metadataDefaultNumber = metadata;
347
- const objectProperty = entity[key];
348
- const metadataEntityArray = metadata;
349
- const arrayItems = entity[key];
771
+ const type = EntityUtilities.getPropertyType(entity, key);
772
+ const metadata = EntityUtilities.getPropertyMetadata(entity, key, type);
350
773
  if (metadata.omitForCreate && omit === 'create') {
351
774
  return true;
352
775
  }
353
776
  if (metadata.omitForUpdate && omit === 'update') {
354
777
  return true;
355
778
  }
356
- if (metadata.required && !entity[key]) {
779
+ if (metadata.required && entity[key] == null) {
357
780
  return false;
358
781
  }
359
782
  switch (type) {
360
783
  case DecoratorTypes.BOOLEAN_DROPDOWN:
784
+ break;
361
785
  case DecoratorTypes.BOOLEAN_CHECKBOX:
362
786
  case DecoratorTypes.BOOLEAN_TOGGLE:
363
- return true;
787
+ const entityBoolean = entity[key];
788
+ const booleanMetadata = metadata;
789
+ if (!EntityUtilities.isBooleanValid(entityBoolean, booleanMetadata)) {
790
+ return false;
791
+ }
792
+ break;
364
793
  case DecoratorTypes.STRING_DROPDOWN:
365
- return true;
794
+ break;
366
795
  case DecoratorTypes.STRING:
367
796
  case DecoratorTypes.STRING_AUTOCOMPLETE:
368
- if (metadataDefaultString.maxLength
369
- && entity[key].length > metadataDefaultString.maxLength) {
370
- return false;
371
- }
372
- if (metadataDefaultString.minLength
373
- && entity[key].length < metadataDefaultString.minLength) {
374
- return false;
375
- }
376
- if (metadataDefaultString.regex
377
- && !entity[key].match(metadataDefaultString.regex)) {
797
+ const entityString = entity[key];
798
+ const stringMetadata = metadata;
799
+ if (!EntityUtilities.isStringValid(entityString, stringMetadata)) {
378
800
  return false;
379
801
  }
380
802
  break;
381
803
  case DecoratorTypes.STRING_TEXTBOX:
382
- if (metadataTextboxString.maxLength
383
- && entity[key].length > metadataTextboxString.maxLength) {
384
- return false;
385
- }
386
- if (metadataTextboxString.minLength
387
- && entity[key].length < metadataTextboxString.minLength) {
804
+ const entityTextbox = entity[key];
805
+ const textboxMetadata = metadata;
806
+ if (!EntityUtilities.isTextboxValid(entityTextbox, textboxMetadata)) {
388
807
  return false;
389
808
  }
390
809
  break;
391
810
  case DecoratorTypes.NUMBER_DROPDOWN:
392
811
  return true;
393
812
  case DecoratorTypes.NUMBER:
394
- if (metadataDefaultNumber.max && entity[key] > metadataDefaultNumber.max) {
395
- return false;
396
- }
397
- if (metadataDefaultNumber.min && entity[key] < metadataDefaultNumber.min) {
813
+ const entityNumber = entity[key];
814
+ const numberMetadata = metadata;
815
+ if (!EntityUtilities.isNumberValid(entityNumber, numberMetadata)) {
398
816
  return false;
399
817
  }
400
818
  break;
401
819
  case DecoratorTypes.OBJECT:
402
- for (const parameterKey in objectProperty) {
403
- if (!this.isPropertyValid(objectProperty, parameterKey, omit)) {
820
+ const entityObject = entity[key];
821
+ for (const parameterKey in entityObject) {
822
+ if (!EntityUtilities.isPropertyValid(entityObject, parameterKey, omit)) {
404
823
  return false;
405
824
  }
406
825
  }
407
826
  break;
408
827
  case DecoratorTypes.ARRAY_STRING_CHIPS:
409
828
  case DecoratorTypes.ARRAY_STRING_AUTOCOMPLETE_CHIPS:
829
+ case DecoratorTypes.ARRAY_DATE:
830
+ case DecoratorTypes.ARRAY_DATE_TIME:
831
+ case DecoratorTypes.ARRAY_DATE_RANGE:
410
832
  case DecoratorTypes.ARRAY:
411
- if (metadataEntityArray.required && !arrayItems.length) {
833
+ const entityArray = entity[key];
834
+ const arrayMetadata = metadata;
835
+ if (arrayMetadata.required && !entityArray.length) {
836
+ return false;
837
+ }
838
+ break;
839
+ case DecoratorTypes.DATE:
840
+ const entityDate = new Date(entity[key]);
841
+ const dateMetadata = metadata;
842
+ if (!EntityUtilities.isDateValid(entityDate, dateMetadata)) {
843
+ return false;
844
+ }
845
+ break;
846
+ case DecoratorTypes.DATE_RANGE:
847
+ const entityDateRange = LodashUtilities.cloneDeep(entity[key]);
848
+ const dateRangeMetadata = metadata;
849
+ if (!EntityUtilities.isDateRangeValid(entityDateRange, dateRangeMetadata)) {
850
+ return false;
851
+ }
852
+ break;
853
+ case DecoratorTypes.DATE_TIME:
854
+ const entityDateTime = new Date(entity[key]);
855
+ const dateTimeMetadata = metadata;
856
+ if (!EntityUtilities.isDateTimeValid(entityDateTime, dateTimeMetadata)) {
857
+ return false;
858
+ }
859
+ break;
860
+ case DecoratorTypes.FILE_DEFAULT:
861
+ case DecoratorTypes.FILE_IMAGE:
862
+ const entityFile = entity[key];
863
+ const entityFileMetadata = metadata;
864
+ if (!EntityUtilities.isFileDataValid(entityFile, entityFileMetadata)) {
865
+ return false;
866
+ }
867
+ break;
868
+ case DecoratorTypes.CUSTOM:
869
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
870
+ const customMetadata = metadata;
871
+ if (!customMetadata.isValid(entity[key], omit)) {
412
872
  return false;
413
873
  }
414
874
  break;
@@ -417,51 +877,315 @@ class EntityUtilities {
417
877
  }
418
878
  return true;
419
879
  }
420
- /**
421
- * Checks if an entity is "dirty" (if its values have changed).
422
- *
423
- * @param entity - The entity after all changes.
424
- * @param entityPriorChanges - The entity before the changes.
425
- * @returns Whether or not the entity is dirty.
426
- */
427
- static dirty(entity, entityPriorChanges) {
428
- if (!entityPriorChanges) {
880
+ static isBooleanValid(value, metadata) {
881
+ if (metadata.required && !value) {
429
882
  return false;
430
883
  }
431
- else {
432
- const diff = this.difference(entity, entityPriorChanges);
433
- if (JSON.stringify(diff) === '{}') {
434
- return false;
435
- }
436
- else {
437
- return true;
438
- }
884
+ return true;
885
+ }
886
+ static isStringValid(value, metadata) {
887
+ if (metadata.maxLength && value.length > metadata.maxLength) {
888
+ return false;
889
+ }
890
+ if (metadata.minLength && value.length < metadata.minLength) {
891
+ return false;
439
892
  }
893
+ if (metadata.regex && !value.match(metadata.regex)) {
894
+ return false;
895
+ }
896
+ return true;
440
897
  }
441
- /**
442
- * Compares two Entities and returns their difference in an object.
443
- *
444
- * @param entity - The first entity to compare.
445
- * @param entityPriorChanges - The second entity to compare.
446
- * @returns The difference between the two Entities in form of a Partial.
447
- */
448
- static difference(entity, entityPriorChanges) {
449
- const res = {};
450
- for (const key in entity) {
451
- if (!isEqual(entity[key], entityPriorChanges[key])) {
452
- res[key] = entity[key];
453
- }
898
+ static isTextboxValid(value, metadata) {
899
+ if (metadata.maxLength && value.length > metadata.maxLength) {
900
+ return false;
454
901
  }
455
- return res;
902
+ if (metadata.minLength && value.length < metadata.minLength) {
903
+ return false;
904
+ }
905
+ return true;
456
906
  }
457
- //TODO X Y
458
- /**
907
+ static isNumberValid(value, metadata) {
908
+ if (metadata.max && value > metadata.max) {
909
+ return false;
910
+ }
911
+ if (metadata.min && value < metadata.min) {
912
+ return false;
913
+ }
914
+ return true;
915
+ }
916
+ static isDateValid(value, metadata) {
917
+ if (metadata.min && value.getTime() < metadata.min(value).getTime()) {
918
+ return false;
919
+ }
920
+ if (metadata.max && value.getTime() > metadata.max(value).getTime()) {
921
+ return false;
922
+ }
923
+ if (metadata.filter && !metadata.filter(value)) {
924
+ return false;
925
+ }
926
+ return true;
927
+ }
928
+ static isDateRangeValid(value, metadata) {
929
+ if (metadata.required) {
930
+ if (!value.start) {
931
+ return false;
932
+ }
933
+ if (!value.end) {
934
+ return false;
935
+ }
936
+ }
937
+ value.start = new Date(value.start);
938
+ value.end = new Date(value.end);
939
+ if (metadata.minStart && value.start.getTime() < metadata.minStart(value.start).getTime()) {
940
+ return false;
941
+ }
942
+ if (metadata.maxStart && value.start.getTime() > metadata.maxStart(value.start).getTime()) {
943
+ return false;
944
+ }
945
+ if (metadata.minEnd && value.end.getTime() < metadata.minEnd(value.end).getTime()) {
946
+ return false;
947
+ }
948
+ if (metadata.maxEnd && value.end.getTime() > metadata.maxEnd(value.end).getTime()) {
949
+ return false;
950
+ }
951
+ if (metadata.filter) {
952
+ if (!metadata.filter(value.start)) {
953
+ return false;
954
+ }
955
+ if (!metadata.filter(value.end)) {
956
+ return false;
957
+ }
958
+ if (value.values) {
959
+ for (const date of value.values) {
960
+ if (!metadata.filter(date)) {
961
+ return false;
962
+ }
963
+ }
964
+ }
965
+ }
966
+ return true;
967
+ }
968
+ static isDateTimeValid(value, metadata) {
969
+ if (metadata.minDate && value.getTime() < metadata.minDate(value).getTime()) {
970
+ return false;
971
+ }
972
+ if (metadata.maxDate && value.getTime() > metadata.maxDate(value).getTime()) {
973
+ return false;
974
+ }
975
+ if (metadata.filterDate && !metadata.filterDate(value)) {
976
+ return false;
977
+ }
978
+ const time = {
979
+ hours: value.getHours(),
980
+ minutes: value.getMinutes()
981
+ };
982
+ if (metadata.minTime) {
983
+ const minTime = metadata.minTime(value);
984
+ if (!(time.hours > minTime.hours
985
+ || (time.hours === minTime.hours
986
+ && time.minutes >= minTime.minutes))) {
987
+ return false;
988
+ }
989
+ }
990
+ if (metadata.maxTime) {
991
+ const maxTime = metadata.maxTime(value);
992
+ if (!(time.hours < maxTime.hours
993
+ || (time.hours === maxTime.hours
994
+ && time.minutes <= maxTime.minutes))) {
995
+ return false;
996
+ }
997
+ }
998
+ if (metadata.filterTime) {
999
+ if (!metadata.filterTime(time)) {
1000
+ return false;
1001
+ }
1002
+ }
1003
+ return true;
1004
+ }
1005
+ static isFileDataValid(value, metadata) {
1006
+ const files = metadata.multiple ? value : [value];
1007
+ const maxSize = metadata.maxSize * 1000000;
1008
+ const maxSizeTotal = metadata.maxSizeTotal * 1000000;
1009
+ let fileSizeTotal = 0;
1010
+ // eslint-disable-next-line @typescript-eslint/prefer-for-of
1011
+ for (let i = 0; i < files.length; i++) {
1012
+ if (!files[i].name || !files[i].file && !files[i].url) {
1013
+ return false;
1014
+ }
1015
+ if (!FileUtilities.isMimeTypeValid(files[i].type, metadata.allowedMimeTypes)) {
1016
+ return false;
1017
+ }
1018
+ if (files[i].size > maxSize) {
1019
+ return false;
1020
+ }
1021
+ fileSizeTotal += files[i].size;
1022
+ if (fileSizeTotal > maxSizeTotal) {
1023
+ return false;
1024
+ }
1025
+ }
1026
+ return true;
1027
+ }
1028
+ /**
1029
+ * Checks if an entity is "dirty" (if its values have changed).
1030
+ *
1031
+ * @param entity - The entity after all changes.
1032
+ * @param entityPriorChanges - The entity before the changes.
1033
+ * @returns Whether or not the entity is dirty.
1034
+ */
1035
+ static async dirty(entity, entityPriorChanges) {
1036
+ if (!entityPriorChanges) {
1037
+ return false;
1038
+ }
1039
+ else {
1040
+ const differences = await EntityUtilities.differencesForDirty(entity, entityPriorChanges);
1041
+ return differences.length ? true : false;
1042
+ }
1043
+ }
1044
+ static async differencesForDirty(entity, entityPriorChanges) {
1045
+ const res = [];
1046
+ for (const key in entity) {
1047
+ const metadata = EntityUtilities.getPropertyMetadata(entity, key);
1048
+ const type = EntityUtilities.getPropertyType(entity, key);
1049
+ if (!(await EntityUtilities.isEqual(entity[key], entityPriorChanges[key], metadata, type))) {
1050
+ res.push({
1051
+ key: key,
1052
+ before: entityPriorChanges[key],
1053
+ after: entity[key]
1054
+ });
1055
+ }
1056
+ }
1057
+ return res;
1058
+ }
1059
+ /**
1060
+ * Compares two Entities and returns their difference in an object.
1061
+ *
1062
+ * @param entity - The first entity to compare.
1063
+ * @param entityPriorChanges - The second entity to compare.
1064
+ * @returns The difference between the two Entities in form of a Partial.
1065
+ */
1066
+ static async difference(entity, entityPriorChanges) {
1067
+ const res = {};
1068
+ for (const key in entity) {
1069
+ const metadata = EntityUtilities.getPropertyMetadata(entity, key);
1070
+ const type = EntityUtilities.getPropertyType(entity, key);
1071
+ if (!(await EntityUtilities.isEqual(entity[key], entityPriorChanges[key], metadata, type))) {
1072
+ res[key] = entity[key];
1073
+ }
1074
+ }
1075
+ return res;
1076
+ }
1077
+ /**
1078
+ * Checks if two given values are equal.
1079
+ * It uses the isEqual method from LodashUtilities and extends it with functionality regarding Dates.
1080
+ *
1081
+ * @param value - The updated value.
1082
+ * @param valuePriorChanges - The value before any changes.
1083
+ * @param metadata - The metadata of the property.
1084
+ * @param type - The type of the property.
1085
+ * @returns Whether or not the given values are equal.
1086
+ */
1087
+ static async isEqual(value, valuePriorChanges, metadata, type) {
1088
+ switch (type) {
1089
+ case DecoratorTypes.DATE_RANGE:
1090
+ return EntityUtilities.isEqualDateRange(value, valuePriorChanges, metadata.filter);
1091
+ case DecoratorTypes.DATE:
1092
+ return EntityUtilities.isEqualDate(value, valuePriorChanges);
1093
+ case DecoratorTypes.DATE_TIME:
1094
+ return EntityUtilities.isEqualDateTime(value, valuePriorChanges);
1095
+ case DecoratorTypes.ARRAY_DATE:
1096
+ case DecoratorTypes.ARRAY_DATE_TIME:
1097
+ return EntityUtilities.isEqualArrayDate(value, valuePriorChanges);
1098
+ case DecoratorTypes.ARRAY_DATE_RANGE:
1099
+ return EntityUtilities.isEqualArrayDateRange(value, valuePriorChanges, metadata.filter);
1100
+ case DecoratorTypes.FILE_IMAGE:
1101
+ case DecoratorTypes.FILE_DEFAULT:
1102
+ return EntityUtilities.isEqualFile(value, valuePriorChanges, metadata.multiple);
1103
+ case DecoratorTypes.CUSTOM:
1104
+ // eslint-disable-next-line max-len, @typescript-eslint/no-explicit-any
1105
+ return EntityUtilities.isEqualCustom(value, valuePriorChanges, metadata);
1106
+ default:
1107
+ return LodashUtilities.isEqual(value, valuePriorChanges);
1108
+ }
1109
+ }
1110
+ static isEqualArrayDate(value, valuePriorChanges) {
1111
+ const newValue = value.map(v => new Date(v)).sort();
1112
+ const newValuePriorChanges = valuePriorChanges.map(v => new Date(v)).sort();
1113
+ return LodashUtilities.isEqual(newValue, newValuePriorChanges);
1114
+ }
1115
+ static isEqualArrayDateRange(value, valuePriorChanges, filter) {
1116
+ const dateRanges = value.sort();
1117
+ const dateRangesPriorChanges = valuePriorChanges.sort();
1118
+ if (dateRanges.length !== dateRangesPriorChanges.length) {
1119
+ return false;
1120
+ }
1121
+ for (let i = 0; i < dateRanges.length; i++) {
1122
+ if (!EntityUtilities.isEqualDateRange(dateRanges[i], dateRangesPriorChanges[i], filter)) {
1123
+ return false;
1124
+ }
1125
+ }
1126
+ return true;
1127
+ }
1128
+ static isEqualDateTime(value, valuePriorChanges) {
1129
+ const date = new Date(value);
1130
+ const datePriorChanges = new Date(valuePriorChanges);
1131
+ return LodashUtilities.isEqual(date, datePriorChanges);
1132
+ }
1133
+ static isEqualDate(value, valuePriorChanges) {
1134
+ const date = new Date(value);
1135
+ const datePriorChanges = new Date(valuePriorChanges);
1136
+ date.setHours(0, 0, 0, 0);
1137
+ datePriorChanges.setHours(0, 0, 0, 0);
1138
+ return LodashUtilities.isEqual(date, datePriorChanges);
1139
+ }
1140
+ static isEqualDateRange(value, valuePriorChanges, filter) {
1141
+ const dateRange = LodashUtilities.cloneDeep(value);
1142
+ dateRange.start = new Date(value.start);
1143
+ dateRange.end = new Date(value.end);
1144
+ dateRange.values = DateUtilities.getDatesBetween(dateRange.start, dateRange.end, filter);
1145
+ const dateRangePriorChanges = LodashUtilities.cloneDeep(valuePriorChanges);
1146
+ dateRangePriorChanges.start = new Date(valuePriorChanges.start);
1147
+ dateRangePriorChanges.end = new Date(valuePriorChanges.end);
1148
+ dateRangePriorChanges.values = DateUtilities.getDatesBetween(dateRangePriorChanges.start, dateRangePriorChanges.end, filter);
1149
+ return LodashUtilities.isEqual(dateRange, dateRangePriorChanges);
1150
+ }
1151
+ // TODO: Find a way to use blobs with jest
1152
+ /* istanbul ignore next */
1153
+ static async isEqualFile(value, valuePriorChanges, multiple) {
1154
+ const files = multiple ? value.sort() : [value].sort();
1155
+ const filesPriorChanges = multiple ? valuePriorChanges.sort() : [valuePriorChanges].sort();
1156
+ if (files.length !== filesPriorChanges.length) {
1157
+ return false;
1158
+ }
1159
+ for (let i = 0; i < files.length; i++) {
1160
+ // checks this before actually getting any files due to performance reasons.
1161
+ if (!LodashUtilities.isEqual(files[i]?.name, filesPriorChanges[i]?.name)
1162
+ || !LodashUtilities.isEqual(files[i]?.url, filesPriorChanges[i]?.url)) {
1163
+ return false;
1164
+ }
1165
+ files[i] = filesPriorChanges[i].file && !files[i].file ? await FileUtilities.getFileData(files[i]) : files[i];
1166
+ // eslint-disable-next-line max-len
1167
+ filesPriorChanges[i] = files[i].file && !filesPriorChanges[i].file ? await FileUtilities.getFileData(filesPriorChanges[i]) : filesPriorChanges[i];
1168
+ if (!LodashUtilities.isEqual(await files[i].file?.text(), await filesPriorChanges[i].file?.text())) {
1169
+ return false;
1170
+ }
1171
+ }
1172
+ return true;
1173
+ }
1174
+ static isEqualCustom(value, valuePriorChanges,
1175
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1176
+ metadata) {
1177
+ if (!metadata.isEqual(value, valuePriorChanges, metadata)) {
1178
+ return false;
1179
+ }
1180
+ return true;
1181
+ }
1182
+ /**
459
1183
  * Compare function for sorting entity keys by their order value.
460
1184
  *
461
1185
  * @param a - First key of entity.
462
1186
  * @param b - Second key of entity.
463
1187
  * @param entity - Current entity (used to get metadata of entity keys).
464
- * @returns 0 if both values have the same order, a negative value if X, a positive value if Y.
1188
+ * @returns 0 if both values have the same order, a negative value if 'a' comes before 'b', a positive value if 'a' comes behind 'b'.
465
1189
  */
466
1190
  static compareOrder(a, b, entity) {
467
1191
  const metadataA = EntityUtilities.getPropertyMetadata(entity, a);
@@ -475,7 +1199,7 @@ class EntityUtilities {
475
1199
  else if (metadataB.position.order === -1) {
476
1200
  return -1;
477
1201
  }
478
- return ((metadataA.position.order) - (metadataB.position.order));
1202
+ return metadataA.position.order - metadataB.position.order;
479
1203
  }
480
1204
  /**
481
1205
  * Gets the bootstrap column values for "lg", "md", "sm".
@@ -504,7 +1228,7 @@ class EntityUtilities {
504
1228
  */
505
1229
  static resetChangesOnEntity(entity, entityPriorChanges) {
506
1230
  for (const key in entityPriorChanges) {
507
- Reflect.set(entity, key, Reflect.get(entityPriorChanges, key));
1231
+ ReflectUtilities.set(entity, key, ReflectUtilities.get(entityPriorChanges, key));
508
1232
  }
509
1233
  }
510
1234
  /**
@@ -552,7 +1276,7 @@ class EntityUtilities {
552
1276
  * @returns An array of keys of the entity.
553
1277
  */
554
1278
  static keysOf(entity, hideOmitForCreate = false, hideOmitForEdit = false) {
555
- let keys = Reflect.ownKeys(entity);
1279
+ let keys = ReflectUtilities.ownKeys(entity);
556
1280
  if (hideOmitForCreate) {
557
1281
  const omitForCreateKeys = EntityUtilities.getOmitForCreate(entity);
558
1282
  keys = keys.filter(k => !omitForCreateKeys.includes(k));
@@ -564,11 +1288,30 @@ class EntityUtilities {
564
1288
  return keys;
565
1289
  }
566
1290
  }
567
- _a = EntityUtilities;
568
1291
  // eslint-disable-next-line @typescript-eslint/member-ordering, jsdoc/require-jsdoc
569
- EntityUtilities.construct = _a.new;
1292
+ EntityUtilities.construct = EntityUtilities.new;
570
1293
  // eslint-disable-next-line @typescript-eslint/member-ordering, jsdoc/require-jsdoc
571
- EntityUtilities.build = _a.new;
1294
+ EntityUtilities.build = EntityUtilities.new;
1295
+
1296
+ /**
1297
+ * A base Entity class with a builtin id.
1298
+ */
1299
+ class Entity {
1300
+ constructor(entity) {
1301
+ EntityUtilities.new(this, entity);
1302
+ }
1303
+ }
1304
+ __decorate([
1305
+ string({
1306
+ omitForCreate: true,
1307
+ omitForUpdate: true,
1308
+ display: false,
1309
+ displayStyle: 'line',
1310
+ displayName: 'ID',
1311
+ required: true
1312
+ }),
1313
+ __metadata("design:type", String)
1314
+ ], Entity.prototype, "id", void 0);
572
1315
 
573
1316
  /**
574
1317
  * A generic EntityService class.
@@ -579,6 +1322,12 @@ EntityUtilities.build = _a.new;
579
1322
  class EntityService {
580
1323
  constructor(http) {
581
1324
  this.http = http;
1325
+ /**
1326
+ * The key which holds the id value.
1327
+ *
1328
+ * @default 'id'
1329
+ */
1330
+ this.idKey = 'id';
582
1331
  /**
583
1332
  * A subject of all the entity values.
584
1333
  * Can be subscribed to when you want to do a specific thing whenever the entities change.
@@ -601,7 +1350,54 @@ class EntityService {
601
1350
  * @returns A Promise of the created entity.
602
1351
  */
603
1352
  async create(entity) {
604
- const body = omit(entity, EntityUtilities.getOmitForCreate(entity));
1353
+ const body = LodashUtilities.omit(entity, EntityUtilities.getOmitForCreate(entity));
1354
+ const filePropertyKeys = EntityUtilities.getFileProperties(entity);
1355
+ if (!filePropertyKeys.length) {
1356
+ return await this.createWithJson(body);
1357
+ }
1358
+ else {
1359
+ return await this.createWithFormData(body, filePropertyKeys, entity);
1360
+ }
1361
+ }
1362
+ // TODO: Find a way to use blobs with jest
1363
+ /* istanbul ignore next */
1364
+ /**
1365
+ * Creates the entity with form data when the entity contains files in contrast to creating it with a normal json body.
1366
+ * All file values are stored inside their respective property key and their name.
1367
+ * Form data is able to handle setting multiple files to the same key.
1368
+ *
1369
+ * @param body - The body Of the request.
1370
+ * @param filePropertyKeys - All property keys that are files and need to be added to the form data.
1371
+ * @param entity - The entity to create. This is needed in addition to the body because the body doesn't contain any metadata.
1372
+ * @returns The created entity from the server.
1373
+ */
1374
+ async createWithFormData(body, filePropertyKeys, entity) {
1375
+ const formData = new FormData();
1376
+ formData.append('body', JSON.stringify(LodashUtilities.omit(body, filePropertyKeys)));
1377
+ for (const key of filePropertyKeys) {
1378
+ if (EntityUtilities.getPropertyMetadata(entity, key, DecoratorTypes.FILE_DEFAULT).multiple) {
1379
+ const fileDataValues = body[key];
1380
+ for (const value of fileDataValues) {
1381
+ formData.append(key, (await FileUtilities.getFileData(value)).file, value.name);
1382
+ }
1383
+ }
1384
+ else {
1385
+ const fileData = body[key];
1386
+ formData.append(key, (await FileUtilities.getFileData(fileData)).file, fileData.name);
1387
+ }
1388
+ }
1389
+ const e = await firstValueFrom(this.http.post(this.baseUrl, formData));
1390
+ this.entities.push(e);
1391
+ this.entitiesSubject.next(this.entities);
1392
+ return e;
1393
+ }
1394
+ /**
1395
+ * Creates the entity with a normal json body in contrast to creating it with form data when the entity contains files.
1396
+ *
1397
+ * @param body - The body Of the request.
1398
+ * @returns The created entity from the server.
1399
+ */
1400
+ async createWithJson(body) {
605
1401
  const e = await firstValueFrom(this.http.post(this.baseUrl, body));
606
1402
  this.entities.push(e);
607
1403
  this.entitiesSubject.next(this.entities);
@@ -626,19 +1422,68 @@ class EntityService {
626
1422
  * It Is used to get changed values and only update them instead of sending the whole entity data.
627
1423
  */
628
1424
  async update(entity, entityPriorChanges) {
629
- const reqBody = omit(EntityUtilities.difference(entity, entityPriorChanges), EntityUtilities.getOmitForUpdate(entity));
630
- const updatedEntity = await firstValueFrom(this.http.patch(`${this.baseUrl}/${entityPriorChanges.id}`, omitBy(reqBody, isNil)));
631
- this.entities[this.entities.findIndex((e) => e.id === entityPriorChanges.id)] = updatedEntity;
1425
+ const body = LodashUtilities.omit(await EntityUtilities.difference(entity, entityPriorChanges), EntityUtilities.getOmitForUpdate(entity));
1426
+ const filePropertyKeys = EntityUtilities.getFileProperties(entityPriorChanges);
1427
+ if (!filePropertyKeys.length) {
1428
+ await this.updateWithJson(body, entityPriorChanges[this.idKey]);
1429
+ }
1430
+ else {
1431
+ await this.updateWithFormData(body, filePropertyKeys, entity, entityPriorChanges[this.idKey]);
1432
+ }
1433
+ }
1434
+ // TODO: Find a way to use blobs with jest
1435
+ /* istanbul ignore next */
1436
+ /**
1437
+ * Updates the entity with form data when the entity contains files in contrast to creating it with a normal json body.
1438
+ * All file values are stored inside their respective property key and their name.
1439
+ * Form data is able to handle setting multiple files to the same key.
1440
+ *
1441
+ * @param body - The request body. Already contains only properties that have changed.
1442
+ * @param filePropertyKeys - The keys of all properties which are files and need to separately be appended to the form data.
1443
+ * @param entity - The original entity. Is needed to get the metadata of all the files.
1444
+ * @param id - The id of the entity to update.
1445
+ */
1446
+ async updateWithFormData(body, filePropertyKeys, entity, id) {
1447
+ const formData = new FormData();
1448
+ formData.append('body', JSON.stringify(LodashUtilities.omitBy(body, LodashUtilities.isNil)));
1449
+ for (const key of filePropertyKeys) {
1450
+ if (EntityUtilities.getPropertyMetadata(entity, key, DecoratorTypes.FILE_DEFAULT).multiple) {
1451
+ // eslint-disable-next-line max-len
1452
+ const fileDataValues = body[key];
1453
+ for (const value of fileDataValues) {
1454
+ formData.append(key, (await FileUtilities.getFileData(value)).file, value.name);
1455
+ }
1456
+ }
1457
+ else {
1458
+ // eslint-disable-next-line max-len
1459
+ const fileData = body[key];
1460
+ formData.append(key, (await FileUtilities.getFileData(fileData)).file, fileData.name);
1461
+ }
1462
+ }
1463
+ const updatedEntity = await firstValueFrom(this.http.patch(`${this.baseUrl}/${id}`, formData));
1464
+ this.entities[this.entities.findIndex(e => e[this.idKey] === id)] = updatedEntity;
1465
+ this.entitiesSubject.next(this.entities);
1466
+ }
1467
+ /**
1468
+ * Updates the entity with a normal json body in contrast to updating it with form data when the entity contains files.
1469
+ *
1470
+ * @param body - The body of the Request. Has already removed all unnecessary values.
1471
+ * @param id - The id of the entity to update.
1472
+ */
1473
+ async updateWithJson(body, id) {
1474
+ const updatedEntity = await firstValueFrom(this.http.patch(`${this.baseUrl}/${id}`, LodashUtilities.omitBy(body, LodashUtilities.isNil)));
1475
+ this.entities[this.entities.findIndex(e => e[this.idKey] === id)] = updatedEntity;
632
1476
  this.entitiesSubject.next(this.entities);
633
1477
  }
634
1478
  /**
635
1479
  * Deletes a specific Entity.
636
1480
  *
637
- * @param id - The id of the element to delete.
1481
+ * @param entity - The entity to delete.
638
1482
  */
639
- async delete(id) {
640
- await firstValueFrom(this.http.delete(`${this.baseUrl}/${id}`));
641
- this.entities.splice(this.entities.findIndex((e) => e.id === id), 1);
1483
+ async delete(entity) {
1484
+ await firstValueFrom(this.http.delete(`${this.baseUrl}/${entity[this.idKey]}`));
1485
+ // the == comparison instead of === is to catch ids that are numbers.
1486
+ this.entities.splice(this.entities.findIndex(e => e[this.idKey] === entity[this.idKey]), 1);
642
1487
  this.entitiesSubject.next(this.entities);
643
1488
  }
644
1489
  }
@@ -662,7 +1507,6 @@ class BaseBuilder {
662
1507
  validateInput(data) {
663
1508
  // By default, no validation is done
664
1509
  }
665
- ;
666
1510
  /**
667
1511
  * Sets the value for the given key if no user value was provided.
668
1512
  *
@@ -671,7 +1515,7 @@ class BaseBuilder {
671
1515
  * @returns The Builder.
672
1516
  */
673
1517
  withDefault(key, value) {
674
- if (!this.inputData || !this.inputData[key]) {
1518
+ if (this.inputData == null || this.inputData[key] == null) {
675
1519
  this.data[key] = value;
676
1520
  }
677
1521
  return this;
@@ -709,18 +1553,18 @@ class ConfirmDialogDataBuilder extends BaseBuilder {
709
1553
  }
710
1554
  // eslint-disable-next-line jsdoc/require-jsdoc
711
1555
  generateBaseData(data) {
712
- return new ConfirmDialogDataInternal(data?.text ? data.text : ['Do you really want to do this?'], data?.type ? data.type : 'default', data?.confirmButtonLabel ? data.confirmButtonLabel : 'Confirm', data?.cancelButtonLabel ? data.cancelButtonLabel : 'Cancel', data?.title ? data.title : 'Confirmation', data?.requireConfirmation ? data.requireConfirmation : false, data?.confirmationText);
1556
+ return new ConfirmDialogDataInternal(data?.text ?? ['Do you really want to do this?'], data?.type ?? 'default', data?.confirmButtonLabel ?? 'Confirm', data?.cancelButtonLabel ?? 'Cancel', data?.title ?? 'Confirmation', data?.requireConfirmation ?? false, data?.confirmationText);
713
1557
  }
714
1558
  // eslint-disable-next-line jsdoc/require-jsdoc
715
1559
  validateInput(data) {
716
1560
  if (!data) {
717
1561
  return;
718
1562
  }
719
- if (data.requireConfirmation && !data.confirmationText) {
1563
+ if (data.requireConfirmation === true && !data.confirmationText) {
720
1564
  throw new Error(`Missing required Input data "confirmationText".
721
1565
  You can only omit this value when "requireConfirmation" is false.`);
722
1566
  }
723
- if (!data.requireConfirmation && data.confirmationText) {
1567
+ if (data.requireConfirmation !== true && data.confirmationText) {
724
1568
  throw new Error('The "confirmationText" will never be shown because "requireConfirmation" is not set to true');
725
1569
  }
726
1570
  if (data.type === 'info-only' && data.cancelButtonLabel) {
@@ -758,10 +1602,10 @@ class NgxMatEntityConfirmDialogComponent {
758
1602
  }
759
1603
  }
760
1604
  NgxMatEntityConfirmDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityConfirmDialogComponent, deps: [{ token: i1.MatDialogRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
761
- NgxMatEntityConfirmDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: NgxMatEntityConfirmDialogComponent, selector: "ngx-mat-entity-confirm-dialog", ngImport: i0, template: "<h2 mat-dialog-title *ngIf=\"data.title\">{{data.title}}</h2>\n\n<mat-dialog-content>\n <p *ngFor=\"let paragraph of data.text\">{{paragraph}}</p>\n <div *ngIf=\"data.requireConfirmation\" class=\"checkbox-wrapper\">\n <mat-checkbox [(ngModel)]=\"confirm\" name=\"confirm\">\n {{data.confirmationText}}\n </mat-checkbox>\n </div>\n</mat-dialog-content>\n\n<mat-dialog-actions>\n <button *ngIf=\"data.type === 'delete'\" mat-raised-button color=\"warn\" (click)=\"confirmAction()\" [disabled]=\"data.requireConfirmation && !confirm\" class=\"confirm-button\">\n {{data.confirmButtonLabel}}\n </button>\n <button *ngIf=\"data.type !== 'delete'\" mat-raised-button (click)=\"confirmAction()\" [disabled]=\"data.requireConfirmation && !confirm\" class=\"confirm-button\">\n {{data.confirmButtonLabel}}\n </button>\n <button mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.cancelButtonLabel}}\n </button>\n</mat-dialog-actions>\n", styles: [".checkbox-wrapper{min-height:50px;display:flex}.checkbox-wrapper>mat-checkbox{align-self:center}mat-dialog-actions{display:flex;justify-content:space-between}\n"], components: [{ type: i6.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { type: i11.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i13.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i13.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]" }] });
1605
+ NgxMatEntityConfirmDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: NgxMatEntityConfirmDialogComponent, selector: "ngx-mat-entity-confirm-dialog", ngImport: i0, template: "<h2 mat-dialog-title *ngIf=\"data.title\">{{data.title}}</h2>\n\n<mat-dialog-content>\n <p *ngFor=\"let paragraph of data.text\">{{paragraph}}</p>\n <div *ngIf=\"data.requireConfirmation\" class=\"checkbox-wrapper\">\n <mat-checkbox [(ngModel)]=\"confirm\" name=\"confirm\">\n {{data.confirmationText}}\n </mat-checkbox>\n </div>\n</mat-dialog-content>\n\n<mat-dialog-actions>\n <button *ngIf=\"data.type === 'delete'\" mat-raised-button color=\"warn\" (click)=\"confirmAction()\" [disabled]=\"data.requireConfirmation && !confirm\" class=\"confirm-button\">\n {{data.confirmButtonLabel}}\n </button>\n <button *ngIf=\"data.type !== 'delete'\" mat-raised-button (click)=\"confirmAction()\" [disabled]=\"data.requireConfirmation && !confirm\" class=\"confirm-button\">\n {{data.confirmButtonLabel}}\n </button>\n <button *ngIf=\"data.type !== 'info-only'\" mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.cancelButtonLabel}}\n </button>\n</mat-dialog-actions>\n", styles: [".checkbox-wrapper{min-height:50px;display:flex}.checkbox-wrapper>mat-checkbox{align-self:center}mat-dialog-actions{display:flex;justify-content:space-between}\n"], components: [{ type: i2.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]" }] });
762
1606
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityConfirmDialogComponent, decorators: [{
763
1607
  type: Component,
764
- args: [{ selector: 'ngx-mat-entity-confirm-dialog', template: "<h2 mat-dialog-title *ngIf=\"data.title\">{{data.title}}</h2>\n\n<mat-dialog-content>\n <p *ngFor=\"let paragraph of data.text\">{{paragraph}}</p>\n <div *ngIf=\"data.requireConfirmation\" class=\"checkbox-wrapper\">\n <mat-checkbox [(ngModel)]=\"confirm\" name=\"confirm\">\n {{data.confirmationText}}\n </mat-checkbox>\n </div>\n</mat-dialog-content>\n\n<mat-dialog-actions>\n <button *ngIf=\"data.type === 'delete'\" mat-raised-button color=\"warn\" (click)=\"confirmAction()\" [disabled]=\"data.requireConfirmation && !confirm\" class=\"confirm-button\">\n {{data.confirmButtonLabel}}\n </button>\n <button *ngIf=\"data.type !== 'delete'\" mat-raised-button (click)=\"confirmAction()\" [disabled]=\"data.requireConfirmation && !confirm\" class=\"confirm-button\">\n {{data.confirmButtonLabel}}\n </button>\n <button mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.cancelButtonLabel}}\n </button>\n</mat-dialog-actions>\n", styles: [".checkbox-wrapper{min-height:50px;display:flex}.checkbox-wrapper>mat-checkbox{align-self:center}mat-dialog-actions{display:flex;justify-content:space-between}\n"] }]
1608
+ args: [{ selector: 'ngx-mat-entity-confirm-dialog', template: "<h2 mat-dialog-title *ngIf=\"data.title\">{{data.title}}</h2>\n\n<mat-dialog-content>\n <p *ngFor=\"let paragraph of data.text\">{{paragraph}}</p>\n <div *ngIf=\"data.requireConfirmation\" class=\"checkbox-wrapper\">\n <mat-checkbox [(ngModel)]=\"confirm\" name=\"confirm\">\n {{data.confirmationText}}\n </mat-checkbox>\n </div>\n</mat-dialog-content>\n\n<mat-dialog-actions>\n <button *ngIf=\"data.type === 'delete'\" mat-raised-button color=\"warn\" (click)=\"confirmAction()\" [disabled]=\"data.requireConfirmation && !confirm\" class=\"confirm-button\">\n {{data.confirmButtonLabel}}\n </button>\n <button *ngIf=\"data.type !== 'delete'\" mat-raised-button (click)=\"confirmAction()\" [disabled]=\"data.requireConfirmation && !confirm\" class=\"confirm-button\">\n {{data.confirmButtonLabel}}\n </button>\n <button *ngIf=\"data.type !== 'info-only'\" mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.cancelButtonLabel}}\n </button>\n</mat-dialog-actions>\n", styles: [".checkbox-wrapper{min-height:50px;display:flex}.checkbox-wrapper>mat-checkbox{align-self:center}mat-dialog-actions{display:flex;justify-content:space-between}\n"] }]
765
1609
  }], ctorParameters: function () { return [{ type: i1.MatDialogRef }, { type: undefined, decorators: [{
766
1610
  type: Inject,
767
1611
  args: [MAT_DIALOG_DATA]
@@ -844,7 +1688,7 @@ class CreateDialogDataBuilder extends BaseBuilder {
844
1688
  .withDefault('text', ['Do you really want to create this entity?'])
845
1689
  .withDefault('title', 'Create')
846
1690
  .getResult();
847
- return new CreateDialogDataInternal(data?.title ? data.title : 'Create', data?.createButtonLabel ? data.createButtonLabel : 'Create', data?.cancelButtonLabel ? data.cancelButtonLabel : 'Cancel', data?.createRequiresConfirmDialog ? data.createRequiresConfirmDialog : false, confirmCreateDialogData);
1691
+ return new CreateDialogDataInternal(data?.title ?? 'Create', data?.createButtonLabel ?? 'Create', data?.cancelButtonLabel ?? 'Cancel', data?.createRequiresConfirmDialog ?? false, confirmCreateDialogData);
848
1692
  }
849
1693
  }
850
1694
 
@@ -871,117 +1715,1101 @@ class AddArrayItemDialogDataBuilder extends BaseBuilder {
871
1715
  .withDefault('createButtonLabel', 'Add')
872
1716
  .withDefault('title', 'Add to array')
873
1717
  .getResult();
874
- return new AddArrayItemDialogDataInternal(data.entity, createDialogData, data.getValidationErrorMessage ? data.getValidationErrorMessage : getValidationErrorMessage);
1718
+ return new AddArrayItemDialogDataInternal(data.entity, createDialogData, data.getValidationErrorMessage ?? getValidationErrorMessage);
875
1719
  }
876
1720
  }
877
1721
 
878
1722
  /**
879
- * The default input component. It gets the metadata of the property from the given @Input "entity" and @Input "propertyKey"
880
- * and displays the input field accordingly.
881
- *
882
- * You can also define a method that generates error-messages and if the input should be hidden when its metadata says
883
- * that it should be omitted for creating or updating.
884
- * The last part being mostly relevant if you want to use this component inside an ngFor.
1723
+ * The abstract base class of any ngx-mat-entity input.
885
1724
  */
886
- class NgxMatEntityInputComponent {
887
- constructor(dialog) {
888
- this.dialog = dialog;
889
- this.chipsInput = '';
890
- this.selection = new SelectionModel(true, []);
891
- this.DecoratorTypes = DecoratorTypes;
892
- this.EntityUtilities = EntityUtilities;
893
- this.getWidth = EntityUtilities.getWidth;
1725
+ // eslint-disable-next-line max-len
1726
+ class NgxMatEntityBaseInputComponent {
1727
+ constructor() {
1728
+ this.inputChangeEvent = new EventEmitter();
1729
+ }
1730
+ ngOnInit() {
1731
+ this.metadata = EntityUtilities.getPropertyMetadata(this.entity, this.key);
894
1732
  }
895
1733
  /**
896
- * This is needed for the inputs to work inside an ngFor.
897
- *
898
- * @param index - The index of the element in the ngFor.
899
- * @returns The index.
1734
+ * Should emit when the input has changed. This is needed to trigger validation and dirty checks.
900
1735
  */
901
- trackByFn(index) {
902
- return index;
1736
+ emitChange() {
1737
+ this.inputChangeEvent.emit();
903
1738
  }
1739
+ }
1740
+ NgxMatEntityBaseInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityBaseInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1741
+ NgxMatEntityBaseInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: NgxMatEntityBaseInputComponent, selector: "ngx-mat-entity-base-input", inputs: { entity: "entity", key: "key", getValidationErrorMessage: "getValidationErrorMessage" }, outputs: { inputChangeEvent: "inputChangeEvent" }, ngImport: i0, template: '', isInline: true });
1742
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityBaseInputComponent, decorators: [{
1743
+ type: Component,
1744
+ args: [{
1745
+ selector: 'ngx-mat-entity-base-input',
1746
+ template: ''
1747
+ }]
1748
+ }], propDecorators: { entity: [{
1749
+ type: Input
1750
+ }], key: [{
1751
+ type: Input
1752
+ }], getValidationErrorMessage: [{
1753
+ type: Input
1754
+ }], inputChangeEvent: [{
1755
+ type: Output
1756
+ }] } });
1757
+
1758
+ /* eslint-disable jsdoc/require-jsdoc */
1759
+ class StringInputComponent extends NgxMatEntityBaseInputComponent {
1760
+ }
1761
+ StringInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: StringInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1762
+ StringInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: StringInputComponent, selector: "string-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"entity[key]\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [required]=\"metadata.required\"\n [pattern]=\"metadata.regex ?? '[\\\\s\\\\S]*'\"\n [minlength]=\"metadata.minLength ?? null\"\n [maxlength]=\"metadata.maxLength ?? null\"\n (ngModelChange)=\"emitChange()\"\n />\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i3$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { type: i3$1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { type: i3$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }] });
1763
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: StringInputComponent, decorators: [{
1764
+ type: Component,
1765
+ args: [{ selector: 'string-input', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"entity[key]\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [required]=\"metadata.required\"\n [pattern]=\"metadata.regex ?? '[\\\\s\\\\S]*'\"\n [minlength]=\"metadata.minLength ?? null\"\n [maxlength]=\"metadata.maxLength ?? null\"\n (ngModelChange)=\"emitChange()\"\n />\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
1766
+ }] });
1767
+
1768
+ /* eslint-disable jsdoc/require-jsdoc */
1769
+ class StringTextboxInputComponent extends NgxMatEntityBaseInputComponent {
1770
+ }
1771
+ StringTextboxInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: StringTextboxInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1772
+ StringTextboxInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: StringTextboxInputComponent, selector: "string-textbox-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <textarea\n matInput\n [(ngModel)]=\"entity[key]\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n cdkTextareaAutosize\n cdkAutosizeMinRows=\"10\"\n [required]=\"metadata.required\"\n [minlength]=\"metadata.minLength ?? null\"\n [maxlength]=\"metadata.maxLength ?? null\"\n (ngModelChange)=\"emitChange()\"\n >\n </textarea>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i3$2.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i3$1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { type: i3$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }] });
1773
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: StringTextboxInputComponent, decorators: [{
1774
+ type: Component,
1775
+ args: [{ selector: 'string-textbox-input', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <textarea\n matInput\n [(ngModel)]=\"entity[key]\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n cdkTextareaAutosize\n cdkAutosizeMinRows=\"10\"\n [required]=\"metadata.required\"\n [minlength]=\"metadata.minLength ?? null\"\n [maxlength]=\"metadata.maxLength ?? null\"\n (ngModelChange)=\"emitChange()\"\n >\n </textarea>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
1776
+ }] });
1777
+
1778
+ /* eslint-disable jsdoc/require-jsdoc */
1779
+ class StringAutocompleteInputComponent extends NgxMatEntityBaseInputComponent {
904
1780
  ngOnInit() {
905
- if (!this.entity) {
906
- throw new Error('Missing required Input data "entity"');
1781
+ super.ngOnInit();
1782
+ this.autocompleteStrings = this.metadata.autocompleteValues;
1783
+ this.filteredAutocompleteStrings = LodashUtilities.cloneDeep(this.autocompleteStrings);
1784
+ }
1785
+ /**
1786
+ * Dynamically filters the Autocomplete options when the user inputs something.
1787
+ *
1788
+ * @param input - The input of the user.
1789
+ */
1790
+ filterAutocompleteStrings(input) {
1791
+ const inputString = input;
1792
+ if (inputString) {
1793
+ const filterValue = inputString.toLowerCase();
1794
+ this.filteredAutocompleteStrings = this.autocompleteStrings.filter(s => s.toLowerCase().includes(filterValue));
907
1795
  }
908
- if (!this.propertyKey) {
909
- throw new Error('Missing required Input data "propertyKey"');
1796
+ }
1797
+ }
1798
+ StringAutocompleteInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: StringAutocompleteInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1799
+ StringAutocompleteInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: StringAutocompleteInputComponent, selector: "string-autocomplete-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"entity[key]\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [matAutocomplete]=\"auto\"\n (keyup)=\"filterAutocompleteStrings(entity[key])\"\n [required]=\"metadata.required\"\n [minlength]=\"metadata.minLength ?? null\"\n [maxlength]=\"metadata.maxLength ?? null\"\n [pattern]=\"metadata.regex ?? '[\\\\s\\\\S]*'\"\n (ngModelChange)=\"emitChange()\"\n />\n <mat-autocomplete #auto=\"matAutocomplete\">\n <mat-option *ngFor=\"let value of filteredAutocompleteStrings\" [value]=\"value\">\n {{value}}\n </mat-option>\n </mat-autocomplete>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$1.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i3$3.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2$1.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i3$1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { type: i3$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { type: i3$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }] });
1800
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: StringAutocompleteInputComponent, decorators: [{
1801
+ type: Component,
1802
+ args: [{ selector: 'string-autocomplete-input', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"entity[key]\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [matAutocomplete]=\"auto\"\n (keyup)=\"filterAutocompleteStrings(entity[key])\"\n [required]=\"metadata.required\"\n [minlength]=\"metadata.minLength ?? null\"\n [maxlength]=\"metadata.maxLength ?? null\"\n [pattern]=\"metadata.regex ?? '[\\\\s\\\\S]*'\"\n (ngModelChange)=\"emitChange()\"\n />\n <mat-autocomplete #auto=\"matAutocomplete\">\n <mat-option *ngFor=\"let value of filteredAutocompleteStrings\" [value]=\"value\">\n {{value}}\n </mat-option>\n </mat-autocomplete>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
1803
+ }] });
1804
+
1805
+ /* eslint-disable jsdoc/require-jsdoc */
1806
+ class StringDropdownInputComponent extends NgxMatEntityBaseInputComponent {
1807
+ }
1808
+ StringDropdownInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: StringDropdownInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1809
+ StringDropdownInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: StringDropdownInputComponent, selector: "string-dropdown-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select (ngModelChange)=\"emitChange()\" [(ngModel)]=\"entity[key]\" [name]=\"key.toString()\" #model=\"ngModel\" [required]=\"metadata.required\">\n <mat-option *ngFor=\"let value of metadata.dropdownValues\" [value]=\"value.value\">{{value.displayName}}</mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$2.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i3$3.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }] });
1810
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: StringDropdownInputComponent, decorators: [{
1811
+ type: Component,
1812
+ args: [{ selector: 'string-dropdown-input', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select (ngModelChange)=\"emitChange()\" [(ngModel)]=\"entity[key]\" [name]=\"key.toString()\" #model=\"ngModel\" [required]=\"metadata.required\">\n <mat-option *ngFor=\"let value of metadata.dropdownValues\" [value]=\"value.value\">{{value.displayName}}</mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
1813
+ }] });
1814
+
1815
+ /* eslint-disable jsdoc/require-jsdoc */
1816
+ class BooleanCheckboxInputComponent extends NgxMatEntityBaseInputComponent {
1817
+ ngOnInit() {
1818
+ super.ngOnInit();
1819
+ if (this.entity[this.key] == null) {
1820
+ this.entity[this.key] = false;
910
1821
  }
911
- this.type = EntityUtilities.getPropertyType(this.entity, this.propertyKey);
912
- this.metadata = EntityUtilities.getPropertyMetadata(this.entity, this.propertyKey, this.type);
913
- this.metadataDefaultString = this.metadata;
914
- this.metadataTextboxString = this.metadata;
915
- this.metadataAutocompleteString = this.metadata;
916
- this.autocompleteStrings = this.metadataAutocompleteString.autocompleteValues;
917
- this.filteredAutocompleteStrings = cloneDeep(this.autocompleteStrings);
918
- this.metadataDropdownString = this.metadata;
919
- this.metadataDropdownBoolean = this.metadata;
920
- if ((this.type === DecoratorTypes.BOOLEAN_CHECKBOX || this.type === DecoratorTypes.BOOLEAN_TOGGLE)
921
- && this.entity[this.propertyKey] === undefined) {
922
- this.entity[this.propertyKey] = false;
923
- }
924
- this.metadataDefaultNumber = this.metadata;
925
- this.metadataDropdownNumber = this.metadata;
926
- this.metadataDefaultObject = this.metadata;
927
- this.objectProperty = this.entity[this.propertyKey];
928
- if (this.type === DecoratorTypes.OBJECT) {
929
- this.objectPropertyRows = EntityUtilities.getEntityRows(this.objectProperty, this.hideOmitForCreate, this.hideOmitForEdit);
1822
+ }
1823
+ }
1824
+ BooleanCheckboxInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: BooleanCheckboxInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1825
+ BooleanCheckboxInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: BooleanCheckboxInputComponent, selector: "boolean-checkbox-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field class=\"hideUnderline\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-checkbox (ngModelChange)=\"emitChange()\" (click)=\"model.control.markAsTouched()\" [(ngModel)]=\"entity[key]\" [name]=\"key.toString()\"></mat-checkbox>\n <!-- hidden input is needed so that the checkbox can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"entity[key]\"\n [name]=\"key.toString() + 'Helper'\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required\">\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["::ng-deep .hideUnderline .mat-form-field-underline{opacity:0%}mat-form-field{width:100%}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }] });
1826
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: BooleanCheckboxInputComponent, decorators: [{
1827
+ type: Component,
1828
+ args: [{ selector: 'boolean-checkbox-input', template: "<mat-form-field class=\"hideUnderline\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-checkbox (ngModelChange)=\"emitChange()\" (click)=\"model.control.markAsTouched()\" [(ngModel)]=\"entity[key]\" [name]=\"key.toString()\"></mat-checkbox>\n <!-- hidden input is needed so that the checkbox can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"entity[key]\"\n [name]=\"key.toString() + 'Helper'\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required\">\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["::ng-deep .hideUnderline .mat-form-field-underline{opacity:0%}mat-form-field{width:100%}\n"] }]
1829
+ }] });
1830
+
1831
+ /* eslint-disable jsdoc/require-jsdoc */
1832
+ class BooleanToggleInputComponent extends NgxMatEntityBaseInputComponent {
1833
+ ngOnInit() {
1834
+ super.ngOnInit();
1835
+ if (this.entity[this.key] == null) {
1836
+ this.entity[this.key] = false;
930
1837
  }
931
- this.metadataEntityArray = this.metadata;
932
- if (this.type === DecoratorTypes.ARRAY) {
933
- if (!this.entity[this.propertyKey]) {
934
- this.entity[this.propertyKey] = [];
1838
+ }
1839
+ }
1840
+ BooleanToggleInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: BooleanToggleInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1841
+ BooleanToggleInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: BooleanToggleInputComponent, selector: "boolean-toggle-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field class=\"hideUnderline\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-slide-toggle (click)=\"model.control.markAsTouched()\" [(ngModel)]=\"entity[key]\" [name]=\"key.toString()\"></mat-slide-toggle>\n <!-- hidden input is needed so that the toggle can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"entity[key]\"\n [name]=\"key.toString() + 'Helper'\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required\"\n (ngModelChange)=\"emitChange\"\n >\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["::ng-deep .hideUnderline .mat-form-field-underline{opacity:0%}mat-form-field{width:100%}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$3.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex", "name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "checked"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }] });
1842
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: BooleanToggleInputComponent, decorators: [{
1843
+ type: Component,
1844
+ args: [{ selector: 'boolean-toggle-input', template: "<mat-form-field class=\"hideUnderline\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-slide-toggle (click)=\"model.control.markAsTouched()\" [(ngModel)]=\"entity[key]\" [name]=\"key.toString()\"></mat-slide-toggle>\n <!-- hidden input is needed so that the toggle can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"entity[key]\"\n [name]=\"key.toString() + 'Helper'\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required\"\n (ngModelChange)=\"emitChange\"\n >\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["::ng-deep .hideUnderline .mat-form-field-underline{opacity:0%}mat-form-field{width:100%}\n"] }]
1845
+ }] });
1846
+
1847
+ /* eslint-disable jsdoc/require-jsdoc */
1848
+ class BooleanDropdownInputComponent extends NgxMatEntityBaseInputComponent {
1849
+ }
1850
+ BooleanDropdownInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: BooleanDropdownInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1851
+ BooleanDropdownInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: BooleanDropdownInputComponent, selector: "boolean-dropdown-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select (ngModelChange)=\"emitChange()\" [(ngModel)]=\"entity[key]\" [name]=\"key.toString()\" #model=\"ngModel\" [required]=\"metadata.required\">\n <mat-option [value]=\"undefined\">-</mat-option>\n <mat-option [value]=\"true\">{{metadata.dropdownTrue}}</mat-option>\n <mat-option [value]=\"false\">{{metadata.dropdownFalse}}</mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$2.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i3$3.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }] });
1852
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: BooleanDropdownInputComponent, decorators: [{
1853
+ type: Component,
1854
+ args: [{ selector: 'boolean-dropdown-input', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select (ngModelChange)=\"emitChange()\" [(ngModel)]=\"entity[key]\" [name]=\"key.toString()\" #model=\"ngModel\" [required]=\"metadata.required\">\n <mat-option [value]=\"undefined\">-</mat-option>\n <mat-option [value]=\"true\">{{metadata.dropdownTrue}}</mat-option>\n <mat-option [value]=\"false\">{{metadata.dropdownFalse}}</mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
1855
+ }] });
1856
+
1857
+ /* eslint-disable jsdoc/require-jsdoc */
1858
+ class NumberInputComponent extends NgxMatEntityBaseInputComponent {
1859
+ }
1860
+ NumberInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NumberInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1861
+ NumberInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: NumberInputComponent, selector: "number-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n type=\"number\"\n [(ngModel)]=\"entity[key]\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [required]=\"metadata.required\"\n [min]=\"metadata.min ?? null\"\n [max]=\"metadata.max ?? null\"\n (ngModelChange)=\"emitChange()\"\n />\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i3$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i3$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i3$1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }] });
1862
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NumberInputComponent, decorators: [{
1863
+ type: Component,
1864
+ args: [{ selector: 'number-input', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n type=\"number\"\n [(ngModel)]=\"entity[key]\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [required]=\"metadata.required\"\n [min]=\"metadata.min ?? null\"\n [max]=\"metadata.max ?? null\"\n (ngModelChange)=\"emitChange()\"\n />\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
1865
+ }] });
1866
+
1867
+ /* eslint-disable jsdoc/require-jsdoc */
1868
+ class NumberDropdownInputComponent extends NgxMatEntityBaseInputComponent {
1869
+ }
1870
+ NumberDropdownInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NumberDropdownInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1871
+ NumberDropdownInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: NumberDropdownInputComponent, selector: "number-dropdown-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select (ngModelChange)=\"emitChange()\" [(ngModel)]=\"entity[key]\" [name]=\"key.toString()\" #model=\"ngModel\" [required]=\"metadata.required\">\n <mat-option *ngFor=\"let value of metadata.dropdownValues\" [value]=\"value.value\">{{value.displayName}}</mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$2.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i3$3.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }] });
1872
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NumberDropdownInputComponent, decorators: [{
1873
+ type: Component,
1874
+ args: [{ selector: 'number-dropdown-input', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select (ngModelChange)=\"emitChange()\" [(ngModel)]=\"entity[key]\" [name]=\"key.toString()\" #model=\"ngModel\" [required]=\"metadata.required\">\n <mat-option *ngFor=\"let value of metadata.dropdownValues\" [value]=\"value.value\">{{value.displayName}}</mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
1875
+ }] });
1876
+
1877
+ /* eslint-disable jsdoc/require-jsdoc */
1878
+ /**
1879
+ * The base data needed for all arrays that are displayed as a table.
1880
+ */
1881
+ class ArrayTableComponent extends NgxMatEntityBaseInputComponent {
1882
+ constructor(matDialog) {
1883
+ super();
1884
+ this.matDialog = matDialog;
1885
+ this.input = undefined;
1886
+ this.dataSource = new MatTableDataSource();
1887
+ this.selection = new SelectionModel(true, []);
1888
+ }
1889
+ ngOnInit() {
1890
+ super.ngOnInit();
1891
+ if (this.entity[this.key] == null) {
1892
+ this.entity[this.key] = [];
1893
+ }
1894
+ this.arrayValues = this.entity[this.key];
1895
+ const givenDisplayColumns = this.metadata.displayColumns.map((v) => v.displayName);
1896
+ if (givenDisplayColumns.find(s => s === 'select')) {
1897
+ throw new Error(`The name "select" for a display column is reserved.
1898
+ Please choose a different name.`);
1899
+ }
1900
+ this.displayedColumns = ['select'].concat(givenDisplayColumns);
1901
+ this.dataSource.data = this.arrayValues;
1902
+ }
1903
+ /**
1904
+ * Toggles all array-items in the table.
1905
+ *
1906
+ */
1907
+ masterToggle() {
1908
+ if (this.isAllSelected()) {
1909
+ this.selection.clear();
1910
+ }
1911
+ else {
1912
+ this.dataSource.data.forEach(row => this.selection.select(row));
1913
+ }
1914
+ }
1915
+ /**
1916
+ * Checks if all array-items in the table have been selected.
1917
+ * This is needed to display the "masterToggle"-checkbox correctly.
1918
+ *
1919
+ * @returns Whether or not all array-items in the table have been selected.
1920
+ */
1921
+ isAllSelected() {
1922
+ const numSelected = this.selection.selected.length;
1923
+ const numRows = this.dataSource.data.length;
1924
+ return numSelected === numRows;
1925
+ }
1926
+ /**
1927
+ * Tries to add an item to the array.
1928
+ */
1929
+ add() {
1930
+ if (this.input != null) {
1931
+ if (!this.metadata.allowDuplicates
1932
+ && this.arrayValues.find(async (v) => await EntityUtilities.isEqual(this.input, v, this.metadata, this.metadata.itemType)) != null) {
1933
+ this.matDialog.open(NgxMatEntityConfirmDialogComponent, {
1934
+ data: this.metadata.duplicatesErrorDialog,
1935
+ autoFocus: false,
1936
+ restoreFocus: false
1937
+ });
1938
+ return;
1939
+ }
1940
+ this.arrayValues.push(LodashUtilities.cloneDeep(this.input));
1941
+ this.dataSource.data = this.arrayValues;
1942
+ this.resetInput();
1943
+ this.emitChange();
1944
+ }
1945
+ }
1946
+ /**
1947
+ * Is split up from the add method to override this functionality more easily.
1948
+ */
1949
+ resetInput() {
1950
+ this.input = undefined;
1951
+ }
1952
+ /**
1953
+ * Removes all selected entries from the entity array.
1954
+ */
1955
+ remove() {
1956
+ this.selection.selected.forEach(s => {
1957
+ this.arrayValues.splice(this.arrayValues.indexOf(s), 1);
1958
+ });
1959
+ this.dataSource.data = this.arrayValues;
1960
+ this.selection.clear();
1961
+ this.emitChange();
1962
+ }
1963
+ }
1964
+ ArrayTableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ArrayTableComponent, deps: [{ token: i1.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
1965
+ ArrayTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: ArrayTableComponent, selector: "ngx-mat-entity-array-table", usesInheritance: true, ngImport: i0, template: '', isInline: true });
1966
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ArrayTableComponent, decorators: [{
1967
+ type: Component,
1968
+ args: [{
1969
+ selector: 'ngx-mat-entity-array-table',
1970
+ template: ''
1971
+ }]
1972
+ }], ctorParameters: function () { return [{ type: i1.MatDialog }]; } });
1973
+
1974
+ /* eslint-disable jsdoc/require-jsdoc */
1975
+ class ArrayDateInputComponent extends ArrayTableComponent {
1976
+ constructor() {
1977
+ super(...arguments);
1978
+ this.DateUtilities = DateUtilities;
1979
+ }
1980
+ }
1981
+ ArrayDateInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ArrayDateInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1982
+ ArrayDateInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: ArrayDateInputComponent, selector: "array-date-input", usesInheritance: true, ngImport: i0, template: "<div class=\"mat-elevation-z8\" style=\"border-radius: 5px;padding: 15px;margin-bottom: 15px;margin-top: 15px;\">\n <mat-form-field appearance=\"standard\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"input\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [matDatepicker]=\"picker\"\n [required]=\"metadata.required\"\n [min]=\"metadata.min ? metadata.min(input) : undefined\"\n [max]=\"metadata.max ? metadata.max(input) : undefined\"\n [matDatepickerFilter]=\"metadata.filter ?? DateUtilities.defaultDateFilter\"\n >\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n \n <div class=\"buttons\">\n <button mat-raised-button\n [disabled]=\"model.errors\"\n (click)=\"add()\">\n {{metadata.addButtonLabel}}\n </button>\n <button mat-raised-button\n [disabled]=\"!selection.selected.length\"\n (click)=\"remove()\">\n {{metadata.removeButtonLabel}}\n </button>\n </div>\n\n <mat-table [dataSource]=\"dataSource\">\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox [disabled]=\"!dataSource.data.length\" (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\" [indeterminate]=\"selection.hasValue() && !isAllSelected()\"></mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let module\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(module) : null\" [checked]=\"selection.isSelected(module)\"></mat-checkbox>\n </mat-cell>\n </ng-container>\n \n <ng-container *ngFor=\"let dCol of metadata.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell class=\"entity\" *matCellDef=\"let entity\">\n {{dCol.value(entity)}}\n </mat-cell>\n </ng-container>\n \n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns\"></mat-row>\n </mat-table>\n\n <div class=\"array-error\" *ngIf=\"metadata.required && !dataSource.data.length\">\n {{metadata.missingErrorMessage}}\n </div>\n</div>", styles: ["mat-form-field{width:100%}.buttons{display:flex;justify-content:space-between;margin-bottom:10px;margin-top:5px}mat-table{border:1px solid #E0E0E0;border-radius:5px;padding-top:5px;padding-bottom:25px}.mat-column-select{flex:0 0 75px}.array-error{display:flex;align-items:center;justify-content:center;margin-top:-25.8px;border:1px solid #E0E0E0;background-color:#f8d3d7;color:#721c24;height:25.8px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$4.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { type: i2$4.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i4$2.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { type: i2.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i4$2.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { type: i4$2.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2$4.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i1$1.MatSuffix, selector: "[matSuffix]" }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }, { type: i4$2.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { type: i4$2.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { type: i4$2.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { type: i4$2.MatCellDef, selector: "[matCellDef]" }, { type: i4$2.MatCell, selector: "mat-cell, td[mat-cell]" }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i4$2.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { type: i4$2.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
1983
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ArrayDateInputComponent, decorators: [{
1984
+ type: Component,
1985
+ args: [{ selector: 'array-date-input', template: "<div class=\"mat-elevation-z8\" style=\"border-radius: 5px;padding: 15px;margin-bottom: 15px;margin-top: 15px;\">\n <mat-form-field appearance=\"standard\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"input\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [matDatepicker]=\"picker\"\n [required]=\"metadata.required\"\n [min]=\"metadata.min ? metadata.min(input) : undefined\"\n [max]=\"metadata.max ? metadata.max(input) : undefined\"\n [matDatepickerFilter]=\"metadata.filter ?? DateUtilities.defaultDateFilter\"\n >\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n \n <div class=\"buttons\">\n <button mat-raised-button\n [disabled]=\"model.errors\"\n (click)=\"add()\">\n {{metadata.addButtonLabel}}\n </button>\n <button mat-raised-button\n [disabled]=\"!selection.selected.length\"\n (click)=\"remove()\">\n {{metadata.removeButtonLabel}}\n </button>\n </div>\n\n <mat-table [dataSource]=\"dataSource\">\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox [disabled]=\"!dataSource.data.length\" (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\" [indeterminate]=\"selection.hasValue() && !isAllSelected()\"></mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let module\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(module) : null\" [checked]=\"selection.isSelected(module)\"></mat-checkbox>\n </mat-cell>\n </ng-container>\n \n <ng-container *ngFor=\"let dCol of metadata.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell class=\"entity\" *matCellDef=\"let entity\">\n {{dCol.value(entity)}}\n </mat-cell>\n </ng-container>\n \n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns\"></mat-row>\n </mat-table>\n\n <div class=\"array-error\" *ngIf=\"metadata.required && !dataSource.data.length\">\n {{metadata.missingErrorMessage}}\n </div>\n</div>", styles: ["mat-form-field{width:100%}.buttons{display:flex;justify-content:space-between;margin-bottom:10px;margin-top:5px}mat-table{border:1px solid #E0E0E0;border-radius:5px;padding-top:5px;padding-bottom:25px}.mat-column-select{flex:0 0 75px}.array-error{display:flex;align-items:center;justify-content:center;margin-top:-25.8px;border:1px solid #E0E0E0;background-color:#f8d3d7;color:#721c24;height:25.8px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}\n"] }]
1986
+ }] });
1987
+
1988
+ /* eslint-disable jsdoc/require-jsdoc */
1989
+ class ArrayDateTimeInputComponent extends ArrayTableComponent {
1990
+ constructor() {
1991
+ super(...arguments);
1992
+ this.DateUtilities = DateUtilities;
1993
+ }
1994
+ ngOnInit() {
1995
+ super.ngOnInit();
1996
+ this.time = DateUtilities.getTimeFromDate(this.entity[this.key]);
1997
+ this.timeDropdownValues = this.metadata.times;
1998
+ if (this.entity[this.key] != null) {
1999
+ this.dateTime = new Date(this.entity[this.key]);
2000
+ }
2001
+ }
2002
+ resetInput() {
2003
+ this.input = undefined;
2004
+ this.time = undefined;
2005
+ }
2006
+ /**
2007
+ * Adds a date time to the array.
2008
+ */
2009
+ addDateTime() {
2010
+ if (this.input && this.time) {
2011
+ this.input = new Date(this.input);
2012
+ this.input.setHours(this.time.hours, this.time.minutes, 0, 0);
2013
+ this.add();
2014
+ }
2015
+ }
2016
+ }
2017
+ ArrayDateTimeInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ArrayDateTimeInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2018
+ ArrayDateTimeInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: ArrayDateTimeInputComponent, selector: "array-date-time-input", usesInheritance: true, ngImport: i0, template: "<div class=\"mat-elevation-z8\" style=\"border-radius: 5px;padding: 15px;margin-bottom: 15px;margin-top: 15px;\">\n \n <div class=\"date-time\">\n <mat-form-field appearance=\"standard\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"input\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [matDatepicker]=\"picker\"\n [required]=\"metadata.required\"\n [min]=\"metadata.minDate ? metadata.minDate(input) : undefined\"\n [max]=\"metadata.maxDate ? metadata.maxDate(input) : undefined\"\n [matDatepickerFilter]=\"metadata.filterDate ?? DateUtilities.defaultDateFilter\"\n >\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n <mat-form-field class=\"timepicker\">\n <mat-label>{{metadata.timeDisplayName}}</mat-label>\n <mat-select\n [(ngModel)]=\"time\"\n [name]=\"key.toString() + 'time'\"\n #timeModel=\"ngModel\"\n [required]=\"metadata.required\"\n >\n <mat-option *ngFor=\"let validTime of DateUtilities.getValidTimesForDropdown(\n DateUtilities.asDate(input),\n metadata.times,\n metadata.minTime,\n metadata.maxTime,\n metadata.filterTime\n )\"\n [value]=\"validTime.value\"\n >\n {{validTime.displayName}}\n </mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(timeModel)}}</mat-error>\n </mat-form-field>\n </div>\n <div class=\"buttons\">\n <button mat-raised-button\n [disabled]=\"model.errors || timeModel.errors || DateUtilities.timeIsUnprocessable(time)\"\n (click)=\"addDateTime()\">\n {{metadata.addButtonLabel}}\n </button>\n <button mat-raised-button\n [disabled]=\"!selection.selected.length\"\n (click)=\"remove()\">\n {{metadata.removeButtonLabel}}\n </button>\n </div>\n\n <mat-table [dataSource]=\"dataSource\">\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox [disabled]=\"!dataSource.data.length\" (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\" [indeterminate]=\"selection.hasValue() && !isAllSelected()\"></mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let module\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(module) : null\" [checked]=\"selection.isSelected(module)\"></mat-checkbox>\n </mat-cell>\n </ng-container>\n \n <ng-container *ngFor=\"let dCol of metadata.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell class=\"entity\" *matCellDef=\"let entity\">\n {{dCol.value(entity)}}\n </mat-cell>\n </ng-container>\n \n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns\"></mat-row>\n </mat-table>\n\n <div class=\"array-error\" *ngIf=\"metadata.required && !dataSource.data.length\">\n {{metadata.missingErrorMessage}}\n </div>\n</div>", styles: ["mat-form-field{width:100%}.buttons{display:flex;justify-content:space-between;margin-bottom:10px;margin-top:5px}mat-table{border:1px solid #E0E0E0;border-radius:5px;padding-top:5px;padding-bottom:25px}.mat-column-select{flex:0 0 75px}.array-error{display:flex;align-items:center;justify-content:center;margin-top:-25.8px;border:1px solid #E0E0E0;background-color:#f8d3d7;color:#721c24;height:25.8px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}.date-time{display:flex;align-items:baseline}.date-time .timepicker{margin-left:10px}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$4.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { type: i2$4.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { type: i2$2.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i3$3.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i4$2.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { type: i2.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i4$2.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { type: i4$2.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2$4.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i1$1.MatSuffix, selector: "[matSuffix]" }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i4$2.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { type: i4$2.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { type: i4$2.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { type: i4$2.MatCellDef, selector: "[matCellDef]" }, { type: i4$2.MatCell, selector: "mat-cell, td[mat-cell]" }, { type: i4$2.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { type: i4$2.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
2019
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ArrayDateTimeInputComponent, decorators: [{
2020
+ type: Component,
2021
+ args: [{ selector: 'array-date-time-input', template: "<div class=\"mat-elevation-z8\" style=\"border-radius: 5px;padding: 15px;margin-bottom: 15px;margin-top: 15px;\">\n \n <div class=\"date-time\">\n <mat-form-field appearance=\"standard\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"input\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [matDatepicker]=\"picker\"\n [required]=\"metadata.required\"\n [min]=\"metadata.minDate ? metadata.minDate(input) : undefined\"\n [max]=\"metadata.maxDate ? metadata.maxDate(input) : undefined\"\n [matDatepickerFilter]=\"metadata.filterDate ?? DateUtilities.defaultDateFilter\"\n >\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n <mat-form-field class=\"timepicker\">\n <mat-label>{{metadata.timeDisplayName}}</mat-label>\n <mat-select\n [(ngModel)]=\"time\"\n [name]=\"key.toString() + 'time'\"\n #timeModel=\"ngModel\"\n [required]=\"metadata.required\"\n >\n <mat-option *ngFor=\"let validTime of DateUtilities.getValidTimesForDropdown(\n DateUtilities.asDate(input),\n metadata.times,\n metadata.minTime,\n metadata.maxTime,\n metadata.filterTime\n )\"\n [value]=\"validTime.value\"\n >\n {{validTime.displayName}}\n </mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(timeModel)}}</mat-error>\n </mat-form-field>\n </div>\n <div class=\"buttons\">\n <button mat-raised-button\n [disabled]=\"model.errors || timeModel.errors || DateUtilities.timeIsUnprocessable(time)\"\n (click)=\"addDateTime()\">\n {{metadata.addButtonLabel}}\n </button>\n <button mat-raised-button\n [disabled]=\"!selection.selected.length\"\n (click)=\"remove()\">\n {{metadata.removeButtonLabel}}\n </button>\n </div>\n\n <mat-table [dataSource]=\"dataSource\">\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox [disabled]=\"!dataSource.data.length\" (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\" [indeterminate]=\"selection.hasValue() && !isAllSelected()\"></mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let module\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(module) : null\" [checked]=\"selection.isSelected(module)\"></mat-checkbox>\n </mat-cell>\n </ng-container>\n \n <ng-container *ngFor=\"let dCol of metadata.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell class=\"entity\" *matCellDef=\"let entity\">\n {{dCol.value(entity)}}\n </mat-cell>\n </ng-container>\n \n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns\"></mat-row>\n </mat-table>\n\n <div class=\"array-error\" *ngIf=\"metadata.required && !dataSource.data.length\">\n {{metadata.missingErrorMessage}}\n </div>\n</div>", styles: ["mat-form-field{width:100%}.buttons{display:flex;justify-content:space-between;margin-bottom:10px;margin-top:5px}mat-table{border:1px solid #E0E0E0;border-radius:5px;padding-top:5px;padding-bottom:25px}.mat-column-select{flex:0 0 75px}.array-error{display:flex;align-items:center;justify-content:center;margin-top:-25.8px;border:1px solid #E0E0E0;background-color:#f8d3d7;color:#721c24;height:25.8px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}.date-time{display:flex;align-items:baseline}.date-time .timepicker{margin-left:10px}\n"] }]
2022
+ }] });
2023
+
2024
+ /* eslint-disable jsdoc/require-jsdoc */
2025
+ class ArrayDateRangeInputComponent extends ArrayTableComponent {
2026
+ constructor() {
2027
+ super(...arguments);
2028
+ this.DateUtilities = DateUtilities;
2029
+ }
2030
+ ngOnInit() {
2031
+ super.ngOnInit();
2032
+ this.input = {
2033
+ start: undefined,
2034
+ end: undefined,
2035
+ values: undefined
2036
+ };
2037
+ }
2038
+ /**
2039
+ * Adds a DateRange to the array.
2040
+ */
2041
+ addDateRange() {
2042
+ if (this.input && this.dateRangeStart && this.dateRangeEnd) {
2043
+ this.input.start = new Date(this.dateRangeStart);
2044
+ this.input.end = new Date(this.dateRangeEnd);
2045
+ const values = DateUtilities.getDatesBetween(this.input.start, this.input.end, this.metadata.filter);
2046
+ this.input.values = values.length ? values : undefined;
2047
+ this.add();
2048
+ }
2049
+ }
2050
+ resetInput() {
2051
+ this.input = undefined;
2052
+ this.dateRangeStart = undefined;
2053
+ this.dateRangeEnd = undefined;
2054
+ }
2055
+ }
2056
+ ArrayDateRangeInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ArrayDateRangeInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2057
+ ArrayDateRangeInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: ArrayDateRangeInputComponent, selector: "array-date-range-input", usesInheritance: true, ngImport: i0, template: "<div class=\"mat-elevation-z8\" style=\"border-radius: 5px;padding: 15px;margin-bottom: 15px;margin-top: 15px;\">\n\n <mat-form-field appearance=\"standard\">\n <mat-label>{{metadata.displayName}}</mat-label>\n \n <mat-date-range-input [rangePicker]=\"picker\" [required]=\"metadata.required\" [dateFilter]=\"metadata.filter ? metadata.filter : DateUtilities.defaultDateFilter\">\n <input matStartDate\n [(ngModel)]=\"dateRangeStart\"\n [name]=\"key.toString() + 'start'\"\n #startModel=\"ngModel\"\n [required]=\"metadata.required\"\n [min]=\"metadata.minStart ? metadata.minStart(input?.start) : undefined\"\n [max]=\"metadata.maxStart ? metadata.maxStart(input?.start) : undefined\"\n [placeholder]=\"metadata.placeholderStart\"\n >\n <input matEndDate\n [(ngModel)]=\"dateRangeEnd\"\n [name]=\"key.toString() + 'end'\"\n #endModel=\"ngModel\"\n [required]=\"metadata.required\"\n [min]=\"metadata.minEnd ? metadata.minEnd(input?.end) : undefined\"\n [max]=\"metadata.maxEnd ? metadata.maxEnd(input?.end) : undefined\"\n [placeholder]=\"metadata.placeholderEnd\"\n >\n </mat-date-range-input>\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-date-range-picker #picker></mat-date-range-picker>\n\n <mat-error *ngIf=\"startModel.errors\">{{getValidationErrorMessage(startModel)}}</mat-error>\n <mat-error *ngIf=\"!startModel.errors && endModel.errors\">{{getValidationErrorMessage(endModel)}}</mat-error>\n </mat-form-field>\n \n <div class=\"buttons\">\n <button mat-raised-button\n [disabled]=\"startModel.errors || endModel.errors\"\n (click)=\"addDateRange()\">\n {{metadata.addButtonLabel}}\n </button>\n <button mat-raised-button\n [disabled]=\"!selection.selected.length\"\n (click)=\"remove()\">\n {{metadata.removeButtonLabel}}\n </button>\n </div>\n\n <mat-table [dataSource]=\"dataSource\">\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox [disabled]=\"!dataSource.data.length\" (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\" [indeterminate]=\"selection.hasValue() && !isAllSelected()\"></mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let module\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(module) : null\" [checked]=\"selection.isSelected(module)\"></mat-checkbox>\n </mat-cell>\n </ng-container>\n \n <ng-container *ngFor=\"let dCol of metadata.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell class=\"entity\" *matCellDef=\"let entity\">\n {{dCol.value(entity)}}\n </mat-cell>\n </ng-container>\n \n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns\"></mat-row>\n </mat-table>\n\n <div class=\"array-error\" *ngIf=\"metadata.required && !dataSource.data.length\">\n {{metadata.missingErrorMessage}}\n </div>\n</div>", styles: ["mat-form-field{width:100%}.buttons{display:flex;justify-content:space-between;margin-bottom:10px;margin-top:5px}mat-table{border:1px solid #E0E0E0;border-radius:5px;padding-top:5px;padding-bottom:25px}.mat-column-select{flex:0 0 75px}.array-error{display:flex;align-items:center;justify-content:center;margin-top:-25.8px;border:1px solid #E0E0E0;background-color:#f8d3d7;color:#721c24;height:25.8px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$4.MatDateRangeInput, selector: "mat-date-range-input", inputs: ["rangePicker", "required", "dateFilter", "min", "max", "disabled", "separator", "comparisonStart", "comparisonEnd"], exportAs: ["matDateRangeInput"] }, { type: i2$4.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { type: i2$4.MatDateRangePicker, selector: "mat-date-range-picker", exportAs: ["matDateRangePicker"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i4$2.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { type: i2.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i4$2.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { type: i4$2.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i2$4.MatStartDate, selector: "input[matStartDate]", inputs: ["errorStateMatcher"], outputs: ["dateChange", "dateInput"] }, { type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2$4.MatEndDate, selector: "input[matEndDate]", inputs: ["errorStateMatcher"], outputs: ["dateChange", "dateInput"] }, { type: i1$1.MatSuffix, selector: "[matSuffix]" }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }, { type: i4$2.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { type: i4$2.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { type: i4$2.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { type: i4$2.MatCellDef, selector: "[matCellDef]" }, { type: i4$2.MatCell, selector: "mat-cell, td[mat-cell]" }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i4$2.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { type: i4$2.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }] });
2058
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ArrayDateRangeInputComponent, decorators: [{
2059
+ type: Component,
2060
+ args: [{ selector: 'array-date-range-input', template: "<div class=\"mat-elevation-z8\" style=\"border-radius: 5px;padding: 15px;margin-bottom: 15px;margin-top: 15px;\">\n\n <mat-form-field appearance=\"standard\">\n <mat-label>{{metadata.displayName}}</mat-label>\n \n <mat-date-range-input [rangePicker]=\"picker\" [required]=\"metadata.required\" [dateFilter]=\"metadata.filter ? metadata.filter : DateUtilities.defaultDateFilter\">\n <input matStartDate\n [(ngModel)]=\"dateRangeStart\"\n [name]=\"key.toString() + 'start'\"\n #startModel=\"ngModel\"\n [required]=\"metadata.required\"\n [min]=\"metadata.minStart ? metadata.minStart(input?.start) : undefined\"\n [max]=\"metadata.maxStart ? metadata.maxStart(input?.start) : undefined\"\n [placeholder]=\"metadata.placeholderStart\"\n >\n <input matEndDate\n [(ngModel)]=\"dateRangeEnd\"\n [name]=\"key.toString() + 'end'\"\n #endModel=\"ngModel\"\n [required]=\"metadata.required\"\n [min]=\"metadata.minEnd ? metadata.minEnd(input?.end) : undefined\"\n [max]=\"metadata.maxEnd ? metadata.maxEnd(input?.end) : undefined\"\n [placeholder]=\"metadata.placeholderEnd\"\n >\n </mat-date-range-input>\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-date-range-picker #picker></mat-date-range-picker>\n\n <mat-error *ngIf=\"startModel.errors\">{{getValidationErrorMessage(startModel)}}</mat-error>\n <mat-error *ngIf=\"!startModel.errors && endModel.errors\">{{getValidationErrorMessage(endModel)}}</mat-error>\n </mat-form-field>\n \n <div class=\"buttons\">\n <button mat-raised-button\n [disabled]=\"startModel.errors || endModel.errors\"\n (click)=\"addDateRange()\">\n {{metadata.addButtonLabel}}\n </button>\n <button mat-raised-button\n [disabled]=\"!selection.selected.length\"\n (click)=\"remove()\">\n {{metadata.removeButtonLabel}}\n </button>\n </div>\n\n <mat-table [dataSource]=\"dataSource\">\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox [disabled]=\"!dataSource.data.length\" (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\" [indeterminate]=\"selection.hasValue() && !isAllSelected()\"></mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let module\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(module) : null\" [checked]=\"selection.isSelected(module)\"></mat-checkbox>\n </mat-cell>\n </ng-container>\n \n <ng-container *ngFor=\"let dCol of metadata.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell class=\"entity\" *matCellDef=\"let entity\">\n {{dCol.value(entity)}}\n </mat-cell>\n </ng-container>\n \n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns\"></mat-row>\n </mat-table>\n\n <div class=\"array-error\" *ngIf=\"metadata.required && !dataSource.data.length\">\n {{metadata.missingErrorMessage}}\n </div>\n</div>", styles: ["mat-form-field{width:100%}.buttons{display:flex;justify-content:space-between;margin-bottom:10px;margin-top:5px}mat-table{border:1px solid #E0E0E0;border-radius:5px;padding-top:5px;padding-bottom:25px}.mat-column-select{flex:0 0 75px}.array-error{display:flex;align-items:center;justify-content:center;margin-top:-25.8px;border:1px solid #E0E0E0;background-color:#f8d3d7;color:#721c24;height:25.8px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}\n"] }]
2061
+ }] });
2062
+
2063
+ /* eslint-disable jsdoc/require-jsdoc */
2064
+ class ArrayStringChipsInputComponent extends NgxMatEntityBaseInputComponent {
2065
+ constructor() {
2066
+ super(...arguments);
2067
+ this.chipsInput = '';
2068
+ }
2069
+ ngOnInit() {
2070
+ super.ngOnInit();
2071
+ if (this.entity[this.key]?.length) {
2072
+ this.stringChipsArrayValues = this.entity[this.key];
2073
+ }
2074
+ }
2075
+ /**
2076
+ * Handles adding strings to the chipsArray.
2077
+ * Checks validation and also creates a new array if it is undefined.
2078
+ * This is needed because two things are validated: The array itself
2079
+ * and the contents of the array. And we need a way to display an
2080
+ * mat-error. As the only validation for the array is whether or not
2081
+ * it contains values, we can set it to undefined when the last element is removed
2082
+ * (removeStringChipArrayValue). That way we can use the "required" validator.
2083
+ *
2084
+ * @param event - The event that fires when a new chip is completed.
2085
+ */
2086
+ addStringChipArrayValue(event) {
2087
+ const value = (event.value || '').trim();
2088
+ if (value) {
2089
+ if (this.metadata.minLength && value.length < this.metadata.minLength) {
2090
+ return;
935
2091
  }
936
- this.entityArrayValues = this.entity[this.propertyKey];
937
- if (this.metadataEntityArray.createInline === undefined) {
938
- this.metadataEntityArray.createInline = true;
2092
+ if (this.metadata.maxLength && value.length > this.metadata.maxLength) {
2093
+ return;
939
2094
  }
940
- if (!this.metadataEntityArray.createInline && !this.metadataEntityArray.createDialogData) {
941
- this.metadataEntityArray.createDialogData = {
942
- title: 'Add'
943
- };
2095
+ if (this.metadata.regex && !value.match(this.metadata.regex)) {
2096
+ return;
944
2097
  }
945
- // TODO
946
- const givenDisplayColumns = this.metadataEntityArray.displayColumns.map((v) => v.displayName);
947
- if (givenDisplayColumns.find((s) => s === 'select')) {
948
- throw new Error(`The name "select" for a display column is reserved.
949
- Please choose a different name.`);
2098
+ if (!this.stringChipsArrayValues) {
2099
+ if (this.entity[this.key] == null) {
2100
+ this.entity[this.key] = [];
2101
+ }
2102
+ this.stringChipsArrayValues = this.entity[this.key];
950
2103
  }
951
- this.displayedColumns = ['select'].concat(givenDisplayColumns);
952
- this.dataSource = new MatTableDataSource();
953
- this.dataSource.data = this.entityArrayValues;
954
- this.arrayItem = new this.metadataEntityArray.EntityClass();
955
- this.arrayItemInlineRows = EntityUtilities.getEntityRows(this.arrayItem, this.hideOmitForCreate === false ? false : true, this.hideOmitForEdit ? true : false);
956
- this.arrayItemPriorChanges = cloneDeep(this.arrayItem);
957
- this.dialogInputData = {
958
- entity: this.arrayItem,
959
- createDialogData: this.metadataEntityArray.createDialogData,
960
- getValidationErrorMessage: this.getValidationErrorMessage
2104
+ this.stringChipsArrayValues.push(value);
2105
+ }
2106
+ event.chipInput?.clear();
2107
+ }
2108
+ /**
2109
+ * Removes the given value from the array.
2110
+ * Sets the array to undefined if it is now empty.
2111
+ * This is needed because two things are validated: The array itself
2112
+ * and the contents of the array. And we need a way to display an
2113
+ * mat-error. As the only validation for the array is whether or not
2114
+ * it is empty, setting it to undefined here enables us to use the "required" validator.
2115
+ *
2116
+ * @param value - The string to remove from the array.
2117
+ */
2118
+ removeStringChipArrayValue(value) {
2119
+ this.stringChipsArrayValues?.splice(this.stringChipsArrayValues.indexOf(value), 1);
2120
+ if (!this.stringChipsArrayValues?.length) {
2121
+ this.entity[this.key] = undefined;
2122
+ this.stringChipsArrayValues = this.entity[this.key];
2123
+ }
2124
+ }
2125
+ /**
2126
+ * Handles adding a string to the array when an autocomplete value has been selected.
2127
+ *
2128
+ * @param event - The autocomplete selected event.
2129
+ * @param chipsInput - The element where the user typed the value.
2130
+ */
2131
+ selected(event, chipsInput) {
2132
+ const value = (event.option.viewValue || '').trim();
2133
+ if (this.metadata.minLength && value.length < this.metadata.minLength) {
2134
+ return;
2135
+ }
2136
+ if (this.metadata.maxLength && value.length > this.metadata.maxLength) {
2137
+ return;
2138
+ }
2139
+ if (this.metadata.regex && !value.match(this.metadata.regex)) {
2140
+ return;
2141
+ }
2142
+ if (!this.stringChipsArrayValues) {
2143
+ if (this.entity[this.key] == null) {
2144
+ this.entity[this.key] = [];
2145
+ }
2146
+ this.stringChipsArrayValues = this.entity[this.key];
2147
+ }
2148
+ this.stringChipsArrayValues.push(value);
2149
+ chipsInput.value = '';
2150
+ }
2151
+ }
2152
+ ArrayStringChipsInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ArrayStringChipsInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2153
+ ArrayStringChipsInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: ArrayStringChipsInputComponent, selector: "array-string-chips-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-chip-list #chipList\n (ngModelChange)=\"emitChange()\"\n [(ngModel)]=\"entity[key]\" [name]=\"key.toString()\" #model=\"ngModel\"\n [required]=\"metadata.required\"\n >\n <mat-chip *ngFor=\"let value of stringChipsArrayValues\" (removed)=\"removeStringChipArrayValue(value)\">\n {{value}}\n <button matChipRemove>\n <i class=\"{{metadata.deleteIcon}}\"></i>\n </button>\n </mat-chip>\n <input matInput\n [matChipInputFor]=\"chipList\"\n [matChipInputAddOnBlur]=\"true\"\n (matChipInputTokenEnd)=\"addStringChipArrayValue($event)\"\n [(ngModel)]=\"chipsInput\" [name]=\"key.toString()\" #chipsModel=\"ngModel\"\n [minlength]='metadata.minLength ?? null'\n [maxlength]='metadata.maxLength ?? null'\n [pattern]=\"metadata.regex ?? '[\\\\s\\\\S]*'\"\n >\n <mat-error *ngIf=\"chipsModel.errors\">{{getValidationErrorMessage(chipsModel)}}</mat-error>\n </mat-chip-list>\n <mat-error *ngIf=\"!chipsModel.errors\">{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$5.MatChipList, selector: "mat-chip-list", inputs: ["errorStateMatcher", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "aria-orientation", "selectable", "tabIndex"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2$5.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i2$5.MatChipRemove, selector: "[matChipRemove]" }, { type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i2$5.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3$1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { type: i3$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { type: i3$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }] });
2154
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ArrayStringChipsInputComponent, decorators: [{
2155
+ type: Component,
2156
+ args: [{ selector: 'array-string-chips-input', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-chip-list #chipList\n (ngModelChange)=\"emitChange()\"\n [(ngModel)]=\"entity[key]\" [name]=\"key.toString()\" #model=\"ngModel\"\n [required]=\"metadata.required\"\n >\n <mat-chip *ngFor=\"let value of stringChipsArrayValues\" (removed)=\"removeStringChipArrayValue(value)\">\n {{value}}\n <button matChipRemove>\n <i class=\"{{metadata.deleteIcon}}\"></i>\n </button>\n </mat-chip>\n <input matInput\n [matChipInputFor]=\"chipList\"\n [matChipInputAddOnBlur]=\"true\"\n (matChipInputTokenEnd)=\"addStringChipArrayValue($event)\"\n [(ngModel)]=\"chipsInput\" [name]=\"key.toString()\" #chipsModel=\"ngModel\"\n [minlength]='metadata.minLength ?? null'\n [maxlength]='metadata.maxLength ?? null'\n [pattern]=\"metadata.regex ?? '[\\\\s\\\\S]*'\"\n >\n <mat-error *ngIf=\"chipsModel.errors\">{{getValidationErrorMessage(chipsModel)}}</mat-error>\n </mat-chip-list>\n <mat-error *ngIf=\"!chipsModel.errors\">{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
2157
+ }] });
2158
+
2159
+ /* eslint-disable jsdoc/require-jsdoc */
2160
+ class ArrayStringAutocompleteChipsComponent extends NgxMatEntityBaseInputComponent {
2161
+ constructor() {
2162
+ super(...arguments);
2163
+ this.chipsInput = '';
2164
+ }
2165
+ ngOnInit() {
2166
+ super.ngOnInit();
2167
+ this.filteredAutocompleteStrings = LodashUtilities.cloneDeep(this.metadata.autocompleteValues);
2168
+ if (this.entity[this.key]?.length) {
2169
+ this.stringChipsArrayValues = this.entity[this.key];
2170
+ }
2171
+ }
2172
+ /**
2173
+ * Handles adding strings to the chipsArray.
2174
+ * Checks validation and also creates a new array if it is undefined.
2175
+ * This is needed because two things are validated: The array itself
2176
+ * and the contents of the array. And we need a way to display an
2177
+ * mat-error. As the only validation for the array is whether or not
2178
+ * it contains values, we can set it to undefined when the last element is removed
2179
+ * (removeStringChipArrayValue). That way we can use the "required" validator.
2180
+ *
2181
+ * @param event - The event that fires when a new chip is completed.
2182
+ */
2183
+ addStringChipArrayValue(event) {
2184
+ const value = (event.value || '').trim();
2185
+ if (value) {
2186
+ if (this.metadata.minLength && value.length < this.metadata.minLength) {
2187
+ return;
2188
+ }
2189
+ if (this.metadata.maxLength && value.length > this.metadata.maxLength) {
2190
+ return;
2191
+ }
2192
+ if (this.metadata.regex && !value.match(this.metadata.regex)) {
2193
+ return;
2194
+ }
2195
+ if (!this.stringChipsArrayValues) {
2196
+ if (this.entity[this.key] == null) {
2197
+ this.entity[this.key] = [];
2198
+ }
2199
+ this.stringChipsArrayValues = this.entity[this.key];
2200
+ }
2201
+ this.stringChipsArrayValues.push(value);
2202
+ }
2203
+ event.chipInput?.clear();
2204
+ }
2205
+ /**
2206
+ * Removes the given value from the array.
2207
+ * Sets the array to undefined if it is now empty.
2208
+ * This is needed because two things are validated: The array itself
2209
+ * and the contents of the array. And we need a way to display an
2210
+ * mat-error. As the only validation for the array is whether or not
2211
+ * it is empty, setting it to undefined here enables us to use the "required" validator.
2212
+ *
2213
+ * @param value - The string to remove from the array.
2214
+ */
2215
+ removeStringChipArrayValue(value) {
2216
+ this.stringChipsArrayValues?.splice(this.stringChipsArrayValues.indexOf(value), 1);
2217
+ if (!this.stringChipsArrayValues?.length) {
2218
+ this.entity[this.key] = undefined;
2219
+ this.stringChipsArrayValues = this.entity[this.key];
2220
+ }
2221
+ }
2222
+ /**
2223
+ * Handles adding a string to the array when an autocomplete value has been selected.
2224
+ *
2225
+ * @param event - The autocomplete selected event.
2226
+ * @param chipsInput - The element where the user typed the value.
2227
+ */
2228
+ selected(event, chipsInput) {
2229
+ const value = (event.option.viewValue || '').trim();
2230
+ if (this.metadata.minLength && value.length < this.metadata.minLength) {
2231
+ return;
2232
+ }
2233
+ if (this.metadata.maxLength && value.length > this.metadata.maxLength) {
2234
+ return;
2235
+ }
2236
+ if (this.metadata.regex && !value.match(this.metadata.regex)) {
2237
+ return;
2238
+ }
2239
+ if (!this.stringChipsArrayValues) {
2240
+ if (this.entity[this.key] == null) {
2241
+ this.entity[this.key] = [];
2242
+ }
2243
+ this.stringChipsArrayValues = this.entity[this.key];
2244
+ }
2245
+ this.stringChipsArrayValues.push(value);
2246
+ chipsInput.value = '';
2247
+ }
2248
+ /**
2249
+ * Dynamically filters the Autocomplete options when the user inputs something.
2250
+ *
2251
+ * @param input - The input of the user.
2252
+ */
2253
+ filterAutocompleteStrings(input) {
2254
+ if (input != null) {
2255
+ const filterValue = input.toLowerCase();
2256
+ this.filteredAutocompleteStrings = this.metadata.autocompleteValues.filter(s => s.toLowerCase().includes(filterValue));
2257
+ }
2258
+ }
2259
+ }
2260
+ ArrayStringAutocompleteChipsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ArrayStringAutocompleteChipsComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2261
+ ArrayStringAutocompleteChipsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: ArrayStringAutocompleteChipsComponent, selector: "array-string-autocomplete-chips", usesInheritance: true, ngImport: i0, template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-chip-list #chipList\n (ngModelChange)=\"emitChange()\"\n [(ngModel)]=\"entity[key]\" [name]=\"key.toString()\" #model=\"ngModel\"\n [required]=\"metadata.required\"\n >\n <mat-chip *ngFor=\"let value of stringChipsArrayValues\" (removed)=\"removeStringChipArrayValue(value)\">\n {{value}}\n <button matChipRemove>\n <i class=\"{{metadata.deleteIcon}}\"></i>\n </button>\n </mat-chip>\n <input matInput\n [matChipInputFor]=\"chipList\"\n [matAutocomplete]=\"auto\"\n [matChipInputAddOnBlur]=\"true\"\n (matChipInputTokenEnd)=\"addStringChipArrayValue($event)\"\n (keyup)=\"filterAutocompleteStrings(chipsInput)\"\n [(ngModel)]=\"chipsInput\" [name]=\"key.toString()\" #chipsModel=\"ngModel\"\n #chipsElement\n [minlength]='metadata.minLength ?? null'\n [maxlength]='metadata.maxLength ?? null'\n [pattern]=\"metadata.regex ?? '[\\\\s\\\\S]*'\"\n >\n <mat-error *ngIf=\"chipsModel.errors\">{{getValidationErrorMessage(chipsModel)}}</mat-error>\n </mat-chip-list>\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"selected($event, chipsElement)\">\n <mat-option *ngFor=\"let value of metadata.autocompleteValues\" [value]=\"value\">\n {{value}}\n </mat-option>\n </mat-autocomplete>\n <mat-error *ngIf=\"!chipsModel.errors\">{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$5.MatChipList, selector: "mat-chip-list", inputs: ["errorStateMatcher", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "aria-orientation", "selectable", "tabIndex"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i2$1.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i3$3.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2$5.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i2$5.MatChipRemove, selector: "[matChipRemove]" }, { type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i2$5.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i2$1.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3$1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { type: i3$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { type: i3$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }] });
2262
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ArrayStringAutocompleteChipsComponent, decorators: [{
2263
+ type: Component,
2264
+ args: [{ selector: 'array-string-autocomplete-chips', template: "<mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-chip-list #chipList\n (ngModelChange)=\"emitChange()\"\n [(ngModel)]=\"entity[key]\" [name]=\"key.toString()\" #model=\"ngModel\"\n [required]=\"metadata.required\"\n >\n <mat-chip *ngFor=\"let value of stringChipsArrayValues\" (removed)=\"removeStringChipArrayValue(value)\">\n {{value}}\n <button matChipRemove>\n <i class=\"{{metadata.deleteIcon}}\"></i>\n </button>\n </mat-chip>\n <input matInput\n [matChipInputFor]=\"chipList\"\n [matAutocomplete]=\"auto\"\n [matChipInputAddOnBlur]=\"true\"\n (matChipInputTokenEnd)=\"addStringChipArrayValue($event)\"\n (keyup)=\"filterAutocompleteStrings(chipsInput)\"\n [(ngModel)]=\"chipsInput\" [name]=\"key.toString()\" #chipsModel=\"ngModel\"\n #chipsElement\n [minlength]='metadata.minLength ?? null'\n [maxlength]='metadata.maxLength ?? null'\n [pattern]=\"metadata.regex ?? '[\\\\s\\\\S]*'\"\n >\n <mat-error *ngIf=\"chipsModel.errors\">{{getValidationErrorMessage(chipsModel)}}</mat-error>\n </mat-chip-list>\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"selected($event, chipsElement)\">\n <mat-option *ngFor=\"let value of metadata.autocompleteValues\" [value]=\"value\">\n {{value}}\n </mat-option>\n </mat-autocomplete>\n <mat-error *ngIf=\"!chipsModel.errors\">{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
2265
+ }] });
2266
+
2267
+ /* eslint-disable jsdoc/require-jsdoc */
2268
+ class DateInputComponent extends NgxMatEntityBaseInputComponent {
2269
+ constructor() {
2270
+ super(...arguments);
2271
+ this.DateUtilities = DateUtilities;
2272
+ this.defaultDateFilter = () => true;
2273
+ }
2274
+ }
2275
+ DateInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: DateInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2276
+ DateInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: DateInputComponent, selector: "date-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field appearance=\"standard\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n (ngModelChange)=\"emitChange()\"\n matInput\n [(ngModel)]=\"entity[key]\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [matDatepicker]=\"picker\"\n [required]=\"metadata.required\"\n [min]=\"metadata.min ? metadata.min(DateUtilities.asDate(entity[key])) : undefined\"\n [max]=\"metadata.max ? metadata.max(DateUtilities.asDate(entity[key])) : undefined\"\n [matDatepickerFilter]=\"metadata.filter ?? defaultDateFilter\"\n >\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$4.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { type: i2$4.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2$4.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i1$1.MatSuffix, selector: "[matSuffix]" }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }] });
2277
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: DateInputComponent, decorators: [{
2278
+ type: Component,
2279
+ args: [{ selector: 'date-input', template: "<mat-form-field appearance=\"standard\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n (ngModelChange)=\"emitChange()\"\n matInput\n [(ngModel)]=\"entity[key]\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [matDatepicker]=\"picker\"\n [required]=\"metadata.required\"\n [min]=\"metadata.min ? metadata.min(DateUtilities.asDate(entity[key])) : undefined\"\n [max]=\"metadata.max ? metadata.max(DateUtilities.asDate(entity[key])) : undefined\"\n [matDatepickerFilter]=\"metadata.filter ?? defaultDateFilter\"\n >\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
2280
+ }] });
2281
+
2282
+ /* eslint-disable jsdoc/require-jsdoc */
2283
+ const EMPTY_DATERANGE = {
2284
+ start: undefined,
2285
+ end: undefined,
2286
+ values: undefined
2287
+ };
2288
+ class DateRangeInputComponent extends NgxMatEntityBaseInputComponent {
2289
+ constructor() {
2290
+ super(...arguments);
2291
+ this.defaultDateFilter = () => true;
2292
+ }
2293
+ ngOnInit() {
2294
+ super.ngOnInit();
2295
+ this.dateRange = LodashUtilities.cloneDeep(this.entity[this.key]) ?? EMPTY_DATERANGE;
2296
+ this.dateRangeStart = new Date(this.dateRange.start);
2297
+ this.dateRangeEnd = new Date(this.dateRange.end);
2298
+ this.setDateRangeValues();
2299
+ }
2300
+ /**
2301
+ * Updates the date range values based on the start and end date.
2302
+ */
2303
+ setDateRangeValues() {
2304
+ if (this.dateRangeStart && this.dateRangeEnd) {
2305
+ this.dateRange.start = new Date(this.dateRangeStart);
2306
+ this.dateRange.end = new Date(this.dateRangeEnd);
2307
+ const values = DateUtilities.getDatesBetween(new Date(this.dateRange.start), new Date(this.dateRange.end), this.metadata.filter);
2308
+ this.dateRange.values = values.length ? values : undefined;
2309
+ }
2310
+ else {
2311
+ this.dateRange.values = undefined;
2312
+ }
2313
+ this.entity[this.key] = this.dateRange;
2314
+ this.emitChange();
2315
+ }
2316
+ }
2317
+ DateRangeInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: DateRangeInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2318
+ DateRangeInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: DateRangeInputComponent, selector: "date-range-input", usesInheritance: true, ngImport: i0, template: "<mat-form-field appearance=\"standard\">\n <mat-label>{{metadata.displayName}}</mat-label>\n \n <mat-date-range-input [rangePicker]=\"picker\" [required]=\"metadata.required\" [dateFilter]=\"metadata.filter ?? defaultDateFilter\">\n <input matStartDate\n [(ngModel)]=\"dateRangeStart\"\n [name]=\"key.toString() + 'start'\"\n #startModel=\"ngModel\"\n [required]=\"metadata.required\"\n [min]=\"metadata.minStart ? metadata.minStart(dateRange.start) : undefined\"\n [max]=\"metadata.maxStart ? metadata.maxStart(dateRange.start) : undefined\"\n [placeholder]=\"metadata.placeholderStart\"\n (ngModelChange)=\"setDateRangeValues()\"\n >\n <input matEndDate\n [(ngModel)]=\"dateRangeEnd\"\n [name]=\"key.toString() + 'end'\"\n #endModel=\"ngModel\"\n [required]=\"metadata.required\"\n [min]=\"metadata.minEnd ? metadata.minEnd(dateRange.end) : undefined\"\n [max]=\"metadata.maxEnd ? metadata.maxEnd(dateRange.end) : undefined\"\n [placeholder]=\"metadata.placeholderEnd\"\n (ngModelChange)=\"setDateRangeValues()\"\n >\n </mat-date-range-input>\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-date-range-picker #picker></mat-date-range-picker>\n\n <mat-error *ngIf=\"startModel.errors\">{{getValidationErrorMessage(startModel)}}</mat-error>\n <mat-error *ngIf=\"!startModel.errors && endModel.errors\">{{getValidationErrorMessage(endModel)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$4.MatDateRangeInput, selector: "mat-date-range-input", inputs: ["rangePicker", "required", "dateFilter", "min", "max", "disabled", "separator", "comparisonStart", "comparisonEnd"], exportAs: ["matDateRangeInput"] }, { type: i2$4.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { type: i2$4.MatDateRangePicker, selector: "mat-date-range-picker", exportAs: ["matDateRangePicker"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i2$4.MatStartDate, selector: "input[matStartDate]", inputs: ["errorStateMatcher"], outputs: ["dateChange", "dateInput"] }, { type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2$4.MatEndDate, selector: "input[matEndDate]", inputs: ["errorStateMatcher"], outputs: ["dateChange", "dateInput"] }, { type: i1$1.MatSuffix, selector: "[matSuffix]" }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }] });
2319
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: DateRangeInputComponent, decorators: [{
2320
+ type: Component,
2321
+ args: [{ selector: 'date-range-input', template: "<mat-form-field appearance=\"standard\">\n <mat-label>{{metadata.displayName}}</mat-label>\n \n <mat-date-range-input [rangePicker]=\"picker\" [required]=\"metadata.required\" [dateFilter]=\"metadata.filter ?? defaultDateFilter\">\n <input matStartDate\n [(ngModel)]=\"dateRangeStart\"\n [name]=\"key.toString() + 'start'\"\n #startModel=\"ngModel\"\n [required]=\"metadata.required\"\n [min]=\"metadata.minStart ? metadata.minStart(dateRange.start) : undefined\"\n [max]=\"metadata.maxStart ? metadata.maxStart(dateRange.start) : undefined\"\n [placeholder]=\"metadata.placeholderStart\"\n (ngModelChange)=\"setDateRangeValues()\"\n >\n <input matEndDate\n [(ngModel)]=\"dateRangeEnd\"\n [name]=\"key.toString() + 'end'\"\n #endModel=\"ngModel\"\n [required]=\"metadata.required\"\n [min]=\"metadata.minEnd ? metadata.minEnd(dateRange.end) : undefined\"\n [max]=\"metadata.maxEnd ? metadata.maxEnd(dateRange.end) : undefined\"\n [placeholder]=\"metadata.placeholderEnd\"\n (ngModelChange)=\"setDateRangeValues()\"\n >\n </mat-date-range-input>\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-date-range-picker #picker></mat-date-range-picker>\n\n <mat-error *ngIf=\"startModel.errors\">{{getValidationErrorMessage(startModel)}}</mat-error>\n <mat-error *ngIf=\"!startModel.errors && endModel.errors\">{{getValidationErrorMessage(endModel)}}</mat-error>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
2322
+ }] });
2323
+
2324
+ /* eslint-disable jsdoc/require-jsdoc */
2325
+ class DateTimeInputComponent extends NgxMatEntityBaseInputComponent {
2326
+ constructor() {
2327
+ super(...arguments);
2328
+ this.DateUtilities = DateUtilities;
2329
+ this.defaultDateFilter = () => true;
2330
+ }
2331
+ ngOnInit() {
2332
+ super.ngOnInit();
2333
+ this.time = DateUtilities.getTimeFromDate(this.entity[this.key]);
2334
+ this.timeDropdownValues = this.metadata.times;
2335
+ if (this.entity[this.key] != null) {
2336
+ this.dateTime = new Date(this.entity[this.key]);
2337
+ }
2338
+ }
2339
+ /**
2340
+ * Checks if two times are equal. Is needed for the dropdown.
2341
+ *
2342
+ * @param time1 - The first time to compare.
2343
+ * @param time2 - The second time to compare.
2344
+ * @returns Whether or not the time objects are the same.
2345
+ */
2346
+ compareTimes(time1, time2) {
2347
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
2348
+ return time1 && time2 && time1.hours === time2.hours && time1.minutes === time2.minutes;
2349
+ }
2350
+ /**
2351
+ * Sets the time on a datetime property.
2352
+ */
2353
+ setTime() {
2354
+ if (!this.dateTime) {
2355
+ this.entity[this.key] = undefined;
2356
+ this.emitChange();
2357
+ return;
2358
+ }
2359
+ this.entity[this.key] = new Date(this.dateTime);
2360
+ if (this.time?.hours != null && this.time?.minutes != null) {
2361
+ this.entity[this.key].setHours(this.time.hours, this.time.minutes, 0, 0);
2362
+ }
2363
+ else {
2364
+ this.entity[this.key].setHours(0, 0, 0, 0);
2365
+ }
2366
+ this.emitChange();
2367
+ }
2368
+ }
2369
+ DateTimeInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: DateTimeInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2370
+ DateTimeInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: DateTimeInputComponent, selector: "date-time-input", usesInheritance: true, ngImport: i0, template: "<div class=\"date-time\">\n <mat-form-field appearance=\"standard\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"dateTime\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [matDatepicker]=\"picker\"\n [required]=\"metadata.required\"\n [min]=\"metadata.minDate ? metadata.minDate(dateTime) : undefined\"\n [max]=\"metadata.maxDate ? metadata.maxDate(dateTime) : undefined\"\n [matDatepickerFilter]=\"metadata.filterDate ?? defaultDateFilter\"\n (dateInput)=\"setTime()\"\n >\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n <mat-form-field class=\"timepicker\">\n <mat-label>{{metadata.timeDisplayName}}</mat-label>\n <mat-select\n [(ngModel)]=\"time\"\n [name]=\"key.toString() + 'time'\"\n #timeModel=\"ngModel\"\n [required]=\"metadata.required\"\n [compareWith]=\"compareTimes\"\n (ngModelChange)=\"setTime()\"\n >\n <mat-option *ngFor=\"let validTime of DateUtilities.getValidTimesForDropdown(\n DateUtilities.asDate(entity[key]),\n metadata.times,\n metadata.minTime,\n metadata.maxTime,\n metadata.filterTime\n )\"\n [value]=\"validTime.value\"\n >\n {{validTime.displayName}}\n </mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(timeModel)}}</mat-error>\n </mat-form-field>\n</div>", styles: ["mat-form-field{width:100%}.date-time{display:flex;align-items:baseline}.date-time .timepicker{margin-left:10px}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$4.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { type: i2$4.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { type: i2$2.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i3$3.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i3$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2$4.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i1$1.MatSuffix, selector: "[matSuffix]" }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
2371
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: DateTimeInputComponent, decorators: [{
2372
+ type: Component,
2373
+ args: [{ selector: 'date-time-input', template: "<div class=\"date-time\">\n <mat-form-field appearance=\"standard\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"dateTime\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [matDatepicker]=\"picker\"\n [required]=\"metadata.required\"\n [min]=\"metadata.minDate ? metadata.minDate(dateTime) : undefined\"\n [max]=\"metadata.maxDate ? metadata.maxDate(dateTime) : undefined\"\n [matDatepickerFilter]=\"metadata.filterDate ?? defaultDateFilter\"\n (dateInput)=\"setTime()\"\n >\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n <mat-form-field class=\"timepicker\">\n <mat-label>{{metadata.timeDisplayName}}</mat-label>\n <mat-select\n [(ngModel)]=\"time\"\n [name]=\"key.toString() + 'time'\"\n #timeModel=\"ngModel\"\n [required]=\"metadata.required\"\n [compareWith]=\"compareTimes\"\n (ngModelChange)=\"setTime()\"\n >\n <mat-option *ngFor=\"let validTime of DateUtilities.getValidTimesForDropdown(\n DateUtilities.asDate(entity[key]),\n metadata.times,\n metadata.minTime,\n metadata.maxTime,\n metadata.filterTime\n )\"\n [value]=\"validTime.value\"\n >\n {{validTime.displayName}}\n </mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(timeModel)}}</mat-error>\n </mat-form-field>\n</div>", styles: ["mat-form-field{width:100%}.date-time{display:flex;align-items:baseline}.date-time .timepicker{margin-left:10px}\n"] }]
2374
+ }] });
2375
+
2376
+ /**
2377
+ * Adds drag and drop functionality to an element.
2378
+ */
2379
+ class DragDropDirective {
2380
+ constructor() {
2381
+ /**
2382
+ * Emits the dropped files to the parent.
2383
+ */
2384
+ this.files = new EventEmitter();
2385
+ }
2386
+ /**
2387
+ * Prevents the event default.
2388
+ *
2389
+ * @param evt - The Event when dragged files hover over the parent.
2390
+ */
2391
+ onDragOver(evt) {
2392
+ evt.preventDefault();
2393
+ evt.stopPropagation();
2394
+ }
2395
+ /**
2396
+ * Prevents the event default.
2397
+ *
2398
+ * @param evt - The Event when dragged files leave the parent.
2399
+ */
2400
+ onDragLeave(evt) {
2401
+ evt.preventDefault();
2402
+ evt.stopPropagation();
2403
+ }
2404
+ /**
2405
+ * Prevents the event default and emits the dropped files with the output.
2406
+ *
2407
+ * @param evt - The Event when files are dropped.
2408
+ */
2409
+ onDrop(evt) {
2410
+ evt.preventDefault();
2411
+ evt.stopPropagation();
2412
+ if (evt.dataTransfer && evt.dataTransfer.files.length > 0) {
2413
+ this.files.emit(Array.from(evt.dataTransfer.files));
2414
+ }
2415
+ }
2416
+ }
2417
+ DragDropDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: DragDropDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2418
+ DragDropDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.11", type: DragDropDirective, selector: "[dragDrop]", outputs: { files: "files" }, host: { listeners: { "dragover": "onDragOver($event)", "dragleave": "onDragLeave($event)", "drop": "onDrop($event)" } }, ngImport: i0 });
2419
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: DragDropDirective, decorators: [{
2420
+ type: Directive,
2421
+ args: [{
2422
+ // eslint-disable-next-line @angular-eslint/directive-selector
2423
+ selector: '[dragDrop]'
2424
+ }]
2425
+ }], ctorParameters: function () { return []; }, propDecorators: { files: [{
2426
+ type: Output
2427
+ }], onDragOver: [{
2428
+ type: HostListener,
2429
+ args: ['dragover', ['$event']]
2430
+ }], onDragLeave: [{
2431
+ type: HostListener,
2432
+ args: ['dragleave', ['$event']]
2433
+ }], onDrop: [{
2434
+ type: HostListener,
2435
+ args: ['drop', ['$event']]
2436
+ }] } });
2437
+
2438
+ /* eslint-disable jsdoc/require-jsdoc */
2439
+ class FileInputComponent {
2440
+ constructor(dialog) {
2441
+ this.dialog = dialog;
2442
+ this.FileUtilities = FileUtilities;
2443
+ this.fileDataChangeEvent = new EventEmitter();
2444
+ }
2445
+ async ngOnInit() {
2446
+ this.metadata = EntityUtilities.getPropertyMetadata(this.entity, this.key, DecoratorTypes.FILE_DEFAULT);
2447
+ if (this.metadata.multiple) {
2448
+ this.initMultiFile();
2449
+ }
2450
+ else {
2451
+ this.initSingleFile();
2452
+ }
2453
+ this.fileDataChangeEvent.emit(this.singleFileData ?? this.multiFileData);
2454
+ }
2455
+ initMultiFile() {
2456
+ this.multiFileData = this.entity[this.key];
2457
+ if (this.multiFileData) {
2458
+ this.filenames = this.multiFileData.map(f => f.name);
2459
+ }
2460
+ }
2461
+ initSingleFile() {
2462
+ this.singleFileData = this.entity[this.key];
2463
+ if (this.singleFileData) {
2464
+ this.filenames = LodashUtilities.cloneDeep([this.singleFileData.name]);
2465
+ }
2466
+ }
2467
+ async setFileFromInput(event) {
2468
+ const files = event.target.files ?? [];
2469
+ await this.setFile(Array.from(files));
2470
+ }
2471
+ async setFile(files) {
2472
+ // validation done inline
2473
+ if (files.find(f => !FileUtilities.isMimeTypeValid(f.type, this.metadata.allowedMimeTypes))) {
2474
+ this.dialog.open(NgxMatEntityConfirmDialogComponent, {
2475
+ data: this.metadata.mimeTypeErrorDialog,
2476
+ autoFocus: false,
2477
+ restoreFocus: false
2478
+ });
2479
+ this.resetFileInputs();
2480
+ return;
2481
+ }
2482
+ if (files.find(f => f.size > (this.metadata.maxSize * 1000000))) {
2483
+ this.dialog.open(NgxMatEntityConfirmDialogComponent, {
2484
+ data: this.metadata.maxSizeErrorDialog,
2485
+ autoFocus: false,
2486
+ restoreFocus: false
2487
+ });
2488
+ this.resetFileInputs();
2489
+ return;
2490
+ }
2491
+ let fileSizeTotal = 0;
2492
+ for (const file of files) {
2493
+ fileSizeTotal += file.size;
2494
+ }
2495
+ if (fileSizeTotal > (this.metadata.maxSizeTotal * 1000000)) {
2496
+ this.dialog.open(NgxMatEntityConfirmDialogComponent, {
2497
+ data: this.metadata.maxSizeTotalErrorDialog,
2498
+ autoFocus: false,
2499
+ restoreFocus: false
2500
+ });
2501
+ this.resetFileInputs();
2502
+ return;
2503
+ }
2504
+ if (this.metadata.multiple) {
2505
+ await this.setMultiFile(Array.from(files));
2506
+ }
2507
+ else {
2508
+ await this.setSingleFile(files[0]);
2509
+ }
2510
+ this.fileDataChangeEvent.emit(this.singleFileData ?? this.multiFileData);
2511
+ }
2512
+ resetFileInputs() {
2513
+ this.filenames = undefined;
2514
+ this.singleFileData = undefined;
2515
+ this.multiFileData = undefined;
2516
+ this.fileDataChangeEvent.emit();
2517
+ }
2518
+ async setMultiFile(files) {
2519
+ const data = [];
2520
+ for (const file of files) {
2521
+ const fileData = {
2522
+ file: file,
2523
+ name: file.name,
2524
+ type: file.type,
2525
+ size: file.size
961
2526
  };
962
- this.dialogData = new AddArrayItemDialogDataBuilder(this.dialogInputData).getResult();
963
- this.arrayItemDialogRows = EntityUtilities.getEntityRows(this.dialogData.entity, true);
2527
+ data.push(fileData);
2528
+ }
2529
+ this.multiFileData = LodashUtilities.cloneDeep(data);
2530
+ this.filenames = this.multiFileData.map(f => f.name);
2531
+ }
2532
+ async setSingleFile(file) {
2533
+ this.singleFileData = {
2534
+ file: file,
2535
+ name: file.name,
2536
+ type: file.type,
2537
+ size: file.size
2538
+ };
2539
+ this.filenames = LodashUtilities.cloneDeep([this.singleFileData.name]);
2540
+ }
2541
+ removeFile(name) {
2542
+ if (this.metadata.multiple) {
2543
+ this.filenames?.splice(this.filenames.indexOf(name), 1);
2544
+ if (!this.filenames?.length) {
2545
+ this.filenames = undefined;
2546
+ }
2547
+ const fileDataToRemove = this.multiFileData?.find(f => f.name === name);
2548
+ this.multiFileData?.splice(this.multiFileData.indexOf(fileDataToRemove), 1);
2549
+ if (!this.multiFileData?.length) {
2550
+ this.multiFileData = undefined;
2551
+ }
2552
+ }
2553
+ else {
2554
+ this.filenames = undefined;
2555
+ this.singleFileData = undefined;
2556
+ }
2557
+ this.fileDataChangeEvent.emit(this.singleFileData ?? this.multiFileData);
2558
+ }
2559
+ }
2560
+ FileInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: FileInputComponent, deps: [{ token: i1.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
2561
+ FileInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: FileInputComponent, selector: "file-input", inputs: { entity: "entity", key: "key", getValidationErrorMessage: "getValidationErrorMessage" }, outputs: { fileDataChangeEvent: "fileDataChangeEvent" }, ngImport: i0, template: "<input #fileInput\n type=\"file\" hidden\n [multiple]=\"metadata.multiple\"\n [accept]=\"FileUtilities.getAcceptString(metadata.allowedMimeTypes)\"\n (change)=\"setFileFromInput($event)\"\n>\n\n<mat-form-field floatLabel=\"always\" (click)=\"fileInput.click()\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-chip-list #chipList\n [(ngModel)]=\"filenames\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [required]=\"metadata.required\"\n >\n <mat-chip *ngFor=\"let name of filenames\" (removed)=\"removeFile(name)\">\n {{name}}\n <button matChipRemove>\n <i class=\"{{metadata.deleteIcon}}\"></i>\n </button>\n </mat-chip>\n <input [matChipInputFor]=\"chipList\" [readonly]=\"true\">\n </mat-chip-list>\n <button mat-icon-button matSuffix>\n <i class=\"fas fa-upload\"></i>\n </button>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>\n\n<div *ngIf=\"metadata.dragAndDrop\" class=\"dropdown\" dragDrop (files)=\"setFile($event)\">\n <i class=\"fas fa-file-arrow-up\"></i>\n</div>", styles: ["mat-form-field{width:100%}input:hover,mat-form-field:hover{cursor:pointer}i{color:#757575}.dropdown{display:flex;align-items:center;justify-content:center;height:200px;border:2px dashed #757575;border-radius:15px;margin-top:5px;margin-bottom:5px}.dropdown i{font-size:30px}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i2$5.MatChipList, selector: "mat-chip-list", inputs: ["errorStateMatcher", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "aria-orientation", "selectable", "tabIndex"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2$5.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i2$5.MatChipRemove, selector: "[matChipRemove]" }, { type: i2$5.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i1$1.MatSuffix, selector: "[matSuffix]" }, { type: i1$1.MatError, selector: "mat-error", inputs: ["id"] }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: DragDropDirective, selector: "[dragDrop]", outputs: ["files"] }] });
2562
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: FileInputComponent, decorators: [{
2563
+ type: Component,
2564
+ args: [{ selector: 'file-input', template: "<input #fileInput\n type=\"file\" hidden\n [multiple]=\"metadata.multiple\"\n [accept]=\"FileUtilities.getAcceptString(metadata.allowedMimeTypes)\"\n (change)=\"setFileFromInput($event)\"\n>\n\n<mat-form-field floatLabel=\"always\" (click)=\"fileInput.click()\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-chip-list #chipList\n [(ngModel)]=\"filenames\"\n [name]=\"key.toString()\"\n #model=\"ngModel\"\n [required]=\"metadata.required\"\n >\n <mat-chip *ngFor=\"let name of filenames\" (removed)=\"removeFile(name)\">\n {{name}}\n <button matChipRemove>\n <i class=\"{{metadata.deleteIcon}}\"></i>\n </button>\n </mat-chip>\n <input [matChipInputFor]=\"chipList\" [readonly]=\"true\">\n </mat-chip-list>\n <button mat-icon-button matSuffix>\n <i class=\"fas fa-upload\"></i>\n </button>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n</mat-form-field>\n\n<div *ngIf=\"metadata.dragAndDrop\" class=\"dropdown\" dragDrop (files)=\"setFile($event)\">\n <i class=\"fas fa-file-arrow-up\"></i>\n</div>", styles: ["mat-form-field{width:100%}input:hover,mat-form-field:hover{cursor:pointer}i{color:#757575}.dropdown{display:flex;align-items:center;justify-content:center;height:200px;border:2px dashed #757575;border-radius:15px;margin-top:5px;margin-bottom:5px}.dropdown i{font-size:30px}\n"] }]
2565
+ }], ctorParameters: function () { return [{ type: i1.MatDialog }]; }, propDecorators: { entity: [{
2566
+ type: Input
2567
+ }], key: [{
2568
+ type: Input
2569
+ }], getValidationErrorMessage: [{
2570
+ type: Input
2571
+ }], fileDataChangeEvent: [{
2572
+ type: Output
2573
+ }] } });
2574
+
2575
+ /* eslint-disable jsdoc/require-jsdoc */
2576
+ class FileDefaultInputComponent extends NgxMatEntityBaseInputComponent {
2577
+ constructor() {
2578
+ super(...arguments);
2579
+ this.FileUtilities = FileUtilities;
2580
+ }
2581
+ async refreshFileData(fileData) {
2582
+ this.entity[this.key] = fileData;
2583
+ this.emitChange();
2584
+ }
2585
+ }
2586
+ FileDefaultInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: FileDefaultInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2587
+ FileDefaultInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: FileDefaultInputComponent, selector: "file-default-input", usesInheritance: true, ngImport: i0, template: "<div *ngIf=\"metadata.dragAndDrop\" class=\"file-input mat-elevation-z8\">\n <file-input (fileDataChangeEvent)=\"refreshFileData($event)\" [entity]=\"entity\" [key]=\"key\" [getValidationErrorMessage]=\"getValidationErrorMessage\"></file-input>\n</div>\n\n<div *ngIf=\"!metadata.dragAndDrop\">\n <file-input (fileDataChangeEvent)=\"refreshFileData($event)\" [entity]=\"entity\" [key]=\"key\" [getValidationErrorMessage]=\"getValidationErrorMessage\"></file-input>\n</div>", styles: [".file-input{margin-top:15px;margin-bottom:15px;padding:15px;border-radius:5px}\n"], components: [{ type: FileInputComponent, selector: "file-input", inputs: ["entity", "key", "getValidationErrorMessage"], outputs: ["fileDataChangeEvent"] }], directives: [{ type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
2588
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: FileDefaultInputComponent, decorators: [{
2589
+ type: Component,
2590
+ args: [{ selector: 'file-default-input', template: "<div *ngIf=\"metadata.dragAndDrop\" class=\"file-input mat-elevation-z8\">\n <file-input (fileDataChangeEvent)=\"refreshFileData($event)\" [entity]=\"entity\" [key]=\"key\" [getValidationErrorMessage]=\"getValidationErrorMessage\"></file-input>\n</div>\n\n<div *ngIf=\"!metadata.dragAndDrop\">\n <file-input (fileDataChangeEvent)=\"refreshFileData($event)\" [entity]=\"entity\" [key]=\"key\" [getValidationErrorMessage]=\"getValidationErrorMessage\"></file-input>\n</div>", styles: [".file-input{margin-top:15px;margin-bottom:15px;padding:15px;border-radius:5px}\n"] }]
2591
+ }] });
2592
+
2593
+ // eslint-disable-next-line max-len
2594
+ const placeholder = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABLAAAAMgCAMAAAAEPmswAAAANlBMVEXx8/XCy9LFztXu8PPs7/Lp7e/W3OHL0tnZ3+PN1NrS2d7i5urn6u7f5OjI0Nfc4ebP1tzk6excnoRZAAAXh0lEQVR42uzUAQ0AAAzDoN+/6eloAiK4B4gQFpAhLCBDWECGsIAMYQEZwgIyhAVkCAvIEBaQISwgQ1hAhrCADGEBGcICMoQFZAgLyBAWkCEsIENYQIawgAxhARnCAjKEBWQIC8gQFpAhLCBDWECGsIAMYQEZwgIyhAVkCAvIEBaQISwgQ1hAhrCADGEBGcICMoQFZAgLyBAWkCEsIENYQIawgAxhARnCAjKEBWQIC8gQFpAhLGDs1AEJAAAAgKD/r9sR6Ag3hAVsCAvYEBawISxgQ1jAhrCADWEBG8ICNoQFbAgL2BAWsCEsYENYwIawgA1hARvCAjaEBWwIC9gQFrAhLGBDWMCGsIANYQEbwgI2hAVsCAvYEBawISxgQ1jAhrCADWEBG8ICNoQFbAgL2BAWsCEsYENYwIawgA1hARvCAjaEBWwIC9gQFrAhLGBDWMCGsIANYQEbwgI2hAVsCAvYEBbETh2QAAAAAAj6/7odgY6QDWEBG8ICNoQFbAgL2BAWsCEsYENYwIawgA1hARvCAjaEBWwIC9gQFrAhLGBDWMCGsIANYQEbwgI2hAVsCAvYEBawISxgQ1jAhrCADWEBG8ICNoQFbAgL2BAWsCEsYENYwIawgA1hARvCAjaEBWwIC9gQFrAhLGBDWMCGsIANYQEbwgI2hAVsCAvYEBawISxgQ1jAhrCADWEBG8ICNoRF7NQBCQAAAICg/6/bEegIYUNYwIawgA1hARvCAjaEBWwIC9gQFrAhLGBDWMCGsIANYQEbwgI2hAVsCAvYEBawISxgQ1jAhrCADWEBG8ICNoQFbAgL2BAWsCEsYENYwIawgA1hARvCAjaEBWwIC9gQFrAhLGBDWMCGsIANYQEbwgI2hAVsCAvYEBawISxgQ1jAhrCADWEBG8ICNoQFbAgL2BAWsCEsYENYwIawgA1hxc6dJtcKAgEURgREwGn/m32Vd1Op/Ih3cO72fIs4BU0rADEIFgAxCBYAMQgWADEIFgAxCBbwm+3bFOKQ8zSV4r13zvky5a4bYgxjYyuch2ABD7ZJMRdnXnIlDyE1FY5HsADbhmFy5lM+x7GvcCSChXtrQufNCnXpQlvhIAQLt2XHONVmE2VIzLaOQLBwT230ZlsuBy6IeyNYuB+bOmd24TpOWrsiWLiZJhazKz8w09oNwcKd9NGbA9SZg9Y+CBZuw4ZijlMiE63tESzcg02TOZqnWVsjWLiDpqvNKXxkI35LBAv6pWJO5APzrM0QLChnozNnm5jBb4RgQbU2m0uoO3YdtkCwoFjy5jp85Ji1GsGCWpfK1X95rLAKwYJS4XK54pi1HsGCSuH8SfucjkWH5QgWFLpwrr6UVGEZggV10rVz9cVxM1yGYEGZthgJ6oHPdhYgWFClv8jeFcOsfRAsKGIHI8rENumHCBb0iLWRhvn7ZwgWtGgvuXj1kidZHyBY0MF2RiqS9T6CBRWCvNsgyVqAYEGBRsYqA8lajWBBPGlvg38rvBi+gWBBuvb6i+3vmdjLeolgQTYdx6tvme33FwgWRBO6yzBr4BvDpwgWJNN0vHqo+Sz6GYIFuRplx6sHx4PhPIIFsaJRigfDWQQLQvXid6+Yvn+OYEGmUfRq+2uMsv5EsCCSvmk7o6x3ECwIpPo6yCLpEwQL8iTl10G2smYRLIij/zrIvXAOwYIwvcrlq1kT74W/ESzIMmr51Plddazwg2BBlGDux7NH+oNgQRK5/0Fm+L4JgvWPvbvRSRiGAjBaBoqK+PP+L2s0xGSj3QiQ9I57zkN86brblvVItn1l8/2cYLEar1mmGWoOFlm/BIu1yLh9ZZE1IVisRNLtK4usEcFiFYbvwtYiS7BYg7zb7WPfFlmCRXj7bNOiFlkNgkV8j373lZ2siwkW4SX/PTi1+9pkJljEluhyhgsdMy+yBIvQDoWpXeLThYJFYMYZ6vJe4SBYxDWkuAv5Gu9Z78kSLMIajF8ZcBgRLOL6MH5l731MsAhrb/zK3vuEYBFV6ttk7L3XCRZBvRUcLpwSLGLSK3PvFYJFSHrls7BGsIhIr3wWVgkWATnu7G9hnWARj175LGwQLMLRK5+FLYJFNHp1jd1+k4NgEYpeXel5k4JgEYleXe24yUCwCESvXDkzR7CIxPzVTbYJxt4FizD0ynzDPMEiDr3yCtgCwSKMr8Ltnh58I0uwiOG1cA/bxz6oI1iE4L4+E1nLBIsY3IdsIusCgkUI3pu4q/fH3XoXLPob9OqXo4VLBIsAvD944tnCBYJFAN53PjFDukCw6O9Q+GPrfYlg0d2x8M+tfrMEi94+CyOm3tsEi65cKDNl6n2OYNGTA89Vpt5bBIuOHCCs8rOwSbDoaW9gtMbPwhbBohsD7k1+FjYIFv0MBkbb/CysESx6MTA6z8nCCsGiEwNYS7xOcU6w6OWlsMB4ww9794LdJgyEUXgwAsfFL/a/2Z4+T2zjWCMgnl/cbwttbxppNNwjWHgLBrByMN5wj2Ct4HztL+OxS621qTuOp/5a06HnItgw+v0uTRUI1qL2/dDao3b8qO+RRDkGGt5haGpAsJZzPbX2XDvUc/I5ExuwsrE4+QbBWsz+I9kr6VLR/XI5Nsq8SVdBsQjWIg6D5Rn5bxYbGpwYyPqPYC3iMFq+4+aTxSeevdg38xfBWsB5MJ+j/s+5Oc5cEDoxQvoPwZrvozW3SwWHCWX4RM67iX9Oh2DNc+isRFL/QVduNBRg6P0XgjVTv/nJYx9eEAYgXSyCNcNu2PpUjBMXhCEo/7AkWKVm78tM8jc2XqxEDkL4mQ7BKnZot35j48QFYRi6z3QIVqlru/kbGx8uCAORLRbBKvSD808nVoxGorrpnWCVuTIV48TKvlhEL30IVoEl1zlt5xyLlX2xaBaLYJU4J153+bCyLx7J5Q0Ey23hw+Ok+NfGiwP3iBSLRbAKDLaksdkCDtwDSnrLuwmWX29mDB57MOEelF6xCJbTGocx9R9jMeEelNxKP4Ll1tlvHGPl4psTgbVixSJYXr39wS+FuVgpE5lYsQiW0661FcgdJTiwUiY2rd8KCZbTyf7ipjAPO9yjk/o/FsHy2dstBt5fYEVDfErFIlg+g63j2FSLidHwhJ5bECyXs33GaMNLfDRVgk6xCJbLyT7jFOsVJkZFyBSLYHnsbD1C5wgOe4MElWIRLI/e7rFn+ws8eRYiUiyC5dHZelJTIZ4869C4KyRYDnu7x2TDF9gxqkWiWATL4WJrOjW14cmzFoViESyHZGtqm8rw5FmNwCsdgpXvbI8YxXqGJ8+C4heLYOXr7RE7G57gAEtS+I1+BCvfyaYwOzqFAyxR0YtFsPIle8Qh1iQOsGQFLxbByrazCQy7T2ICS1fsb+kQrGwHe4rPQN/iCaGy0MUiWNl6m8Kp+yN2YGmL/E1ogpXtYtMYHb3HDixxgYtFsLIN9gRb/G6xxF1e3AtrgpXtaM/w/vkzlrhXYGiCIljZOntAsKbsOMDSF7VYBCtbsrVV8ofBk5waBD1QreTfyPoIVh6e5NQi5kbJOv6NfAtbX9zLmVw8yanHT/buBDt1GIbCsJwRCOP+N/t62vNaphLbSZEs/98O2gOXyJFkk102BFYkAisGIzmeDMEeAitaK09REl5hJMcVg6MXHr4jb8EZVgRGcpyxl1gOviPv0stzrGv4MdLR4Iu5pZIEViQaR+cxkuOOucu/CKxIjObMYiTHIWsXUxBY0TbynPtevUiM5LhkbKEfgRWJ9TIz6GhwytZ6LAIrEgv8ZtDR4JWpZTMEViRWJM/ZCXyytGyGwIrFJRSvsGTUM0OHqwRWLK75eoUdDa7ZGYQmsOLt5CnO3EOgxd05M59NAisWV9W/MgpcszIITWAl6OUeR1ifaHH37xxMILASnOSBz5NNY/8ZGGBkSIfASjDKDZ8/YelY2lcFG0M6BFaKXh4w+UyLeyU6Cw2kBFaKQW75fHOc7CCogYUhHQIrRSN3aHMPtLjXw0CnIIGV5CT3vN8DN4eCsCb6L4YIrCRHuUYTVgi0uFdFvYGUwEpzkP/cPWxnocW9MkPQRGClGuUKPQ1sca/OOSgisJId5BsnWB/2gqqoNpASWMmaVv6ArTW00biXvkLtMaghsNIN8snXUWYeZp6rpNiORWBl2Mva+lAqZp5rtA9aCKxk36s1aWlg5rlWU1BCYOXYyQcKQmae63UKOgisLAcRoQWLgrBiQ1BBYGVpem8z8BkoCKt2DhoIrDzHztmWoXQUhHXT+dwSWJnGtvoDd2ae66ZSGRBYubbVX/ZMQVg5jXYsAivbueyzSyN/Pwo2hbcjsPJt25qfrygIodDcQGAtMHZlj5EuwFZkqBQIBNYSx16W6Ip9P0hBCJ3mBgJrkeYg+S7F9l9REEKpuYHAWmiobx4nBApCKDU3EFhLjb3k6As+vuKaHGhtbiCwlhvayh6vKAihdZEOgbWCZpI0l2L3i36ZBFD59SWwVjFOKXFVdDUYKAih101IYK0iIbKm0uMqNFyTA615WAJrNcdNL3O6TcGtV18oCKH4qpDAWtP21MnvukOxdw/+oCCE5qtCAmtlx2Hq5FE7DQ6erUKgIITqHDSB9Qea7XCaLvu+a7u+30+nYVtwT/stCkKovioksJCAgvAfe3eU6ygMBFG0GhtCSAxh/5udUWby8Z4COGCgI92ziJLLuBuc+6mQwEI+nozi9KlCAgu5KIQ4/VMhgYVMFEKc/6mQwEIeCiEcTBUSWMhDIYSDBaQEFrJQCOFhASmBhRwUQiwLve2LwEIetozCxb8KCSxk4LcT8DGjQ2BhGYUQTmZ0CCwsoxDCyYwOgYVFFEJ4mdEhsLCEQgg3MzoEFpZQCPGJ0XZDYGERhRCfGWwvBBaWUAjh6OKdwMI8CiE+drF9EFhYQCGEp4t3AgtzKIRwdfFOYGEOhRCuLt4JLMy6CvBz8U5gYU5VC/Dz4p3AwpxBgKNVMwQWJlEI4W3VDIGFGRRC+Fo1Q2BhCoUQ7na8E1iYdBHga8c7gYUJFEL4u3gnsDClFeDs4p3AwjsUQrj8uarsCP21a4Z0G+sYQwiSQoixvo9paJvHpTI4RCFEAVcrSrar/tEMY9SCeL+1zaM3OEIhhMPFDbK9VF07Bn2kTs2V45YPFEJ4XNwg20PfpKgJOallONtdgL/FDbLSqi7V2qpOHUetU1AI8eR0cYOsqKq7BRVybzlpHY5CiH+cvh+VlVN1o8oKt4ar+CNRCPHi8/2orJRrCtpDTA/DISiE2EeyUmRFVG3UfgKZdQAKIX7y+H5UVkA/BP1GZn0vCiGeHP74S7bZJek9Mus7NQL+8vh+VLZRlXSckC6GnfUCnhyOQcu2aYOOVTc80CqOQoj33O0flW3RRR0vJN5nlUUhxAR3Y9Cy9aqb8nHM+g59EPDi7hpLtloXdCKOWYVQCDHP1Ri0LJOf49VL3Rm2ohBiga9rLFkeX8er/yLNcBsKIXI4+o2ObAU//38KA7OGJY0CfvM0Bi1bofd00cHTrLUohDja3TaSfe4R5crIC/gVKIR/2Lvb5NRhGArD54RvCC3sf7N3Op07UyhJ7PQHsvU+W4BxIvlIQbkw2/zkMrFH+em/V6MgRKlIbSy50hDzX82RVYeCEMUitbHkOh9hP/60ozAsRkGIGoHaWHKVQ7D21YORI6sCkVGUC9PGkqcFTV9xZP0RBSGqRWljyb+1/J/myKrAllG8w2bwavKEwGnReXdyWXMoCPF2o1eTi719eLDUlYGdOa1kVdCvo9eSH/RwXkmbI0fWSxSEiOHmleRnTcWvpmz3RoWwYRX0afVuLLnI0FyLg1jWMwpCxHH3OnKJocUn8Ej3/QcKQoRy9Cryt/7OK7rvDygIEcvJa8hf+jyvaGX91HpcBZ1Z18aS7W7PK0kjq9+XnAS8wcUryO75vKIutE1BiJD2rifb7ut+8NmGupCCEBEdXE3dn1eSdtSFFISIZze4lvxf10soqQsnDJH3BaF3V9dSivNK2rKR9KWrgPc5u5LcyfzgogsfBPvtJuB96hcmK08/luY7BSGi2bmOMk2YMazT8Rs02vTpKvKks/pzNPr+hdGam2soWXuDhAOfyUEodSM68oRTr//mTxIOvV0Bo2l3V5BfO/R6XvGS1dAnRZDC3uWU8fro02AJFsI4uJhSfkNlx3UhM88Io2JER0nzz+mvC/vK2KFtV5dSigAWL1nMPCOyswspbzwn80tW3z1KNKd4REeJH75j3ulCIu6IZXQZ+dlHnofvJusKhyTv0GjI0UXU20bkOpeUKVIi7ojn5BJKXixsM6ZIOw+toEllIzpKeEGYPUWa7zdGC64uIJob2XrvaS5V0JizlynLBCGb/Ug0ILbN4EXK23BP2ntP1qREQ+5eJPaNfNmmyb2zowFx7b1ENGO/JSkLcxb9aMXBC5S74Z6uLMxa9KMNOy8Qz95MkSx2NCC2q+cpfcM90zh0n3v60ZObZ4nLox/ufZeFQ/aXaMS3EHgXl0d5ysK8t8Box8VzRPo5zW1h6ltgNGPvGSL9nOW2kAYWmjC7zE80sJIsT+ahhEaMniZqhSR7/f6xdy+4iQNBEEDdQYEA4Xf/y+5ukk2AYAkFKXKX3ztEWe6p6THAoouXGjUYYM1j5YyPEn2saszgX2EWK2cMsGhk/KHCwb/CTYtjJfFRopVDjRj8K8yh9m4pMr0c67bBAGsG/QZXCGlmrPA++FcY9ZwyyJr5Hg462tZNA/GDLK960dCmvhNYMxhk2cNBR7cK7wJrBoOs3QANneobgZU/yLKHg6aWdU1gxQ+ynALT1qquCKz0jTMao/T1WlcE1l121ZbGKI291CWBdZ/XrqN3A3daW9UFgZX90KqBO7091wWBFb0jy8Cd7g51TmAld0g13OlvXWcEVnCHVMOdABe3oAVW8Ojdon4S7OqLwModvdtzRoZjfRJYsaN3K2UIcfZTKLBSR+8OCImxrf8EVmjr3QEhQTb1QWBljt4dEJJk8VTvBFbm6N1DSETZ1juBFblwxpsThNnUG4GVuHBGoYE0Hz+FAivwsNCNZ/Js6x+B9VPbmiqP0pNoWX8JrLjDwpVCA4nefgoFVtph4d5KZDKdqkpgPWCxrslRwCLWskpgPWRyNwufrHAn1mJfAivqsFBekexUAivqZqGCO9GWAutRpwkdFtrYR7bFXmDlPGXvSS/SnQRWTL1BXpHPNY6Uu9AuPDMDatEhd6HlFdCl3iCvgC71BnkFdLkLbd4OdKk3yCugS71BXgFd6g367UCTeoP7zsAPHeoe9l8BU7CrX7WyXxRoUm9Yu6gA/GHvDnMThmEwgNZpF9LQUrj/ZfdvmmBMDEabSu8dIkrsz85O4g3VeQW8ZhjjPv+lAk3pa9whzgA0J8ePxBmABs3xZqP2ILCTVe/2LgI7aRYm04NA1+1iFvog3Q503S6ahZ6DwJe2FycnaQbgLY4p/lnVHQS+abj07noFXGl2TsfsIHCrydS76xVwq8lCViquV8D7fRwU24HdyPGa0aQzsJrpFM8bFa+ANfUlnnS+dADrGmo8oZobBLYwLKf4k1NRagc2M9UUD0rZWxDYVj8/cmalOotdAS2Yyhi/OBcpBqAh/WXJY4or6ZwXhxXQpGE6znMpOZdlmY+TVyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPDJHhwIAAAAAAD5vzaCqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqwBwcCAAAAAED+r42gqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqirswYEAAAAAAJD/ayOoqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqkp7cCAAAAAAIMjfepArAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgKcAnTNeiLeG1rEAAAAASUVORK5CYII=';
2595
+
2596
+ /* eslint-disable jsdoc/require-jsdoc */
2597
+ class FileImageInputComponent extends NgxMatEntityBaseInputComponent {
2598
+ constructor() {
2599
+ super(...arguments);
2600
+ this.FileUtilities = FileUtilities;
2601
+ this.imageIndex = 0;
2602
+ this.placeHolder = placeholder;
2603
+ }
2604
+ async setSinglePreviewImage() {
2605
+ let singleFileData = this.entity[this.key];
2606
+ if (singleFileData) {
2607
+ singleFileData = await FileUtilities.getFileData(singleFileData);
2608
+ this.singlePreviewImage = await FileUtilities.getDataURLFromFile(singleFileData.file);
2609
+ }
2610
+ else {
2611
+ this.singlePreviewImage = undefined;
2612
+ }
2613
+ }
2614
+ async setMultiPreviewImages(index) {
2615
+ const multiFileData = this.entity[this.key];
2616
+ const previewImages = [];
2617
+ if (multiFileData?.length) {
2618
+ for (let i = 0; i < multiFileData.length; i++) {
2619
+ if (i === index) {
2620
+ multiFileData[index] = await FileUtilities.getFileData(multiFileData[index]);
2621
+ previewImages.push(await FileUtilities.getDataURLFromFile(multiFileData[index].file));
2622
+ }
2623
+ else {
2624
+ previewImages.push('empty');
2625
+ }
2626
+ }
2627
+ }
2628
+ this.multiPreviewImages = previewImages;
2629
+ }
2630
+ async refreshFileData(fileData) {
2631
+ this.entity[this.key] = fileData;
2632
+ this.emitChange();
2633
+ if (this.metadata.multiple) {
2634
+ if (!(fileData?.[this.imageIndex])) {
2635
+ this.imageIndex = 0;
2636
+ }
2637
+ await this.setMultiPreviewImages(this.imageIndex);
2638
+ }
2639
+ else {
2640
+ await this.setSinglePreviewImage();
2641
+ }
2642
+ }
2643
+ async prev() {
2644
+ if (this.imageIndex > 0) {
2645
+ await this.setMultiPreviewImages(this.imageIndex - 1);
2646
+ this.imageIndex--;
2647
+ }
2648
+ }
2649
+ async next() {
2650
+ if (this.multiPreviewImages?.length && this.imageIndex !== (this.multiPreviewImages.length - 1)) {
2651
+ await this.setMultiPreviewImages(this.imageIndex + 1);
2652
+ this.imageIndex++;
2653
+ }
2654
+ }
2655
+ async setIndex(index) {
2656
+ await this.setMultiPreviewImages(index);
2657
+ this.imageIndex = index;
2658
+ }
2659
+ }
2660
+ FileImageInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: FileImageInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
2661
+ FileImageInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: FileImageInputComponent, selector: "file-image-input", usesInheritance: true, ngImport: i0, template: "<div *ngIf=\"!metadata.dragAndDrop && !metadata.preview\">\n <file-input (fileDataChangeEvent)=\"refreshFileData($event)\" [entity]=\"entity\" [key]=\"key\" [getValidationErrorMessage]=\"getValidationErrorMessage\"></file-input>\n</div>\n\n<div *ngIf=\"metadata.dragAndDrop || metadata.preview\" class=\"file-input mat-elevation-z8\">\n <file-input (fileDataChangeEvent)=\"refreshFileData($event)\" [entity]=\"entity\" [key]=\"key\" [getValidationErrorMessage]=\"getValidationErrorMessage\"></file-input>\n\n <div class=\"image-preview\" *ngIf=\"metadata.preview && metadata.multiple\">\n <i (click)=\"prev()\" [class.disabled]=\"imageIndex === 0\" class=\"prev-button fa-solid fa-angle-left\"></i>\n <img *ngIf=\"multiPreviewImages?.[imageIndex]\" class=\"mat-elevation-z2\" [src]=\"multiPreviewImages?.[imageIndex]\">\n <img *ngIf=\"!multiPreviewImages?.[imageIndex]\" class=\"mat-elevation-z2\" [src]=\"metadata.previewPlaceholderUrl ?? placeHolder\">\n <i (click)=\"next()\" [class.disabled]=\"!multiPreviewImages || !multiPreviewImages.length || imageIndex === (multiPreviewImages.length - 1)\" class=\"next-button fa-solid fa-angle-right\"></i>\n </div>\n <div class=\"preview-nav\" *ngIf=\"metadata.preview && metadata.multiple\">\n <button (click)=\"setIndex(imageIndex-4)\" mat-icon-button *ngIf=\"\n this.multiPreviewImages\n && multiPreviewImages[imageIndex-4]\n && imageIndex === (this.multiPreviewImages.length - 1)\"\n >\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex - 3}}</span>\n </button>\n <!-- eslint-disable-next-line @angular-eslint/template/conditional-complexity -->\n <button (click)=\"setIndex(imageIndex-3)\" mat-icon-button *ngIf=\"this.multiPreviewImages\n && multiPreviewImages[imageIndex-3]\n && (\n imageIndex === (this.multiPreviewImages.length - 2)\n || imageIndex === (this.multiPreviewImages.length - 1)\n )\"\n >\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex - 2}}</span>\n </button>\n <button (click)=\"setIndex(imageIndex-2)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex-2]\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex - 1}}</span>\n </button>\n <button (click)=\"setIndex(imageIndex-1)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex-1]\">\n <i class=\"dot\"></i>\n <span class=\"image-index\">{{imageIndex}}</span>\n </button>\n <button mat-icon-button disabled>\n <i class=\"dot selected\"></i>\n <span class=\"image-index\">{{imageIndex + 1}}</span>\n </button>\n <button (click)=\"setIndex(imageIndex+1)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+1]\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 2}}</span>\n </button>\n <button (click)=\"setIndex(imageIndex+2)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+2]\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 3}}</span>\n </button>\n <button (click)=\"setIndex(imageIndex+3)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+3] && imageIndex <= 1\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 4}}</span>\n </button>\n <button (click)=\"setIndex(imageIndex+4)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+4] && imageIndex === 0\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 5}}</span>\n </button>\n </div>\n\n <div class=\"image-preview\" *ngIf=\"metadata.preview && !metadata.multiple\">\n <i class=\"prev-button disabled fa-solid fa-angle-left\"></i>\n <img class=\"mat-elevation-z2\" [src]=\"singlePreviewImage ?? metadata.previewPlaceholderUrl ?? placeHolder\">\n <i class=\"next-button disabled fa-solid fa-angle-right\"></i>\n </div>\n <div class=\"preview-nav\" *ngIf=\"metadata.preview && !metadata.multiple\">\n <button disabled mat-icon-button>\n <span class=\"dot selected\"></span>\n <span class=\"image-index\">1</span>\n </button>\n </div>\n</div>", styles: [".file-input{margin-top:15px;margin-bottom:15px;padding:15px;border-radius:5px}.image-preview{height:250px;display:flex;align-items:center;padding-top:15px;padding-bottom:15px}.image-preview .prev-button{font-size:100px;margin-left:5px}.image-preview .next-button{font-size:100px;margin-right:5px}.image-preview .prev-button:hover,.image-preview .next-button:hover{cursor:pointer}.image-preview .prev-button.disabled,.image-preview .next-button.disabled{color:#00000061}.image-preview .prev-button.disabled:hover,.image-preview .next-button.disabled:hover{cursor:default}.image-preview img{max-width:calc(100% - 100px);max-height:100%;margin-left:auto;margin-right:auto;border-radius:3px}.preview-nav{text-align:center}.preview-nav button{display:inline-block;width:18px;height:18px;margin-left:5px;margin-right:5px}.preview-nav button .dot{height:100%;width:100%;background-color:#00000061;border-radius:50%;display:block}.preview-nav button .dot.selected{background-color:#000000de}.preview-nav button .image-index{position:absolute;height:100%;width:100%;display:block;top:-11.5px;color:#fff}.preview-nav button:hover{background-color:#000}\n"], components: [{ type: FileInputComponent, selector: "file-input", inputs: ["entity", "key", "getValidationErrorMessage"], outputs: ["fileDataChangeEvent"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
2662
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: FileImageInputComponent, decorators: [{
2663
+ type: Component,
2664
+ args: [{ selector: 'file-image-input', template: "<div *ngIf=\"!metadata.dragAndDrop && !metadata.preview\">\n <file-input (fileDataChangeEvent)=\"refreshFileData($event)\" [entity]=\"entity\" [key]=\"key\" [getValidationErrorMessage]=\"getValidationErrorMessage\"></file-input>\n</div>\n\n<div *ngIf=\"metadata.dragAndDrop || metadata.preview\" class=\"file-input mat-elevation-z8\">\n <file-input (fileDataChangeEvent)=\"refreshFileData($event)\" [entity]=\"entity\" [key]=\"key\" [getValidationErrorMessage]=\"getValidationErrorMessage\"></file-input>\n\n <div class=\"image-preview\" *ngIf=\"metadata.preview && metadata.multiple\">\n <i (click)=\"prev()\" [class.disabled]=\"imageIndex === 0\" class=\"prev-button fa-solid fa-angle-left\"></i>\n <img *ngIf=\"multiPreviewImages?.[imageIndex]\" class=\"mat-elevation-z2\" [src]=\"multiPreviewImages?.[imageIndex]\">\n <img *ngIf=\"!multiPreviewImages?.[imageIndex]\" class=\"mat-elevation-z2\" [src]=\"metadata.previewPlaceholderUrl ?? placeHolder\">\n <i (click)=\"next()\" [class.disabled]=\"!multiPreviewImages || !multiPreviewImages.length || imageIndex === (multiPreviewImages.length - 1)\" class=\"next-button fa-solid fa-angle-right\"></i>\n </div>\n <div class=\"preview-nav\" *ngIf=\"metadata.preview && metadata.multiple\">\n <button (click)=\"setIndex(imageIndex-4)\" mat-icon-button *ngIf=\"\n this.multiPreviewImages\n && multiPreviewImages[imageIndex-4]\n && imageIndex === (this.multiPreviewImages.length - 1)\"\n >\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex - 3}}</span>\n </button>\n <!-- eslint-disable-next-line @angular-eslint/template/conditional-complexity -->\n <button (click)=\"setIndex(imageIndex-3)\" mat-icon-button *ngIf=\"this.multiPreviewImages\n && multiPreviewImages[imageIndex-3]\n && (\n imageIndex === (this.multiPreviewImages.length - 2)\n || imageIndex === (this.multiPreviewImages.length - 1)\n )\"\n >\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex - 2}}</span>\n </button>\n <button (click)=\"setIndex(imageIndex-2)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex-2]\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex - 1}}</span>\n </button>\n <button (click)=\"setIndex(imageIndex-1)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex-1]\">\n <i class=\"dot\"></i>\n <span class=\"image-index\">{{imageIndex}}</span>\n </button>\n <button mat-icon-button disabled>\n <i class=\"dot selected\"></i>\n <span class=\"image-index\">{{imageIndex + 1}}</span>\n </button>\n <button (click)=\"setIndex(imageIndex+1)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+1]\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 2}}</span>\n </button>\n <button (click)=\"setIndex(imageIndex+2)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+2]\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 3}}</span>\n </button>\n <button (click)=\"setIndex(imageIndex+3)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+3] && imageIndex <= 1\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 4}}</span>\n </button>\n <button (click)=\"setIndex(imageIndex+4)\" mat-icon-button *ngIf=\"multiPreviewImages?.[imageIndex+4] && imageIndex === 0\">\n <span class=\"dot\"></span>\n <span class=\"image-index\">{{imageIndex + 5}}</span>\n </button>\n </div>\n\n <div class=\"image-preview\" *ngIf=\"metadata.preview && !metadata.multiple\">\n <i class=\"prev-button disabled fa-solid fa-angle-left\"></i>\n <img class=\"mat-elevation-z2\" [src]=\"singlePreviewImage ?? metadata.previewPlaceholderUrl ?? placeHolder\">\n <i class=\"next-button disabled fa-solid fa-angle-right\"></i>\n </div>\n <div class=\"preview-nav\" *ngIf=\"metadata.preview && !metadata.multiple\">\n <button disabled mat-icon-button>\n <span class=\"dot selected\"></span>\n <span class=\"image-index\">1</span>\n </button>\n </div>\n</div>", styles: [".file-input{margin-top:15px;margin-bottom:15px;padding:15px;border-radius:5px}.image-preview{height:250px;display:flex;align-items:center;padding-top:15px;padding-bottom:15px}.image-preview .prev-button{font-size:100px;margin-left:5px}.image-preview .next-button{font-size:100px;margin-right:5px}.image-preview .prev-button:hover,.image-preview .next-button:hover{cursor:pointer}.image-preview .prev-button.disabled,.image-preview .next-button.disabled{color:#00000061}.image-preview .prev-button.disabled:hover,.image-preview .next-button.disabled:hover{cursor:default}.image-preview img{max-width:calc(100% - 100px);max-height:100%;margin-left:auto;margin-right:auto;border-radius:3px}.preview-nav{text-align:center}.preview-nav button{display:inline-block;width:18px;height:18px;margin-left:5px;margin-right:5px}.preview-nav button .dot{height:100%;width:100%;background-color:#00000061;border-radius:50%;display:block}.preview-nav button .dot.selected{background-color:#000000de}.preview-nav button .image-index{position:absolute;height:100%;width:100%;display:block;top:-11.5px;color:#fff}.preview-nav button:hover{background-color:#000}\n"] }]
2665
+ }] });
2666
+
2667
+ /* eslint-disable jsdoc/require-jsdoc */
2668
+ class CustomInputComponent extends NgxMatEntityBaseInputComponent {
2669
+ constructor(viewContainerRef) {
2670
+ super();
2671
+ this.viewContainerRef = viewContainerRef;
2672
+ }
2673
+ ngOnInit() {
2674
+ super.ngOnInit();
2675
+ this.component = this.viewContainerRef.createComponent(this.metadata.component);
2676
+ this.component.instance.entity = this.entity;
2677
+ this.component.instance.key = this.key;
2678
+ this.component.instance.getValidationErrorMessage = this.getValidationErrorMessage;
2679
+ this.component.instance.inputChangeEvent.subscribe(this.inputChangeEvent);
2680
+ }
2681
+ }
2682
+ CustomInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: CustomInputComponent, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component });
2683
+ CustomInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: CustomInputComponent, selector: "custom-input", usesInheritance: true, ngImport: i0, template: "", styles: [""] });
2684
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: CustomInputComponent, decorators: [{
2685
+ type: Component,
2686
+ args: [{ selector: 'custom-input', template: "", styles: [""] }]
2687
+ }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }]; } });
2688
+
2689
+ /**
2690
+ * The default input component. It gets the metadata of the property from the given @Input "entity" and @Input "propertyKey"
2691
+ * and displays the input field accordingly.
2692
+ *
2693
+ * You can also define a method that generates error-messages and if the input should be hidden when its metadata says
2694
+ * that it should be omitted for creating or updating.
2695
+ * The last part being mostly relevant if you want to use this component inside an ngFor.
2696
+ */
2697
+ class NgxMatEntityInputComponent {
2698
+ constructor(dialog) {
2699
+ this.dialog = dialog;
2700
+ this.inputChangeEvent = new EventEmitter();
2701
+ this.selection = new SelectionModel(true, []);
2702
+ this.isArrayItemValid = false;
2703
+ this.isDialogArrayItemValid = false;
2704
+ this.DecoratorTypes = DecoratorTypes;
2705
+ this.EntityUtilities = EntityUtilities;
2706
+ this.DateUtilities = DateUtilities;
2707
+ }
2708
+ /**
2709
+ * This is needed for the inputs to work inside an ngFor.
2710
+ *
2711
+ * @param index - The index of the element in the ngFor.
2712
+ * @returns The index.
2713
+ */
2714
+ trackByFn(index) {
2715
+ return index;
2716
+ }
2717
+ ngOnInit() {
2718
+ if (!this.entity) {
2719
+ throw new Error('Missing required Input data "entity"');
2720
+ }
2721
+ this.internalEntity = this.entity;
2722
+ if (this.propertyKey == null) {
2723
+ throw new Error('Missing required Input data "propertyKey"');
2724
+ }
2725
+ this.internalPropertyKey = this.propertyKey;
2726
+ this.internalGetValidationErrorMessage = this.getValidationErrorMessage ?? getValidationErrorMessage;
2727
+ this.type = EntityUtilities.getPropertyType(this.entity, this.propertyKey);
2728
+ this.metadata = EntityUtilities.getPropertyMetadata(this.entity, this.propertyKey, this.type);
2729
+ if (this.type === DecoratorTypes.OBJECT) {
2730
+ this.initObjectInput();
2731
+ }
2732
+ if (this.type === DecoratorTypes.ARRAY) {
2733
+ this.initEntityArray();
2734
+ }
2735
+ }
2736
+ initEntityArray() {
2737
+ this.metadataEntityArray = this.metadata;
2738
+ if (this.internalEntity[this.internalPropertyKey] == null) {
2739
+ this.internalEntity[this.internalPropertyKey] = [];
964
2740
  }
965
- this.metadataStringChipsArray = this.metadata;
966
- if ((this.type === DecoratorTypes.ARRAY_STRING_CHIPS || this.type === DecoratorTypes.ARRAY_STRING_AUTOCOMPLETE_CHIPS)
967
- && this.entity[this.propertyKey]?.length) {
968
- this.stringChipsArrayValues = this.entity[this.propertyKey];
2741
+ this.entityArrayValues = this.internalEntity[this.internalPropertyKey];
2742
+ if (!this.metadataEntityArray.createInline && !this.metadataEntityArray.createDialogData) {
2743
+ this.metadataEntityArray.createDialogData = {
2744
+ title: 'Add'
2745
+ };
969
2746
  }
970
- this.metadataAutocompleteStringChipsArray = this.metadata;
971
- if (!this.getValidationErrorMessage) {
972
- this.getValidationErrorMessage = getValidationErrorMessage;
2747
+ const givenDisplayColumns = this.metadataEntityArray.displayColumns.map((v) => v.displayName);
2748
+ if (givenDisplayColumns.find(s => s === 'select')) {
2749
+ throw new Error(`The name "select" for a display column is reserved.
2750
+ Please choose a different name.`);
973
2751
  }
2752
+ this.displayedColumns = ['select'].concat(givenDisplayColumns);
2753
+ this.dataSource = new MatTableDataSource();
2754
+ this.dataSource.data = this.entityArrayValues;
2755
+ this.arrayItem = new this.metadataEntityArray.EntityClass();
2756
+ this.arrayItemInlineRows = EntityUtilities.getEntityRows(this.arrayItem, this.hideOmitForCreate ?? true, this.hideOmitForEdit);
2757
+ this.arrayItemPriorChanges = LodashUtilities.cloneDeep(this.arrayItem);
2758
+ this.dialogInputData = {
2759
+ entity: this.arrayItem,
2760
+ createDialogData: this.metadataEntityArray.createDialogData,
2761
+ getValidationErrorMessage: this.getValidationErrorMessage
2762
+ };
2763
+ this.dialogData = new AddArrayItemDialogDataBuilder(this.dialogInputData).getResult();
2764
+ this.arrayItemDialogRows = EntityUtilities.getEntityRows(this.dialogData.entity, true);
2765
+ }
2766
+ initObjectInput() {
2767
+ this.metadataDefaultObject = this.metadata;
2768
+ this.objectProperty = this.internalEntity[this.internalPropertyKey];
2769
+ this.objectPropertyRows = EntityUtilities.getEntityRows(this.objectProperty, this.hideOmitForCreate, this.hideOmitForEdit);
974
2770
  }
975
2771
  /**
976
- * Tries to add an item to the array.
2772
+ * Checks if the arrayItem is valid.
2773
+ */
2774
+ checkIsArrayItemValid() {
2775
+ this.isArrayItemValid = EntityUtilities.isEntityValid(this.arrayItem, 'create');
2776
+ }
2777
+ /**
2778
+ * Checks if the arrayItem inside the dialog is valid.
2779
+ */
2780
+ checkIsDialogArrayItemValid() {
2781
+ this.isDialogArrayItemValid = EntityUtilities.isEntityValid(this.dialogData.entity, 'create');
2782
+ }
2783
+ /**
2784
+ * Emits that a the value has been changed.
2785
+ */
2786
+ emitChange() {
2787
+ this.inputChangeEvent.emit();
2788
+ }
2789
+ /**
2790
+ * Tries to add an item to the entity array.
977
2791
  * Does this either inline if the "createInline"-metadata is set to true
978
2792
  * or in a separate dialog if it is set to false.
979
2793
  */
980
- add() {
2794
+ async addEntity() {
981
2795
  if (this.metadataEntityArray.createInline) {
982
- this.entityArrayValues.push(cloneDeep(this.arrayItem));
2796
+ if (!this.metadataEntityArray.allowDuplicates) {
2797
+ for (const v of this.entityArrayValues) {
2798
+ if ((await EntityUtilities.isEqual(this.arrayItem, v, this.metadata, this.metadataEntityArray.itemType))) {
2799
+ this.dialog.open(NgxMatEntityConfirmDialogComponent, {
2800
+ data: this.metadataEntityArray.duplicatesErrorDialog,
2801
+ autoFocus: false,
2802
+ restoreFocus: false
2803
+ });
2804
+ return;
2805
+ }
2806
+ }
2807
+ }
2808
+ this.entityArrayValues.push(LodashUtilities.cloneDeep(this.arrayItem));
983
2809
  this.dataSource.data = this.entityArrayValues;
984
2810
  EntityUtilities.resetChangesOnEntity(this.arrayItem, this.arrayItemPriorChanges);
2811
+ this.checkIsArrayItemValid();
2812
+ this.emitChange();
985
2813
  }
986
2814
  else {
987
2815
  this.addArrayItemDialogRef = this.dialog.open(this.addArrayItemDialog, {
@@ -996,9 +2824,11 @@ class NgxMatEntityInputComponent {
996
2824
  */
997
2825
  addArrayItem() {
998
2826
  this.addArrayItemDialogRef.close();
999
- this.entityArrayValues.push(cloneDeep(this.arrayItem));
2827
+ this.entityArrayValues.push(LodashUtilities.cloneDeep(this.arrayItem));
1000
2828
  this.dataSource.data = this.entityArrayValues;
1001
2829
  EntityUtilities.resetChangesOnEntity(this.arrayItem, this.arrayItemPriorChanges);
2830
+ this.checkIsArrayItemValid();
2831
+ this.emitChange();
1002
2832
  }
1003
2833
  /**
1004
2834
  * Cancels adding the array item defined in the dialog.
@@ -1006,130 +2836,59 @@ class NgxMatEntityInputComponent {
1006
2836
  cancelAddArrayItem() {
1007
2837
  this.addArrayItemDialogRef.close();
1008
2838
  EntityUtilities.resetChangesOnEntity(this.arrayItem, this.arrayItemPriorChanges);
2839
+ this.emitChange();
1009
2840
  }
1010
2841
  /**
1011
- * Removes all selected entries from the array.
2842
+ * Removes all selected entries from the entity array.
2843
+ *
2844
+ * @param selection - The selection containing the items to remove.
2845
+ * @param values - The values of the dataSource.
2846
+ * @param dataSource - The dataSource.
1012
2847
  */
1013
- remove() {
1014
- this.selection.selected.forEach(s => {
1015
- this.entityArrayValues.splice(this.entityArrayValues.indexOf(s), 1);
2848
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2849
+ remove(selection, values, dataSource) {
2850
+ selection.selected.forEach(s => {
2851
+ values.splice(values.indexOf(s), 1);
1016
2852
  });
1017
- this.dataSource.data = this.entityArrayValues;
1018
- this.selection.clear();
2853
+ dataSource.data = values;
2854
+ selection.clear();
2855
+ this.emitChange();
1019
2856
  }
1020
2857
  /**
1021
2858
  * Toggles all array-items in the table.
2859
+ *
2860
+ * @param selection - The selection to toggle.
2861
+ * @param dataSource - The dataSource of the selection.
1022
2862
  */
1023
- masterToggle() {
1024
- if (this.isAllSelected()) {
1025
- this.selection.clear();
2863
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2864
+ masterToggle(selection, dataSource) {
2865
+ if (this.isAllSelected(selection, dataSource)) {
2866
+ selection.clear();
1026
2867
  }
1027
2868
  else {
1028
- this.dataSource.data.forEach((row) => this.selection.select(row));
2869
+ dataSource.data.forEach(row => selection.select(row));
1029
2870
  }
1030
2871
  }
1031
2872
  /**
1032
2873
  * Checks if all array-items in the table have been selected.
1033
2874
  * This is needed to display the "masterToggle"-checkbox correctly.
1034
2875
  *
2876
+ * @param selection - The selection to check.
2877
+ * @param dataSource - The dataSource of the selection.
1035
2878
  * @returns Whether or not all array-items in the table have been selected.
1036
2879
  */
1037
- isAllSelected() {
1038
- const numSelected = this.selection.selected.length;
1039
- const numRows = this.dataSource.data.length;
2880
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2881
+ isAllSelected(selection, dataSource) {
2882
+ const numSelected = selection.selected.length;
2883
+ const numRows = dataSource.data.length;
1040
2884
  return numSelected === numRows;
1041
2885
  }
1042
- /**
1043
- * Handles adding strings to the chipsArray.
1044
- * Checks validation and also creates a new array if it is undefined.
1045
- * This is needed because two things are validated: The array itself
1046
- * and the contents of the array. And we need a way to display an
1047
- * mat-error. As the only validation for the array is whether or not
1048
- * it contains values, we can set it to undefined when the last element is removed
1049
- * (removeStringChipArrayValue). That way we can use the "required" validator.
1050
- *
1051
- * @param event - The event that fires when a new chip is completed.
1052
- */
1053
- addStringChipArrayValue(event) {
1054
- const value = (event.value || '').trim();
1055
- if (value) {
1056
- if (this.metadataStringChipsArray.minLength && value.length < this.metadataStringChipsArray.minLength) {
1057
- return;
1058
- }
1059
- if (this.metadataStringChipsArray.maxLength && value.length > this.metadataStringChipsArray.maxLength) {
1060
- return;
1061
- }
1062
- if (this.metadataStringChipsArray.regex && !value.match(this.metadataStringChipsArray.regex)) {
1063
- return;
1064
- }
1065
- if (!this.stringChipsArrayValues) {
1066
- if (!this.entity[this.propertyKey]) {
1067
- this.entity[this.propertyKey] = [];
1068
- }
1069
- this.stringChipsArrayValues = this.entity[this.propertyKey];
1070
- }
1071
- this.stringChipsArrayValues.push(value);
1072
- }
1073
- event.chipInput.clear();
1074
- }
1075
- /**
1076
- * Removes the given value from the array.
1077
- * Sets the array to undefined if it is now empty.
1078
- * This is needed because two things are validated: The array itself
1079
- * and the contents of the array. And we need a way to display an
1080
- * mat-error. As the only validation for the array is whether or not
1081
- * it is empty, setting it to undefined here enables us to use the "required" validator.
1082
- *
1083
- * @param value - The string to remove from the array.
1084
- */
1085
- removeStringChipArrayValue(value) {
1086
- this.stringChipsArrayValues.splice(this.stringChipsArrayValues.indexOf(value), 1);
1087
- if (!this.stringChipsArrayValues.length) {
1088
- this.entity[this.propertyKey] = undefined;
1089
- this.stringChipsArrayValues = this.entity[this.propertyKey];
1090
- }
1091
- }
1092
- /**
1093
- * Handles adding a string to the array when an autocomplete value has been selected.
1094
- *
1095
- * @param event - The autocomplete selected event.
1096
- * @param chipsInput - The element where the user typed the value.
1097
- */
1098
- selected(event, chipsInput) {
1099
- const value = (event.option.viewValue || '').trim();
1100
- if (this.metadataStringChipsArray.minLength && value.length < this.metadataStringChipsArray.minLength) {
1101
- return;
1102
- }
1103
- if (this.metadataStringChipsArray.maxLength && value.length > this.metadataStringChipsArray.maxLength) {
1104
- return;
1105
- }
1106
- if (this.metadataStringChipsArray.regex && !value.match(this.metadataStringChipsArray.regex)) {
1107
- return;
1108
- }
1109
- if (!this.stringChipsArrayValues) {
1110
- if (!this.entity[this.propertyKey]) {
1111
- this.entity[this.propertyKey] = [];
1112
- }
1113
- this.stringChipsArrayValues = this.entity[this.propertyKey];
1114
- }
1115
- this.stringChipsArrayValues.push(value);
1116
- chipsInput.value = '';
1117
- }
1118
- /**
1119
- * Dynamically filters the Autocomplete options when the user inputs something.
1120
- *
1121
- * @param input - The input of the user.
1122
- */
1123
- filterAutocompleteStrings(input) {
1124
- const filterValue = input.toLowerCase();
1125
- this.filteredAutocompleteStrings = this.autocompleteStrings.filter(s => s.toLowerCase().includes(filterValue));
1126
- }
1127
2886
  }
1128
2887
  NgxMatEntityInputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityInputComponent, deps: [{ token: i1.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
1129
- NgxMatEntityInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: { entity: "entity", propertyKey: "propertyKey", getValidationErrorMessage: "getValidationErrorMessage", hideOmitForCreate: "hideOmitForCreate", hideOmitForEdit: "hideOmitForEdit" }, viewQueries: [{ propertyName: "addArrayItemDialog", first: true, predicate: ["addArrayItemDialog"], descendants: true }], ngImport: i0, template: "<div [ngSwitch]=\"type\" *ngIf=\"!(hideOmitForCreate && metadata.omitForCreate) && !(hideOmitForEdit && metadata.omitForUpdate)\">\n <!-------------------------------------------->\n <!-----------------Strings-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.STRING\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"entity[propertyKey]\"\n [name]=\"propertyKey.toString()\"\n #model=\"ngModel\"\n [required]=\"metadata.required\"\n [pattern]=\"metadataDefaultString.regex ? metadataDefaultString.regex : '[\\\\s\\\\S]*'\"\n [minlength]=\"metadataDefaultString.minLength ? metadataDefaultString.minLength : null\"\n [maxlength]=\"metadataDefaultString.maxLength ? metadataDefaultString.maxLength : null\"\n />\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.STRING_TEXTBOX\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <textarea\n matInput\n [(ngModel)]=\"entity[propertyKey]\"\n [name]=\"propertyKey.toString()\"\n #model=\"ngModel\"\n cdkTextareaAutosize\n cdkAutosizeMinRows=\"10\"\n [required]=\"metadata.required\"\n [minlength]=\"metadataTextboxString.minLength ? metadataTextboxString.minLength : null\"\n [maxlength]=\"metadataTextboxString.maxLength ? metadataTextboxString.maxLength : null\"\n >\n </textarea>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.STRING_AUTOCOMPLETE\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"entity[propertyKey]\"\n [name]=\"propertyKey.toString()\"\n #model=\"ngModel\"\n [matAutocomplete]=\"auto\"\n (keyup)=\"filterAutocompleteStrings(entity[propertyKey])\"\n [required]=\"metadata.required\"\n [minlength]=\"metadataAutocompleteString.minLength ? metadataAutocompleteString.minLength : null\"\n [maxlength]=\"metadataAutocompleteString.maxLength ? metadataAutocompleteString.maxLength : null\"\n [pattern]=\"metadataAutocompleteString.regex ? metadataAutocompleteString.regex : '[\\\\s\\\\S]*'\"\n />\n <mat-autocomplete #auto=\"matAutocomplete\">\n <mat-option *ngFor=\"let value of filteredAutocompleteStrings\" [value]=\"value\">\n {{value}}\n </mat-option>\n </mat-autocomplete>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.STRING_DROPDOWN\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select [(ngModel)]=\"entity[propertyKey]\" [name]=\"propertyKey.toString()\" #model=\"ngModel\" [required]=\"metadata.required\">\n <mat-option *ngFor=\"let value of metadataDropdownString.dropdownValues\" [value]=\"value.value\">{{value.displayName}}</mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <!-------------------------------------------->\n <!-----------------Booleans------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_CHECKBOX\">\n <mat-form-field class=\"hideUnderline\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-checkbox (click)=\"model.control.markAsTouched()\" [(ngModel)]=\"entity[propertyKey]\" [name]=\"propertyKey.toString()\"></mat-checkbox>\n <!-- hidden input is needed so that the checkbox can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"entity[propertyKey]\"\n [name]=\"propertyKey.toString() + 'Helper'\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required\">\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_TOGGLE\">\n <mat-form-field class=\"hideUnderline\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-slide-toggle (click)=\"model.control.markAsTouched()\" [(ngModel)]=\"entity[propertyKey]\" [name]=\"propertyKey.toString()\"></mat-slide-toggle>\n <!-- hidden input is needed so that the toggle can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"entity[propertyKey]\"\n [name]=\"propertyKey.toString() + 'Helper'\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required\">\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_DROPDOWN\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select [(ngModel)]=\"entity[propertyKey]\" [name]=\"propertyKey.toString()\" #model=\"ngModel\" [required]=\"metadata.required\">\n <mat-option [value]=\"undefined\">-</mat-option>\n <mat-option [value]=\"true\">{{metadataDropdownBoolean.dropdownTrue}}</mat-option>\n <mat-option [value]=\"false\">{{metadataDropdownBoolean.dropdownFalse}}</mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <!-------------------------------------------->\n <!------------------Numbers------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n type=\"number\"\n [(ngModel)]=\"entity[propertyKey]\"\n [name]=\"propertyKey.toString()\"\n #model=\"ngModel\"\n [required]=\"metadata.required\"\n [min]=\"metadataDefaultNumber.min ? metadataDefaultNumber.min : null\"\n [max]=\"metadataDefaultNumber.max ? metadataDefaultNumber.max : null\"\n />\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER_DROPDOWN\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select [(ngModel)]=\"entity[propertyKey]\" [name]=\"propertyKey.toString()\" #model=\"ngModel\" [required]=\"metadata.required\">\n <mat-option *ngFor=\"let value of metadataDropdownNumber.dropdownValues\" [value]=\"value.value\">{{value.displayName}}</mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Object------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.OBJECT\">\n <b>{{metadataDefaultObject.displayName}}</b>\n <!-- iterates over the object properties -->\n\n <div class=\"row\" *ngFor=\"let row of objectPropertyRows\">\n <!--\n displays another ngx-material-entity with the:\n object as the entity,\n the current key in the loop received by the keyvalue direction as the propertyKey\n and the getValidationErrorMessage of the current component\n -->\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"objectProperty\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"getValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n class=\"col-lg-{{getWidth(objectProperty, key, 'lg')}} col-md-{{getWidth(objectProperty, key, 'md')}} col-sm-{{getWidth(objectProperty, key, 'sm')}}\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Array-------------------->\n <!-------------------------------------------->\n <div class=\"entityArray\" *ngSwitchCase=\"DecoratorTypes.ARRAY\">\n <div class=\"mat-elevation-z8\" style=\"border-radius: 5px;padding: 15px;margin-bottom: 15px;margin-top: 15px;\">\n\n <div style=\"padding-bottom: 10px\">\n <b>{{metadataEntityArray.displayName}}</b>\n </div>\n <div *ngIf=\"metadataEntityArray.createInline\">\n <div class=\"row\" *ngFor=\"let row of arrayItemInlineRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"getValidationErrorMessage\"\n class=\"col-lg-{{getWidth(arrayItem, key, 'lg')}} col-md-{{getWidth(arrayItem, key, 'md')}} col-sm-{{getWidth(arrayItem, key, 'sm')}}\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n \n <div class=\"buttons\">\n <button mat-raised-button\n [disabled]=\"metadataEntityArray.createInline && !EntityUtilities.isEntityValid(arrayItem, 'create')\"\n (click)=\"add()\">\n {{metadataEntityArray.addButtonLabel}}\n </button>\n <button mat-raised-button\n [disabled]=\"!selection.selected.length\"\n (click)=\"remove()\">\n {{metadataEntityArray.removeButtonLabel}}\n </button>\n </div>\n \n <mat-table [dataSource]=\"dataSource\">\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox [disabled]=\"!dataSource.data.length\" (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\" [indeterminate]=\"selection.hasValue() && !isAllSelected()\"></mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let module\" class=\"module\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(module) : null\" [checked]=\"selection.isSelected(module)\"></mat-checkbox>\n </mat-cell>\n </ng-container>\n \n <ng-container *ngFor=\"let dCol of metadataEntityArray.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell class=\"entity\" *matCellDef=\"let entity\">\n {{dCol.value(entity)}}\n </mat-cell>\n </ng-container>\n \n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns\"></mat-row>\n </mat-table>\n \n <div class=\"array-error\" *ngIf=\"metadataEntityArray.required && !dataSource.data.length\">\n {{metadataEntityArray.missingErrorMessage}}\n </div>\n </div>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_CHIPS\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-chip-list #chipList\n [(ngModel)]=\"entity[propertyKey]\" [name]=\"propertyKey.toString()\" #model=\"ngModel\"\n [required]=\"metadata.required\"\n >\n <mat-chip *ngFor=\"let value of stringChipsArrayValues\" (removed)=\"removeStringChipArrayValue(value)\">\n {{value}}\n <button matChipRemove>\n <i class=\"{{metadataStringChipsArray.deleteIcon}}\"></i>\n </button>\n </mat-chip>\n <input matInput\n [matChipInputFor]=\"chipList\"\n [matChipInputAddOnBlur]=\"true\"\n (matChipInputTokenEnd)=\"addStringChipArrayValue($event)\"\n [(ngModel)]=\"chipsInput\" [name]=\"propertyKey.toString()\" #chipsModel=\"ngModel\"\n [minlength]='metadataStringChipsArray.minLength ? metadataStringChipsArray.minLength : null'\n [maxlength]='metadataStringChipsArray.maxLength ? metadataStringChipsArray.maxLength : null'\n [pattern]=\"metadataStringChipsArray.regex ? metadataStringChipsArray.regex : '[\\\\s\\\\S]*'\"\n >\n <mat-error *ngIf=\"chipsModel.errors\">{{getValidationErrorMessage(chipsModel)}}</mat-error>\n </mat-chip-list>\n <mat-error *ngIf=\"!chipsModel.errors\">{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_AUTOCOMPLETE_CHIPS\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-chip-list #chipList\n [(ngModel)]=\"entity[propertyKey]\" [name]=\"propertyKey.toString()\" #model=\"ngModel\"\n [required]=\"metadata.required\"\n >\n <mat-chip *ngFor=\"let value of stringChipsArrayValues\" (removed)=\"removeStringChipArrayValue(value)\">\n {{value}}\n <button matChipRemove>\n <i class=\"{{metadataStringChipsArray.deleteIcon}}\"></i>\n </button>\n </mat-chip>\n <input matInput\n [matChipInputFor]=\"chipList\"\n [matAutocomplete]=\"auto\"\n [matChipInputAddOnBlur]=\"true\"\n (matChipInputTokenEnd)=\"addStringChipArrayValue($event)\"\n (keyup)=\"filterAutocompleteStrings(chipsInput)\"\n [(ngModel)]=\"chipsInput\" [name]=\"propertyKey.toString()\" #chipsModel=\"ngModel\"\n #chipsElement\n [minlength]='metadataStringChipsArray.minLength ? metadataStringChipsArray.minLength : null'\n [maxlength]='metadataStringChipsArray.maxLength ? metadataStringChipsArray.maxLength : null'\n [pattern]=\"metadataStringChipsArray.regex ? metadataStringChipsArray.regex : '[\\\\s\\\\S]*'\"\n >\n <mat-error *ngIf=\"chipsModel.errors\">{{getValidationErrorMessage(chipsModel)}}</mat-error>\n </mat-chip-list>\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"selected($event, chipsElement)\">\n <mat-option *ngFor=\"let value of filteredAutocompleteStrings\" [value]=\"value\">\n {{value}}\n </mat-option>\n </mat-autocomplete>\n <mat-error *ngIf=\"!chipsModel.errors\">{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchDefault>ERROR: The type {{type}} is not known.</div>\n</div>\n\n<!--------------------------------------------------------->\n<!--------------------Add Array Item Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #addArrayItemDialog>\n <h2 mat-dialog-title>{{dialogData.createDialogData.title}}</h2>\n\n <mat-dialog-content>\n <form #form=\"ngForm\" class=\"row\">\n <div class=\"row\" *ngFor=\"let row of arrayItemDialogRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"dialogData.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"dialogData.getValidationErrorMessage\"\n class=\"col-lg-{{getWidth(dialogData.entity, key, 'lg')}} col-md-{{getWidth(dialogData.entity, key, 'md')}} col-sm-{{getWidth(dialogData.entity, key, 'sm')}}\"\n >\n </ngx-mat-entity-input>\n </div>\n </form>\n </mat-dialog-content>\n\n <mat-dialog-actions>\n <button mat-raised-button (click)=\"addArrayItem()\" [disabled]=\"!EntityUtilities.isEntityValid(dialogData.entity, 'create')\">\n {{dialogData.createDialogData.createButtonLabel}}\n </button>\n <button mat-raised-button (click)=\"cancelAddArrayItem()\" class=\"cancel-button\">\n {{dialogData.createDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n\n</ng-template>", styles: ["mat-form-field{width:100%}::ng-deep .hideUnderline .mat-form-field-underline{opacity:0%}.entityArray .buttons{display:flex;justify-content:space-between;margin-bottom:10px;margin-top:5px}.entityArray mat-table{border:1px solid #E0E0E0;border-radius:5px;padding-top:5px;padding-bottom:25px}.entityArray .mat-column-select{flex:0 0 75px}.entityArray .array-error{display:flex;align-items:center;justify-content:center;margin-top:-25.8px;border:1px solid #E0E0E0;background-color:#f8d3d7;color:#721c24;height:25.8px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}\n"], components: [{ type: i2.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i4.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: i5.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i6.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i7.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex", "name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "checked"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: ["entity", "propertyKey", "getValidationErrorMessage", "hideOmitForCreate", "hideOmitForEdit"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i9.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { type: i9.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { type: i9.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { type: i10.MatChipList, selector: "mat-chip-list", inputs: ["errorStateMatcher", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "aria-orientation", "selectable", "tabIndex"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }], directives: [{ type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i11.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i11.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i2.MatLabel, selector: "mat-label" }, { type: i12.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i13.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i13.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i13.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { type: i13.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i13.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { type: i13.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { type: i13.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { type: i2.MatError, selector: "mat-error", inputs: ["id"] }, { type: i14.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { type: i3$1.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i11.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i13.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i13.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i13.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i9.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { type: i9.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { type: i9.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { type: i9.MatCellDef, selector: "[matCellDef]" }, { type: i9.MatCell, selector: "mat-cell, td[mat-cell]" }, { type: i9.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { type: i9.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { type: i10.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i10.MatChipRemove, selector: "[matChipRemove]" }, { type: i10.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i11.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { type: i13.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i13.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i13.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]" }] });
2888
+ NgxMatEntityInputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: { entity: "entity", propertyKey: "propertyKey", getValidationErrorMessage: "getValidationErrorMessage", hideOmitForCreate: "hideOmitForCreate", hideOmitForEdit: "hideOmitForEdit" }, outputs: { inputChangeEvent: "inputChangeEvent" }, viewQueries: [{ propertyName: "addArrayItemDialog", first: true, predicate: ["addArrayItemDialog"], descendants: true }], ngImport: i0, template: "<div [ngSwitch]=\"type\" *ngIf=\"!(hideOmitForCreate && metadata.omitForCreate) && !(hideOmitForEdit && metadata.omitForUpdate)\">\n <!-------------------------------------------->\n <!-----------------Strings-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.STRING\">\n <string-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></string-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_TEXTBOX\">\n <string-textbox-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></string-textbox-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_AUTOCOMPLETE\">\n <string-autocomplete-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></string-autocomplete-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_DROPDOWN\">\n <string-dropdown-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></string-dropdown-input>\n </div>\n\n <!-------------------------------------------->\n <!-----------------Booleans------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_CHECKBOX\">\n <boolean-checkbox-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></boolean-checkbox-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_TOGGLE\">\n <boolean-toggle-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></boolean-toggle-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_DROPDOWN\">\n <boolean-dropdown-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></boolean-dropdown-input>\n </div>\n\n <!-------------------------------------------->\n <!------------------Numbers------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER\">\n <number-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></number-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER_DROPDOWN\">\n <number-dropdown-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></number-dropdown-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Object------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.OBJECT\">\n <b>{{metadataDefaultObject.displayName}}</b>\n <!-- iterates over the object properties -->\n <div class=\"row\" *ngFor=\"let row of objectPropertyRows\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"objectProperty\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n class=\"col-lg-{{EntityUtilities.getWidth(objectProperty, key, 'lg')}} col-md-{{EntityUtilities.getWidth(objectProperty, key, 'md')}} col-sm-{{EntityUtilities.getWidth(objectProperty, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Array-------------------->\n <!-------------------------------------------->\n <div class=\"entityArray\" *ngSwitchCase=\"DecoratorTypes.ARRAY\">\n <div class=\"mat-elevation-z8\" style=\"border-radius: 5px;padding: 15px;margin-bottom: 15px;margin-top: 15px;\">\n <div style=\"padding-bottom: 10px\">\n <b>{{metadataEntityArray.displayName}}</b>\n </div>\n <div *ngIf=\"metadataEntityArray.createInline\">\n <div class=\"row\" *ngFor=\"let row of arrayItemInlineRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n \n <div class=\"buttons\">\n <button mat-raised-button\n [disabled]=\"metadataEntityArray.createInline && !isArrayItemValid\"\n (click)=\"addEntity()\">\n {{metadataEntityArray.addButtonLabel}}\n </button>\n <button mat-raised-button\n [disabled]=\"!selection.selected.length\"\n (click)=\"remove(selection, entityArrayValues, dataSource)\">\n {{metadataEntityArray.removeButtonLabel}}\n </button>\n </div>\n \n <mat-table [dataSource]=\"dataSource\">\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox [disabled]=\"!dataSource.data.length\" (change)=\"$event ? masterToggle(selection, dataSource) : null\" [checked]=\"selection.hasValue() && isAllSelected(selection, dataSource)\" [indeterminate]=\"selection.hasValue() && !isAllSelected(selection, dataSource)\"></mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let module\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(module) : null\" [checked]=\"selection.isSelected(module)\"></mat-checkbox>\n </mat-cell>\n </ng-container>\n \n <ng-container *ngFor=\"let dCol of metadataEntityArray.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell class=\"entity\" *matCellDef=\"let entity\">\n {{dCol.value(entity)}}\n </mat-cell>\n </ng-container>\n \n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns\"></mat-row>\n </mat-table>\n \n <div class=\"array-error\" *ngIf=\"metadataEntityArray.required && !dataSource.data.length\">\n {{metadataEntityArray.missingErrorMessage}}\n </div>\n </div>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE\">\n <array-date-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></array-date-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE_TIME\">\n <array-date-time-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></array-date-time-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE_RANGE\">\n <array-date-range-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></array-date-range-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_CHIPS\">\n <array-string-chips-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></array-string-chips-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_AUTOCOMPLETE_CHIPS\">\n <array-string-autocomplete-chips (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></array-string-autocomplete-chips>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Dates-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.DATE\">\n <date-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></date-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.DATE_RANGE\">\n <date-range-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></date-range-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.DATE_TIME\">\n <date-time-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></date-time-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Files-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.FILE_DEFAULT\">\n <file-default-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></file-default-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.FILE_IMAGE\">\n <file-image-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></file-image-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Custom------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.CUSTOM\">\n <custom-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></custom-input>\n </div>\n\n <div *ngSwitchDefault>ERROR: The type {{type}} is not known.</div>\n</div>\n\n<!--------------------------------------------------------->\n<!--------------------Add Array Item Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #addArrayItemDialog>\n <h2 mat-dialog-title>{{dialogData.createDialogData.title}}</h2>\n\n <mat-dialog-content>\n <form #form=\"ngForm\" class=\"row\">\n <div class=\"row\" *ngFor=\"let row of arrayItemDialogRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"dialogData.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"dialogData.getValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(dialogData.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(dialogData.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(dialogData.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsDialogArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </form>\n </mat-dialog-content>\n\n <mat-dialog-actions>\n <button mat-raised-button (click)=\"addArrayItem()\" [disabled]=\"!isDialogArrayItemValid\">\n {{dialogData.createDialogData.createButtonLabel}}\n </button>\n <button mat-raised-button (click)=\"cancelAddArrayItem()\" class=\"cancel-button\">\n {{dialogData.createDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n\n</ng-template>", styles: ["mat-form-field{width:100%}.entityArray .buttons{display:flex;justify-content:space-between;margin-bottom:10px;margin-top:5px}.entityArray mat-table{border:1px solid #E0E0E0;border-radius:5px;padding-top:5px;padding-bottom:25px}.entityArray .mat-column-select{flex:0 0 75px}.entityArray .array-error{display:flex;align-items:center;justify-content:center;margin-top:-25.8px;border:1px solid #E0E0E0;background-color:#f8d3d7;color:#721c24;height:25.8px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}\n"], components: [{ type: StringInputComponent, selector: "string-input" }, { type: StringTextboxInputComponent, selector: "string-textbox-input" }, { type: StringAutocompleteInputComponent, selector: "string-autocomplete-input" }, { type: StringDropdownInputComponent, selector: "string-dropdown-input" }, { type: BooleanCheckboxInputComponent, selector: "boolean-checkbox-input" }, { type: BooleanToggleInputComponent, selector: "boolean-toggle-input" }, { type: BooleanDropdownInputComponent, selector: "boolean-dropdown-input" }, { type: NumberInputComponent, selector: "number-input" }, { type: NumberDropdownInputComponent, selector: "number-dropdown-input" }, { type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: ["entity", "propertyKey", "getValidationErrorMessage", "hideOmitForCreate", "hideOmitForEdit"], outputs: ["inputChangeEvent"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i4$2.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { type: i2.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i4$2.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { type: i4$2.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { type: ArrayDateInputComponent, selector: "array-date-input" }, { type: ArrayDateTimeInputComponent, selector: "array-date-time-input" }, { type: ArrayDateRangeInputComponent, selector: "array-date-range-input" }, { type: ArrayStringChipsInputComponent, selector: "array-string-chips-input" }, { type: ArrayStringAutocompleteChipsComponent, selector: "array-string-autocomplete-chips" }, { type: DateInputComponent, selector: "date-input" }, { type: DateRangeInputComponent, selector: "date-range-input" }, { type: DateTimeInputComponent, selector: "date-time-input" }, { type: FileDefaultInputComponent, selector: "file-default-input" }, { type: FileImageInputComponent, selector: "file-image-input" }, { type: CustomInputComponent, selector: "custom-input" }], directives: [{ type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i4.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i4$2.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { type: i4$2.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { type: i4$2.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { type: i4$2.MatCellDef, selector: "[matCellDef]" }, { type: i4$2.MatCell, selector: "mat-cell, td[mat-cell]" }, { type: i4$2.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { type: i4$2.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { type: i4.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { type: i3$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i3$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i3$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]" }] });
1130
2889
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityInputComponent, decorators: [{
1131
2890
  type: Component,
1132
- args: [{ selector: 'ngx-mat-entity-input', template: "<div [ngSwitch]=\"type\" *ngIf=\"!(hideOmitForCreate && metadata.omitForCreate) && !(hideOmitForEdit && metadata.omitForUpdate)\">\n <!-------------------------------------------->\n <!-----------------Strings-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.STRING\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"entity[propertyKey]\"\n [name]=\"propertyKey.toString()\"\n #model=\"ngModel\"\n [required]=\"metadata.required\"\n [pattern]=\"metadataDefaultString.regex ? metadataDefaultString.regex : '[\\\\s\\\\S]*'\"\n [minlength]=\"metadataDefaultString.minLength ? metadataDefaultString.minLength : null\"\n [maxlength]=\"metadataDefaultString.maxLength ? metadataDefaultString.maxLength : null\"\n />\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.STRING_TEXTBOX\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <textarea\n matInput\n [(ngModel)]=\"entity[propertyKey]\"\n [name]=\"propertyKey.toString()\"\n #model=\"ngModel\"\n cdkTextareaAutosize\n cdkAutosizeMinRows=\"10\"\n [required]=\"metadata.required\"\n [minlength]=\"metadataTextboxString.minLength ? metadataTextboxString.minLength : null\"\n [maxlength]=\"metadataTextboxString.maxLength ? metadataTextboxString.maxLength : null\"\n >\n </textarea>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.STRING_AUTOCOMPLETE\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n [(ngModel)]=\"entity[propertyKey]\"\n [name]=\"propertyKey.toString()\"\n #model=\"ngModel\"\n [matAutocomplete]=\"auto\"\n (keyup)=\"filterAutocompleteStrings(entity[propertyKey])\"\n [required]=\"metadata.required\"\n [minlength]=\"metadataAutocompleteString.minLength ? metadataAutocompleteString.minLength : null\"\n [maxlength]=\"metadataAutocompleteString.maxLength ? metadataAutocompleteString.maxLength : null\"\n [pattern]=\"metadataAutocompleteString.regex ? metadataAutocompleteString.regex : '[\\\\s\\\\S]*'\"\n />\n <mat-autocomplete #auto=\"matAutocomplete\">\n <mat-option *ngFor=\"let value of filteredAutocompleteStrings\" [value]=\"value\">\n {{value}}\n </mat-option>\n </mat-autocomplete>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.STRING_DROPDOWN\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select [(ngModel)]=\"entity[propertyKey]\" [name]=\"propertyKey.toString()\" #model=\"ngModel\" [required]=\"metadata.required\">\n <mat-option *ngFor=\"let value of metadataDropdownString.dropdownValues\" [value]=\"value.value\">{{value.displayName}}</mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <!-------------------------------------------->\n <!-----------------Booleans------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_CHECKBOX\">\n <mat-form-field class=\"hideUnderline\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-checkbox (click)=\"model.control.markAsTouched()\" [(ngModel)]=\"entity[propertyKey]\" [name]=\"propertyKey.toString()\"></mat-checkbox>\n <!-- hidden input is needed so that the checkbox can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"entity[propertyKey]\"\n [name]=\"propertyKey.toString() + 'Helper'\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required\">\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_TOGGLE\">\n <mat-form-field class=\"hideUnderline\">\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-slide-toggle (click)=\"model.control.markAsTouched()\" [(ngModel)]=\"entity[propertyKey]\" [name]=\"propertyKey.toString()\"></mat-slide-toggle>\n <!-- hidden input is needed so that the toggle can be used inside a mat-form-field -->\n <input matInput hidden\n [(ngModel)]=\"entity[propertyKey]\"\n [name]=\"propertyKey.toString() + 'Helper'\"\n #model=\"ngModel\"\n [pattern]=\"metadata.required ? 'true' : '[\\\\s\\\\S]*'\"\n [required]=\"metadata.required\">\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_DROPDOWN\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select [(ngModel)]=\"entity[propertyKey]\" [name]=\"propertyKey.toString()\" #model=\"ngModel\" [required]=\"metadata.required\">\n <mat-option [value]=\"undefined\">-</mat-option>\n <mat-option [value]=\"true\">{{metadataDropdownBoolean.dropdownTrue}}</mat-option>\n <mat-option [value]=\"false\">{{metadataDropdownBoolean.dropdownFalse}}</mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <!-------------------------------------------->\n <!------------------Numbers------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <input\n matInput\n type=\"number\"\n [(ngModel)]=\"entity[propertyKey]\"\n [name]=\"propertyKey.toString()\"\n #model=\"ngModel\"\n [required]=\"metadata.required\"\n [min]=\"metadataDefaultNumber.min ? metadataDefaultNumber.min : null\"\n [max]=\"metadataDefaultNumber.max ? metadataDefaultNumber.max : null\"\n />\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER_DROPDOWN\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-select [(ngModel)]=\"entity[propertyKey]\" [name]=\"propertyKey.toString()\" #model=\"ngModel\" [required]=\"metadata.required\">\n <mat-option *ngFor=\"let value of metadataDropdownNumber.dropdownValues\" [value]=\"value.value\">{{value.displayName}}</mat-option>\n </mat-select>\n <mat-error>{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Object------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.OBJECT\">\n <b>{{metadataDefaultObject.displayName}}</b>\n <!-- iterates over the object properties -->\n\n <div class=\"row\" *ngFor=\"let row of objectPropertyRows\">\n <!--\n displays another ngx-material-entity with the:\n object as the entity,\n the current key in the loop received by the keyvalue direction as the propertyKey\n and the getValidationErrorMessage of the current component\n -->\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"objectProperty\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"getValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n class=\"col-lg-{{getWidth(objectProperty, key, 'lg')}} col-md-{{getWidth(objectProperty, key, 'md')}} col-sm-{{getWidth(objectProperty, key, 'sm')}}\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Array-------------------->\n <!-------------------------------------------->\n <div class=\"entityArray\" *ngSwitchCase=\"DecoratorTypes.ARRAY\">\n <div class=\"mat-elevation-z8\" style=\"border-radius: 5px;padding: 15px;margin-bottom: 15px;margin-top: 15px;\">\n\n <div style=\"padding-bottom: 10px\">\n <b>{{metadataEntityArray.displayName}}</b>\n </div>\n <div *ngIf=\"metadataEntityArray.createInline\">\n <div class=\"row\" *ngFor=\"let row of arrayItemInlineRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"getValidationErrorMessage\"\n class=\"col-lg-{{getWidth(arrayItem, key, 'lg')}} col-md-{{getWidth(arrayItem, key, 'md')}} col-sm-{{getWidth(arrayItem, key, 'sm')}}\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n \n <div class=\"buttons\">\n <button mat-raised-button\n [disabled]=\"metadataEntityArray.createInline && !EntityUtilities.isEntityValid(arrayItem, 'create')\"\n (click)=\"add()\">\n {{metadataEntityArray.addButtonLabel}}\n </button>\n <button mat-raised-button\n [disabled]=\"!selection.selected.length\"\n (click)=\"remove()\">\n {{metadataEntityArray.removeButtonLabel}}\n </button>\n </div>\n \n <mat-table [dataSource]=\"dataSource\">\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox [disabled]=\"!dataSource.data.length\" (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\" [indeterminate]=\"selection.hasValue() && !isAllSelected()\"></mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let module\" class=\"module\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(module) : null\" [checked]=\"selection.isSelected(module)\"></mat-checkbox>\n </mat-cell>\n </ng-container>\n \n <ng-container *ngFor=\"let dCol of metadataEntityArray.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell class=\"entity\" *matCellDef=\"let entity\">\n {{dCol.value(entity)}}\n </mat-cell>\n </ng-container>\n \n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns\"></mat-row>\n </mat-table>\n \n <div class=\"array-error\" *ngIf=\"metadataEntityArray.required && !dataSource.data.length\">\n {{metadataEntityArray.missingErrorMessage}}\n </div>\n </div>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_CHIPS\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-chip-list #chipList\n [(ngModel)]=\"entity[propertyKey]\" [name]=\"propertyKey.toString()\" #model=\"ngModel\"\n [required]=\"metadata.required\"\n >\n <mat-chip *ngFor=\"let value of stringChipsArrayValues\" (removed)=\"removeStringChipArrayValue(value)\">\n {{value}}\n <button matChipRemove>\n <i class=\"{{metadataStringChipsArray.deleteIcon}}\"></i>\n </button>\n </mat-chip>\n <input matInput\n [matChipInputFor]=\"chipList\"\n [matChipInputAddOnBlur]=\"true\"\n (matChipInputTokenEnd)=\"addStringChipArrayValue($event)\"\n [(ngModel)]=\"chipsInput\" [name]=\"propertyKey.toString()\" #chipsModel=\"ngModel\"\n [minlength]='metadataStringChipsArray.minLength ? metadataStringChipsArray.minLength : null'\n [maxlength]='metadataStringChipsArray.maxLength ? metadataStringChipsArray.maxLength : null'\n [pattern]=\"metadataStringChipsArray.regex ? metadataStringChipsArray.regex : '[\\\\s\\\\S]*'\"\n >\n <mat-error *ngIf=\"chipsModel.errors\">{{getValidationErrorMessage(chipsModel)}}</mat-error>\n </mat-chip-list>\n <mat-error *ngIf=\"!chipsModel.errors\">{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_AUTOCOMPLETE_CHIPS\">\n <mat-form-field>\n <mat-label>{{metadata.displayName}}</mat-label>\n <mat-chip-list #chipList\n [(ngModel)]=\"entity[propertyKey]\" [name]=\"propertyKey.toString()\" #model=\"ngModel\"\n [required]=\"metadata.required\"\n >\n <mat-chip *ngFor=\"let value of stringChipsArrayValues\" (removed)=\"removeStringChipArrayValue(value)\">\n {{value}}\n <button matChipRemove>\n <i class=\"{{metadataStringChipsArray.deleteIcon}}\"></i>\n </button>\n </mat-chip>\n <input matInput\n [matChipInputFor]=\"chipList\"\n [matAutocomplete]=\"auto\"\n [matChipInputAddOnBlur]=\"true\"\n (matChipInputTokenEnd)=\"addStringChipArrayValue($event)\"\n (keyup)=\"filterAutocompleteStrings(chipsInput)\"\n [(ngModel)]=\"chipsInput\" [name]=\"propertyKey.toString()\" #chipsModel=\"ngModel\"\n #chipsElement\n [minlength]='metadataStringChipsArray.minLength ? metadataStringChipsArray.minLength : null'\n [maxlength]='metadataStringChipsArray.maxLength ? metadataStringChipsArray.maxLength : null'\n [pattern]=\"metadataStringChipsArray.regex ? metadataStringChipsArray.regex : '[\\\\s\\\\S]*'\"\n >\n <mat-error *ngIf=\"chipsModel.errors\">{{getValidationErrorMessage(chipsModel)}}</mat-error>\n </mat-chip-list>\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"selected($event, chipsElement)\">\n <mat-option *ngFor=\"let value of filteredAutocompleteStrings\" [value]=\"value\">\n {{value}}\n </mat-option>\n </mat-autocomplete>\n <mat-error *ngIf=\"!chipsModel.errors\">{{getValidationErrorMessage(model)}}</mat-error>\n </mat-form-field>\n </div>\n\n <div *ngSwitchDefault>ERROR: The type {{type}} is not known.</div>\n</div>\n\n<!--------------------------------------------------------->\n<!--------------------Add Array Item Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #addArrayItemDialog>\n <h2 mat-dialog-title>{{dialogData.createDialogData.title}}</h2>\n\n <mat-dialog-content>\n <form #form=\"ngForm\" class=\"row\">\n <div class=\"row\" *ngFor=\"let row of arrayItemDialogRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"dialogData.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"dialogData.getValidationErrorMessage\"\n class=\"col-lg-{{getWidth(dialogData.entity, key, 'lg')}} col-md-{{getWidth(dialogData.entity, key, 'md')}} col-sm-{{getWidth(dialogData.entity, key, 'sm')}}\"\n >\n </ngx-mat-entity-input>\n </div>\n </form>\n </mat-dialog-content>\n\n <mat-dialog-actions>\n <button mat-raised-button (click)=\"addArrayItem()\" [disabled]=\"!EntityUtilities.isEntityValid(dialogData.entity, 'create')\">\n {{dialogData.createDialogData.createButtonLabel}}\n </button>\n <button mat-raised-button (click)=\"cancelAddArrayItem()\" class=\"cancel-button\">\n {{dialogData.createDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n\n</ng-template>", styles: ["mat-form-field{width:100%}::ng-deep .hideUnderline .mat-form-field-underline{opacity:0%}.entityArray .buttons{display:flex;justify-content:space-between;margin-bottom:10px;margin-top:5px}.entityArray mat-table{border:1px solid #E0E0E0;border-radius:5px;padding-top:5px;padding-bottom:25px}.entityArray .mat-column-select{flex:0 0 75px}.entityArray .array-error{display:flex;align-items:center;justify-content:center;margin-top:-25.8px;border:1px solid #E0E0E0;background-color:#f8d3d7;color:#721c24;height:25.8px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}\n"] }]
2891
+ args: [{ selector: 'ngx-mat-entity-input', template: "<div [ngSwitch]=\"type\" *ngIf=\"!(hideOmitForCreate && metadata.omitForCreate) && !(hideOmitForEdit && metadata.omitForUpdate)\">\n <!-------------------------------------------->\n <!-----------------Strings-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.STRING\">\n <string-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></string-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_TEXTBOX\">\n <string-textbox-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></string-textbox-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_AUTOCOMPLETE\">\n <string-autocomplete-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></string-autocomplete-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.STRING_DROPDOWN\">\n <string-dropdown-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></string-dropdown-input>\n </div>\n\n <!-------------------------------------------->\n <!-----------------Booleans------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_CHECKBOX\">\n <boolean-checkbox-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></boolean-checkbox-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_TOGGLE\">\n <boolean-toggle-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></boolean-toggle-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.BOOLEAN_DROPDOWN\">\n <boolean-dropdown-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></boolean-dropdown-input>\n </div>\n\n <!-------------------------------------------->\n <!------------------Numbers------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER\">\n <number-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></number-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.NUMBER_DROPDOWN\">\n <number-dropdown-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></number-dropdown-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Object------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.OBJECT\">\n <b>{{metadataDefaultObject.displayName}}</b>\n <!-- iterates over the object properties -->\n <div class=\"row\" *ngFor=\"let row of objectPropertyRows\">\n <ngx-mat-entity-input *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"objectProperty\"\n [propertyKey]=\"key\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n [hideOmitForCreate]=\"hideOmitForCreate\"\n [hideOmitForEdit]=\"hideOmitForEdit\"\n class=\"col-lg-{{EntityUtilities.getWidth(objectProperty, key, 'lg')}} col-md-{{EntityUtilities.getWidth(objectProperty, key, 'md')}} col-sm-{{EntityUtilities.getWidth(objectProperty, key, 'sm')}}\"\n (inputChangeEvent)=\"emitChange()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Array-------------------->\n <!-------------------------------------------->\n <div class=\"entityArray\" *ngSwitchCase=\"DecoratorTypes.ARRAY\">\n <div class=\"mat-elevation-z8\" style=\"border-radius: 5px;padding: 15px;margin-bottom: 15px;margin-top: 15px;\">\n <div style=\"padding-bottom: 10px\">\n <b>{{metadataEntityArray.displayName}}</b>\n </div>\n <div *ngIf=\"metadataEntityArray.createInline\">\n <div class=\"row\" *ngFor=\"let row of arrayItemInlineRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys; let i = index; trackBy: trackByFn\"\n [entity]=\"arrayItem\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(arrayItem, key, 'lg')}} col-md-{{EntityUtilities.getWidth(arrayItem, key, 'md')}} col-sm-{{EntityUtilities.getWidth(arrayItem, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </div>\n \n <div class=\"buttons\">\n <button mat-raised-button\n [disabled]=\"metadataEntityArray.createInline && !isArrayItemValid\"\n (click)=\"addEntity()\">\n {{metadataEntityArray.addButtonLabel}}\n </button>\n <button mat-raised-button\n [disabled]=\"!selection.selected.length\"\n (click)=\"remove(selection, entityArrayValues, dataSource)\">\n {{metadataEntityArray.removeButtonLabel}}\n </button>\n </div>\n \n <mat-table [dataSource]=\"dataSource\">\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox [disabled]=\"!dataSource.data.length\" (change)=\"$event ? masterToggle(selection, dataSource) : null\" [checked]=\"selection.hasValue() && isAllSelected(selection, dataSource)\" [indeterminate]=\"selection.hasValue() && !isAllSelected(selection, dataSource)\"></mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let module\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(module) : null\" [checked]=\"selection.isSelected(module)\"></mat-checkbox>\n </mat-cell>\n </ng-container>\n \n <ng-container *ngFor=\"let dCol of metadataEntityArray.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell class=\"entity\" *matCellDef=\"let entity\">\n {{dCol.value(entity)}}\n </mat-cell>\n </ng-container>\n \n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns\"></mat-row>\n </mat-table>\n \n <div class=\"array-error\" *ngIf=\"metadataEntityArray.required && !dataSource.data.length\">\n {{metadataEntityArray.missingErrorMessage}}\n </div>\n </div>\n </div>\n\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE\">\n <array-date-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></array-date-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE_TIME\">\n <array-date-time-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></array-date-time-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_DATE_RANGE\">\n <array-date-range-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></array-date-range-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_CHIPS\">\n <array-string-chips-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></array-string-chips-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.ARRAY_STRING_AUTOCOMPLETE_CHIPS\">\n <array-string-autocomplete-chips (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></array-string-autocomplete-chips>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Dates-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.DATE\">\n <date-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></date-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.DATE_RANGE\">\n <date-range-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></date-range-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.DATE_TIME\">\n <date-time-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></date-time-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Files-------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.FILE_DEFAULT\">\n <file-default-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></file-default-input>\n </div>\n <div *ngSwitchCase=\"DecoratorTypes.FILE_IMAGE\">\n <file-image-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></file-image-input>\n </div>\n\n <!-------------------------------------------->\n <!-------------------Custom------------------->\n <!-------------------------------------------->\n <div *ngSwitchCase=\"DecoratorTypes.CUSTOM\">\n <custom-input (inputChangeEvent)=\"emitChange()\" [entity]=\"internalEntity\" [key]=\"internalPropertyKey\" [getValidationErrorMessage]=\"internalGetValidationErrorMessage\"></custom-input>\n </div>\n\n <div *ngSwitchDefault>ERROR: The type {{type}} is not known.</div>\n</div>\n\n<!--------------------------------------------------------->\n<!--------------------Add Array Item Dialog---------------->\n<!--------------------------------------------------------->\n<ng-template #addArrayItemDialog>\n <h2 mat-dialog-title>{{dialogData.createDialogData.title}}</h2>\n\n <mat-dialog-content>\n <form #form=\"ngForm\" class=\"row\">\n <div class=\"row\" *ngFor=\"let row of arrayItemDialogRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"dialogData.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n [getValidationErrorMessage]=\"dialogData.getValidationErrorMessage\"\n class=\"col-lg-{{EntityUtilities.getWidth(dialogData.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(dialogData.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(dialogData.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsDialogArrayItemValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </form>\n </mat-dialog-content>\n\n <mat-dialog-actions>\n <button mat-raised-button (click)=\"addArrayItem()\" [disabled]=\"!isDialogArrayItemValid\">\n {{dialogData.createDialogData.createButtonLabel}}\n </button>\n <button mat-raised-button (click)=\"cancelAddArrayItem()\" class=\"cancel-button\">\n {{dialogData.createDialogData.cancelButtonLabel}}\n </button>\n </mat-dialog-actions>\n\n</ng-template>", styles: ["mat-form-field{width:100%}.entityArray .buttons{display:flex;justify-content:space-between;margin-bottom:10px;margin-top:5px}.entityArray mat-table{border:1px solid #E0E0E0;border-radius:5px;padding-top:5px;padding-bottom:25px}.entityArray .mat-column-select{flex:0 0 75px}.entityArray .array-error{display:flex;align-items:center;justify-content:center;margin-top:-25.8px;border:1px solid #E0E0E0;background-color:#f8d3d7;color:#721c24;height:25.8px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}\n"] }]
1133
2892
  }], ctorParameters: function () { return [{ type: i1.MatDialog }]; }, propDecorators: { entity: [{
1134
2893
  type: Input
1135
2894
  }], propertyKey: [{
@@ -1140,6 +2899,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1140
2899
  type: Input
1141
2900
  }], hideOmitForEdit: [{
1142
2901
  type: Input
2902
+ }], inputChangeEvent: [{
2903
+ type: Output
1143
2904
  }], addArrayItemDialog: [{
1144
2905
  type: ViewChild,
1145
2906
  args: ['addArrayItemDialog']
@@ -1148,7 +2909,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1148
2909
  class NgxMatEntityInputModule {
1149
2910
  }
1150
2911
  NgxMatEntityInputModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityInputModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1151
- NgxMatEntityInputModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityInputModule, declarations: [NgxMatEntityInputComponent], imports: [CommonModule,
2912
+ NgxMatEntityInputModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityInputModule, declarations: [StringInputComponent,
2913
+ StringTextboxInputComponent,
2914
+ StringAutocompleteInputComponent,
2915
+ StringDropdownInputComponent,
2916
+ BooleanCheckboxInputComponent,
2917
+ BooleanToggleInputComponent,
2918
+ BooleanDropdownInputComponent,
2919
+ NumberInputComponent,
2920
+ NumberDropdownInputComponent,
2921
+ ArrayStringChipsInputComponent,
2922
+ ArrayStringAutocompleteChipsComponent,
2923
+ DateInputComponent,
2924
+ DateRangeInputComponent,
2925
+ DateTimeInputComponent,
2926
+ ArrayDateInputComponent,
2927
+ ArrayDateTimeInputComponent,
2928
+ ArrayDateRangeInputComponent,
2929
+ FileInputComponent,
2930
+ FileImageInputComponent,
2931
+ FileDefaultInputComponent,
2932
+ DragDropDirective,
2933
+ CustomInputComponent,
2934
+ NgxMatEntityInputComponent], imports: [CommonModule,
1152
2935
  MatInputModule,
1153
2936
  FormsModule,
1154
2937
  MatFormFieldModule,
@@ -1160,7 +2943,8 @@ NgxMatEntityInputModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0",
1160
2943
  MatIconModule,
1161
2944
  MatTableModule,
1162
2945
  MatDialogModule,
1163
- MatButtonModule], exports: [NgxMatEntityInputComponent] });
2946
+ MatButtonModule,
2947
+ MatDatepickerModule], exports: [NgxMatEntityInputComponent] });
1164
2948
  NgxMatEntityInputModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityInputModule, imports: [[
1165
2949
  CommonModule,
1166
2950
  MatInputModule,
@@ -1174,13 +2958,36 @@ NgxMatEntityInputModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0",
1174
2958
  MatIconModule,
1175
2959
  MatTableModule,
1176
2960
  MatDialogModule,
1177
- MatButtonModule
2961
+ MatButtonModule,
2962
+ MatDatepickerModule
1178
2963
  ]] });
1179
2964
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityInputModule, decorators: [{
1180
2965
  type: NgModule,
1181
2966
  args: [{
1182
2967
  declarations: [
1183
- NgxMatEntityInputComponent,
2968
+ StringInputComponent,
2969
+ StringTextboxInputComponent,
2970
+ StringAutocompleteInputComponent,
2971
+ StringDropdownInputComponent,
2972
+ BooleanCheckboxInputComponent,
2973
+ BooleanToggleInputComponent,
2974
+ BooleanDropdownInputComponent,
2975
+ NumberInputComponent,
2976
+ NumberDropdownInputComponent,
2977
+ ArrayStringChipsInputComponent,
2978
+ ArrayStringAutocompleteChipsComponent,
2979
+ DateInputComponent,
2980
+ DateRangeInputComponent,
2981
+ DateTimeInputComponent,
2982
+ ArrayDateInputComponent,
2983
+ ArrayDateTimeInputComponent,
2984
+ ArrayDateRangeInputComponent,
2985
+ FileInputComponent,
2986
+ FileImageInputComponent,
2987
+ FileDefaultInputComponent,
2988
+ DragDropDirective,
2989
+ CustomInputComponent,
2990
+ NgxMatEntityInputComponent
1184
2991
  ],
1185
2992
  imports: [
1186
2993
  CommonModule,
@@ -1195,7 +3002,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1195
3002
  MatIconModule,
1196
3003
  MatTableModule,
1197
3004
  MatDialogModule,
1198
- MatButtonModule
3005
+ MatButtonModule,
3006
+ MatDatepickerModule
1199
3007
  ],
1200
3008
  exports: [NgxMatEntityInputComponent]
1201
3009
  }]
@@ -1238,7 +3046,7 @@ class NgxMatEntityCreateDialogComponent {
1238
3046
  this.injector = injector;
1239
3047
  this.dialog = dialog;
1240
3048
  this.EntityUtilities = EntityUtilities;
1241
- this.getWidth = EntityUtilities.getWidth;
3049
+ this.isEntityValid = false;
1242
3050
  }
1243
3051
  ngOnInit() {
1244
3052
  this.data = new CreateEntityDialogDataBuilder(this.inputData).getResult();
@@ -1246,15 +3054,22 @@ class NgxMatEntityCreateDialogComponent {
1246
3054
  this.entityRows = EntityUtilities.getEntityRows(this.data.entity, true);
1247
3055
  this.entityService = this.injector.get(this.data.EntityServiceClass);
1248
3056
  }
3057
+ /**
3058
+ * Checks if the entity is valid.
3059
+ */
3060
+ checkIsEntityValid() {
3061
+ this.isEntityValid = EntityUtilities.isEntityValid(this.data.entity, 'create');
3062
+ }
1249
3063
  /**
1250
3064
  * Tries add the new entity and close the dialog afterwards.
1251
3065
  * Also handles the confirmation if required.
1252
3066
  */
1253
3067
  create() {
1254
- if (!this.data.createDialogData?.createRequiresConfirmDialog) {
1255
- return this.confirmCreate();
3068
+ if (!this.data.createDialogData.createRequiresConfirmDialog) {
3069
+ this.confirmCreate();
3070
+ return;
1256
3071
  }
1257
- const dialogData = new ConfirmDialogDataBuilder(this.data.createDialogData?.confirmCreateDialogData)
3072
+ const dialogData = new ConfirmDialogDataBuilder(this.data.createDialogData.confirmCreateDialogData)
1258
3073
  .withDefault('text', ['Do you really want to create this entity?'])
1259
3074
  .withDefault('confirmButtonLabel', 'Create')
1260
3075
  .withDefault('title', 'Create')
@@ -1271,7 +3086,7 @@ class NgxMatEntityCreateDialogComponent {
1271
3086
  });
1272
3087
  }
1273
3088
  confirmCreate() {
1274
- this.entityService.create(this.data.entity).then(() => this.dialogRef.close());
3089
+ void this.entityService.create(this.data.entity).then(() => this.dialogRef.close());
1275
3090
  }
1276
3091
  /**
1277
3092
  * Closes the dialog.
@@ -1281,10 +3096,10 @@ class NgxMatEntityCreateDialogComponent {
1281
3096
  }
1282
3097
  }
1283
3098
  NgxMatEntityCreateDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityCreateDialogComponent, deps: [{ token: MAT_DIALOG_DATA }, { token: i1.MatDialogRef }, { token: i0.Injector }, { token: i1.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
1284
- NgxMatEntityCreateDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: NgxMatEntityCreateDialogComponent, selector: "ngx-mat-entity-create-dialog", ngImport: i0, template: "<h2 mat-dialog-title>{{data.createDialogData.title}}</h2>\n\n<mat-dialog-content>\n <form #form=\"ngForm\">\n <div class=\"row\" *ngFor=\"let row of entityRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{getWidth(data.entity, key, 'lg')}} col-md-{{getWidth(data.entity, key, 'md')}} col-sm-{{getWidth(data.entity, key, 'sm')}}\"\n >\n </ngx-mat-entity-input>\n </div>\n </form>\n</mat-dialog-content>\n\n<mat-dialog-actions>\n <button mat-raised-button (click)=\"create()\" [disabled]=\"!EntityUtilities.isEntityValid(data.entity, 'create')\">\n {{data.createDialogData.createButtonLabel}}\n </button>\n <button mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.createDialogData.cancelButtonLabel}}\n </button>\n</mat-dialog-actions>\n", styles: ["mat-dialog-actions{display:flex;justify-content:space-between}\n"], components: [{ type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: ["entity", "propertyKey", "getValidationErrorMessage", "hideOmitForCreate", "hideOmitForEdit"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { type: i13.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i13.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i13.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i11.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]" }] });
3099
+ NgxMatEntityCreateDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: NgxMatEntityCreateDialogComponent, selector: "ngx-mat-entity-create-dialog", ngImport: i0, template: "<h2 mat-dialog-title>{{data.createDialogData.title}}</h2>\n\n<mat-dialog-content>\n <form #form=\"ngForm\">\n <div class=\"row\" *ngFor=\"let row of entityRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsEntityValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </form>\n</mat-dialog-content>\n\n<mat-dialog-actions>\n <button mat-raised-button (click)=\"create()\" [disabled]=\"!isEntityValid\">\n {{data.createDialogData.createButtonLabel}}\n </button>\n <button mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.createDialogData.cancelButtonLabel}}\n </button>\n</mat-dialog-actions>\n", styles: ["mat-dialog-actions{display:flex;justify-content:space-between}\n"], components: [{ type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: ["entity", "propertyKey", "getValidationErrorMessage", "hideOmitForCreate", "hideOmitForEdit"], outputs: ["inputChangeEvent"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { type: i3$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i3$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i3$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]" }] });
1285
3100
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityCreateDialogComponent, decorators: [{
1286
3101
  type: Component,
1287
- args: [{ selector: 'ngx-mat-entity-create-dialog', template: "<h2 mat-dialog-title>{{data.createDialogData.title}}</h2>\n\n<mat-dialog-content>\n <form #form=\"ngForm\">\n <div class=\"row\" *ngFor=\"let row of entityRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{getWidth(data.entity, key, 'lg')}} col-md-{{getWidth(data.entity, key, 'md')}} col-sm-{{getWidth(data.entity, key, 'sm')}}\"\n >\n </ngx-mat-entity-input>\n </div>\n </form>\n</mat-dialog-content>\n\n<mat-dialog-actions>\n <button mat-raised-button (click)=\"create()\" [disabled]=\"!EntityUtilities.isEntityValid(data.entity, 'create')\">\n {{data.createDialogData.createButtonLabel}}\n </button>\n <button mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.createDialogData.cancelButtonLabel}}\n </button>\n</mat-dialog-actions>\n", styles: ["mat-dialog-actions{display:flex;justify-content:space-between}\n"] }]
3102
+ args: [{ selector: 'ngx-mat-entity-create-dialog', template: "<h2 mat-dialog-title>{{data.createDialogData.title}}</h2>\n\n<mat-dialog-content>\n <form #form=\"ngForm\">\n <div class=\"row\" *ngFor=\"let row of entityRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForCreate]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkIsEntityValid()\"\n >\n </ngx-mat-entity-input>\n </div>\n </form>\n</mat-dialog-content>\n\n<mat-dialog-actions>\n <button mat-raised-button (click)=\"create()\" [disabled]=\"!isEntityValid\">\n {{data.createDialogData.createButtonLabel}}\n </button>\n <button mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.createDialogData.cancelButtonLabel}}\n </button>\n</mat-dialog-actions>\n", styles: ["mat-dialog-actions{display:flex;justify-content:space-between}\n"] }]
1288
3103
  }], ctorParameters: function () { return [{ type: undefined, decorators: [{
1289
3104
  type: Inject,
1290
3105
  args: [MAT_DIALOG_DATA]
@@ -1325,7 +3140,7 @@ class EditDialogDataBuilder extends BaseBuilder {
1325
3140
  .withDefault('text', ['Do you really want to delete this entity?'])
1326
3141
  .withDefault('title', 'Delete')
1327
3142
  .getResult();
1328
- return new EditDialogDataInternal(data?.title ? data.title : () => 'Edit', data?.confirmButtonLabel ? data.confirmButtonLabel : 'Save', data?.deleteButtonLabel ? data.deleteButtonLabel : 'Delete', data?.cancelButtonLabel ? data.cancelButtonLabel : 'Cancel', data?.deleteRequiresConfirmDialog ? data.deleteRequiresConfirmDialog : true, data?.editRequiresConfirmDialog ? data.editRequiresConfirmDialog : false, confirmDeleteDialogData, confirmEditDialogData);
3143
+ return new EditDialogDataInternal(data?.title ?? (() => 'Edit'), data?.confirmButtonLabel ?? 'Save', data?.deleteButtonLabel ?? 'Delete', data?.cancelButtonLabel ?? 'Cancel', data?.deleteRequiresConfirmDialog ?? true, data?.editRequiresConfirmDialog ?? false, confirmDeleteDialogData, confirmEditDialogData);
1329
3144
  }
1330
3145
  }
1331
3146
 
@@ -1350,7 +3165,7 @@ class EditEntityDialogDataBuilder extends BaseBuilder {
1350
3165
  // eslint-disable-next-line jsdoc/require-jsdoc
1351
3166
  generateBaseData(data) {
1352
3167
  const editDialogData = new EditDialogDataBuilder(data.editDialogData).getResult();
1353
- return new EditEntityDialogDataInternal(data.entity, data.EntityServiceClass, editDialogData, data.allowDelete ? data.allowDelete : () => true);
3168
+ return new EditEntityDialogDataInternal(data.entity, data.EntityServiceClass, editDialogData, data.allowDelete ?? (() => true));
1354
3169
  }
1355
3170
  }
1356
3171
 
@@ -1367,14 +3182,20 @@ class NgxMatEntityEditDialogComponent {
1367
3182
  this.injector = injector;
1368
3183
  this.dialog = dialog;
1369
3184
  this.EntityUtilities = EntityUtilities;
1370
- this.getWidth = EntityUtilities.getWidth;
3185
+ this.isEntityValid = true;
3186
+ this.isEntityDirty = (async () => false).call(this);
1371
3187
  }
1372
3188
  ngOnInit() {
1373
3189
  this.data = new EditEntityDialogDataBuilder(this.inputData).getResult();
1374
3190
  this.dialogRef.disableClose = true;
1375
3191
  this.entityRows = EntityUtilities.getEntityRows(this.data.entity, false, true);
1376
3192
  this.entityService = this.injector.get(this.data.EntityServiceClass);
1377
- this.entityPriorChanges = cloneDeep(this.data.entity);
3193
+ this.entityPriorChanges = LodashUtilities.cloneDeep(this.data.entity);
3194
+ }
3195
+ // eslint-disable-next-line jsdoc/require-jsdoc
3196
+ checkEntity() {
3197
+ this.isEntityValid = EntityUtilities.isEntityValid(this.data.entity, 'update');
3198
+ this.isEntityDirty = EntityUtilities.dirty(this.data.entity, this.entityPriorChanges);
1378
3199
  }
1379
3200
  /**
1380
3201
  * Tries to save the changes and close the dialog afterwards.
@@ -1382,7 +3203,8 @@ class NgxMatEntityEditDialogComponent {
1382
3203
  */
1383
3204
  edit() {
1384
3205
  if (!this.data.editDialogData.editRequiresConfirmDialog) {
1385
- return this.confirmEdit();
3206
+ this.confirmEdit();
3207
+ return;
1386
3208
  }
1387
3209
  const dialogData = new ConfirmDialogDataBuilder(this.data.editDialogData.confirmEditDialogData)
1388
3210
  .withDefault('text', ['Do you really want to save all changes?'])
@@ -1401,7 +3223,7 @@ class NgxMatEntityEditDialogComponent {
1401
3223
  });
1402
3224
  }
1403
3225
  confirmEdit() {
1404
- this.entityService.update(this.data.entity, this.entityPriorChanges).then(() => this.dialogRef.close(1));
3226
+ void this.entityService.update(this.data.entity, this.entityPriorChanges).then(() => this.dialogRef.close(1));
1405
3227
  }
1406
3228
  /**
1407
3229
  * Tries to delete the entity and close the dialog afterwards.
@@ -1409,7 +3231,8 @@ class NgxMatEntityEditDialogComponent {
1409
3231
  */
1410
3232
  delete() {
1411
3233
  if (!this.data.editDialogData.deleteRequiresConfirmDialog) {
1412
- return this.confirmDelete();
3234
+ this.confirmDelete();
3235
+ return;
1413
3236
  }
1414
3237
  const dialogData = new ConfirmDialogDataBuilder(this.data.editDialogData.confirmDeleteDialogData)
1415
3238
  .withDefault('text', ['Do you really want to delete this entity?'])
@@ -1429,7 +3252,7 @@ class NgxMatEntityEditDialogComponent {
1429
3252
  });
1430
3253
  }
1431
3254
  confirmDelete() {
1432
- this.entityService.delete(this.entityPriorChanges.id).then(() => this.dialogRef.close(2));
3255
+ void this.entityService.delete(this.entityPriorChanges).then(() => this.dialogRef.close(2));
1433
3256
  }
1434
3257
  /**
1435
3258
  * Reverts all changes made and closes the dialog.
@@ -1440,10 +3263,10 @@ class NgxMatEntityEditDialogComponent {
1440
3263
  }
1441
3264
  }
1442
3265
  NgxMatEntityEditDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityEditDialogComponent, deps: [{ token: MAT_DIALOG_DATA }, { token: i1.MatDialogRef }, { token: i0.Injector }, { token: i1.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
1443
- NgxMatEntityEditDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: NgxMatEntityEditDialogComponent, selector: "ngx-mat-entity-edit-dialog", ngImport: i0, template: "<h2 mat-dialog-title>\n {{data.editDialogData.title(data.entity)}}\n <button *ngIf=\"data.allowDelete(data.entity)\" mat-raised-button (click)=\"delete()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{data.editDialogData.deleteButtonLabel}}\n </button>\n</h2>\n\n<mat-dialog-content>\n <form #form=\"ngForm\" class=\"row\">\n <div class=\"row\" *ngFor=\"let row of entityRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{getWidth(data.entity, key, 'lg')}} col-md-{{getWidth(data.entity, key, 'md')}} col-sm-{{getWidth(data.entity, key, 'sm')}}\"\n >\n </ngx-mat-entity-input>\n </div>\n </form>\n</mat-dialog-content>\n\n<mat-dialog-actions>\n <button mat-raised-button (click)=\"edit()\" [disabled]=\"!EntityUtilities.isEntityValid(data.entity, 'update') || !EntityUtilities.dirty(data.entity, entityPriorChanges)\">\n {{data.editDialogData.confirmButtonLabel}}\n </button>\n <button mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.editDialogData.cancelButtonLabel}}\n </button>\n</mat-dialog-actions>\n", styles: ["mat-dialog-actions{display:flex;justify-content:space-between}.delete-button{float:right}\n"], components: [{ type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: ["entity", "propertyKey", "getValidationErrorMessage", "hideOmitForCreate", "hideOmitForEdit"] }], directives: [{ type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { type: i13.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i13.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i13.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i11.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]" }] });
3266
+ NgxMatEntityEditDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: NgxMatEntityEditDialogComponent, selector: "ngx-mat-entity-edit-dialog", ngImport: i0, template: "<h2 mat-dialog-title>\n {{data.editDialogData.title(data.entity)}}\n <button *ngIf=\"data.allowDelete(data.entity)\" mat-raised-button (click)=\"delete()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{data.editDialogData.deleteButtonLabel}}\n </button>\n</h2>\n\n<mat-dialog-content>\n <form #form=\"ngForm\" class=\"row\">\n <div class=\"row\" *ngFor=\"let row of entityRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n >\n </ngx-mat-entity-input>\n </div>\n </form>\n</mat-dialog-content>\n\n<mat-dialog-actions>\n <button mat-raised-button (click)=\"edit()\" [disabled]=\"!isEntityValid || (isEntityDirty | async) === false\">\n {{data.editDialogData.confirmButtonLabel}}\n </button>\n <button mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.editDialogData.cancelButtonLabel}}\n </button>\n</mat-dialog-actions>\n", styles: ["mat-dialog-actions{display:flex;justify-content:space-between}.delete-button{float:right}\n"], components: [{ type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: NgxMatEntityInputComponent, selector: "ngx-mat-entity-input", inputs: ["entity", "propertyKey", "getValidationErrorMessage", "hideOmitForCreate", "hideOmitForEdit"], outputs: ["inputChangeEvent"] }], directives: [{ type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { type: i3$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i3$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i3$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]" }], pipes: { "async": i4.AsyncPipe } });
1444
3267
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityEditDialogComponent, decorators: [{
1445
3268
  type: Component,
1446
- args: [{ selector: 'ngx-mat-entity-edit-dialog', template: "<h2 mat-dialog-title>\n {{data.editDialogData.title(data.entity)}}\n <button *ngIf=\"data.allowDelete(data.entity)\" mat-raised-button (click)=\"delete()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{data.editDialogData.deleteButtonLabel}}\n </button>\n</h2>\n\n<mat-dialog-content>\n <form #form=\"ngForm\" class=\"row\">\n <div class=\"row\" *ngFor=\"let row of entityRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{getWidth(data.entity, key, 'lg')}} col-md-{{getWidth(data.entity, key, 'md')}} col-sm-{{getWidth(data.entity, key, 'sm')}}\"\n >\n </ngx-mat-entity-input>\n </div>\n </form>\n</mat-dialog-content>\n\n<mat-dialog-actions>\n <button mat-raised-button (click)=\"edit()\" [disabled]=\"!EntityUtilities.isEntityValid(data.entity, 'update') || !EntityUtilities.dirty(data.entity, entityPriorChanges)\">\n {{data.editDialogData.confirmButtonLabel}}\n </button>\n <button mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.editDialogData.cancelButtonLabel}}\n </button>\n</mat-dialog-actions>\n", styles: ["mat-dialog-actions{display:flex;justify-content:space-between}.delete-button{float:right}\n"] }]
3269
+ args: [{ selector: 'ngx-mat-entity-edit-dialog', template: "<h2 mat-dialog-title>\n {{data.editDialogData.title(data.entity)}}\n <button *ngIf=\"data.allowDelete(data.entity)\" mat-raised-button (click)=\"delete()\" color=\"warn\" class=\"delete-button\" tabindex=\"-1\">\n {{data.editDialogData.deleteButtonLabel}}\n </button>\n</h2>\n\n<mat-dialog-content>\n <form #form=\"ngForm\" class=\"row\">\n <div class=\"row\" *ngFor=\"let row of entityRows\">\n <ngx-mat-entity-input\n *ngFor=\"let key of row.keys\"\n [entity]=\"data.entity\"\n [propertyKey]=\"key\"\n [hideOmitForEdit]=\"true\"\n class=\"col-lg-{{EntityUtilities.getWidth(data.entity, key, 'lg')}} col-md-{{EntityUtilities.getWidth(data.entity, key, 'md')}} col-sm-{{EntityUtilities.getWidth(data.entity, key, 'sm')}}\"\n (inputChangeEvent)=\"checkEntity()\"\n >\n </ngx-mat-entity-input>\n </div>\n </form>\n</mat-dialog-content>\n\n<mat-dialog-actions>\n <button mat-raised-button (click)=\"edit()\" [disabled]=\"!isEntityValid || (isEntityDirty | async) === false\">\n {{data.editDialogData.confirmButtonLabel}}\n </button>\n <button mat-raised-button (click)=\"cancel()\" class=\"cancel-button\">\n {{data.editDialogData.cancelButtonLabel}}\n </button>\n</mat-dialog-actions>\n", styles: ["mat-dialog-actions{display:flex;justify-content:space-between}.delete-button{float:right}\n"] }]
1447
3270
  }], ctorParameters: function () { return [{ type: undefined, decorators: [{
1448
3271
  type: Inject,
1449
3272
  args: [MAT_DIALOG_DATA]
@@ -1468,7 +3291,7 @@ class BaseDataBuilder extends BaseBuilder {
1468
3291
  }
1469
3292
  // eslint-disable-next-line jsdoc/require-jsdoc
1470
3293
  generateBaseData(data) {
1471
- return new BaseDataInternal(data.title, data.displayColumns, data.EntityServiceClass, data.searchLabel ? data.searchLabel : 'Search', data.createButtonLabel ? data.createButtonLabel : 'Create', data.searchString ? data.searchString : defaultSearchFunction, data.allowCreate === false ? data.allowCreate : true, data.allowEdit ? data.allowEdit : () => true, data.allowDelete ? data.allowDelete : () => true, data.multiSelectActions ? data.multiSelectActions : [], data.multiSelectLabel ? data.multiSelectLabel : 'Actions', data.EntityClass, data.edit, data.create);
3294
+ return new BaseDataInternal(data.title, data.displayColumns, data.EntityServiceClass, data.searchLabel ?? 'Search', data.createButtonLabel ?? 'Create', data.searchString ?? defaultSearchFunction, data.allowCreate ?? true, data.allowEdit ?? (() => true), data.allowDelete ?? (() => true), data.multiSelectActions ?? [], data.multiSelectLabel ?? 'Actions', data.EntityClass, data.edit, data.create);
1472
3295
  }
1473
3296
  }
1474
3297
  /**
@@ -1514,7 +3337,7 @@ class TableDataBuilder extends BaseBuilder {
1514
3337
  }
1515
3338
  if ((data.baseData.allowEdit && data.baseData.allowEdit !== (() => false)
1516
3339
  || data.baseData.allowDelete && data.baseData.allowDelete !== (() => false)
1517
- || data.baseData.allowCreate)
3340
+ || data.baseData.allowCreate === true)
1518
3341
  && !data.baseData.EntityClass) {
1519
3342
  throw new Error(`
1520
3343
  Missing required Input data "EntityClass".
@@ -1582,21 +3405,19 @@ class NgxMatEntityTableComponent {
1582
3405
  return this.data.baseData.displayColumns.find((dp) => dp.displayName === header)?.value(entity);
1583
3406
  };
1584
3407
  this.dataSource.sort = this.sort;
1585
- if (this.data.baseData.searchString) {
1586
- this.dataSource.filterPredicate = (entity, filter) => {
1587
- const searchStr = this.data.baseData.searchString(entity);
1588
- const formattedSearchString = searchStr.toLowerCase();
1589
- const formattedFilterString = filter.toLowerCase();
1590
- return formattedSearchString.includes(formattedFilterString);
1591
- };
1592
- }
3408
+ this.dataSource.filterPredicate = (entity, filter) => {
3409
+ const searchStr = this.data.baseData.searchString(entity);
3410
+ const formattedSearchString = searchStr.toLowerCase();
3411
+ const formattedFilterString = filter.toLowerCase();
3412
+ return formattedSearchString.includes(formattedFilterString);
3413
+ };
1593
3414
  this.dataSource.filter = this.filter;
1594
3415
  this.dataSource.paginator = this.paginator;
1595
3416
  this.entityService.entitiesSubject.pipe(takeUntil(this.onDestroy)).subscribe((entities) => {
1596
3417
  this.dataSource.data = entities;
1597
3418
  this.selection.clear();
1598
3419
  });
1599
- this.entityService.read();
3420
+ void this.entityService.read();
1600
3421
  }
1601
3422
  /**
1602
3423
  * Edits an entity. This either calls the edit-Method provided by the user or uses a default edit-dialog.
@@ -1613,11 +3434,11 @@ class NgxMatEntityTableComponent {
1613
3434
  this.data.baseData.edit(new this.data.baseData.EntityClass(entity));
1614
3435
  }
1615
3436
  else {
1616
- this.editDefault(new this.data.baseData.EntityClass(entity));
3437
+ void this.editDefault(new this.data.baseData.EntityClass(entity));
1617
3438
  }
1618
3439
  }
1619
3440
  }
1620
- editDefault(entity) {
3441
+ async editDefault(entity) {
1621
3442
  const inputDialogData = {
1622
3443
  entity: entity,
1623
3444
  EntityServiceClass: this.data.baseData.EntityServiceClass,
@@ -1625,19 +3446,18 @@ class NgxMatEntityTableComponent {
1625
3446
  editDialogData: this.data.editDialogData
1626
3447
  };
1627
3448
  const dialogData = new EditEntityDialogDataBuilder(inputDialogData).getResult();
1628
- firstValueFrom(this.dialog.open(NgxMatEntityEditDialogComponent, {
3449
+ const res = await firstValueFrom(this.dialog.open(NgxMatEntityEditDialogComponent, {
1629
3450
  data: dialogData,
1630
3451
  minWidth: '60%',
1631
3452
  autoFocus: false,
1632
3453
  restoreFocus: false
1633
- }).afterClosed()).then((res) => {
1634
- if (res === 0) {
1635
- const data = this.dataSource.data;
1636
- data[this.dataSource.data.findIndex((e) => e.id === entity.id)] = entity;
1637
- this.dataSource.data = data;
1638
- this.selection.clear();
1639
- }
1640
- });
3454
+ }).afterClosed());
3455
+ if (res === 0) {
3456
+ const data = this.dataSource.data;
3457
+ data[this.dataSource.data.findIndex((e) => e[this.entityService.idKey] === entity[this.entityService.idKey])] = entity;
3458
+ this.dataSource.data = data;
3459
+ this.selection.clear();
3460
+ }
1641
3461
  }
1642
3462
  /**
1643
3463
  * Creates a new Entity. This either calls the create-Method provided by the user or uses a default create-dialog.
@@ -1678,7 +3498,8 @@ class NgxMatEntityTableComponent {
1678
3498
  */
1679
3499
  runMultiAction(action) {
1680
3500
  if (!action.requireConfirmDialog || !action.requireConfirmDialog(this.selection.selected)) {
1681
- return this.confirmRunMultiAction(action);
3501
+ this.confirmRunMultiAction(action);
3502
+ return;
1682
3503
  }
1683
3504
  const dialogData = new ConfirmDialogDataBuilder(action.confirmDialogData)
1684
3505
  .withDefault('text', [`Do you really want to run this action on ${this.selection.selected.length} entries?`])
@@ -1721,7 +3542,7 @@ class NgxMatEntityTableComponent {
1721
3542
  this.selection.clear();
1722
3543
  }
1723
3544
  else {
1724
- this.dataSource.data.forEach((row) => this.selection.select(row));
3545
+ this.dataSource.data.forEach(row => this.selection.select(row));
1725
3546
  }
1726
3547
  }
1727
3548
  /**
@@ -1750,7 +3571,7 @@ class NgxMatEntityTableComponent {
1750
3571
  }
1751
3572
  }
1752
3573
  NgxMatEntityTableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityTableComponent, deps: [{ token: i1.MatDialog }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component });
1753
- NgxMatEntityTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: NgxMatEntityTableComponent, selector: "ngx-mat-entity-table", inputs: { tableData: "tableData" }, viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, static: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true, static: true }, { propertyName: "filter", first: true, predicate: ["filter"], descendants: true, static: true }], ngImport: i0, template: "<h1 class=\"title\">{{data.baseData.title}}</h1>\n\n<div class=\"row\">\n <mat-form-field class=\"col-lg-8 col-md-6 col-sm-12\">\n <mat-label>{{data.baseData.searchLabel}}</mat-label>\n <input matInput (keyup)=\"applyFilter($event)\" />\n </mat-form-field>\n <div\n *ngIf=\"data.baseData.multiSelectActions.length\"\n [class.col-lg-2]=\"data.baseData.allowCreate\"\n [class.col-lg-4]=\"!data.baseData.allowCreate\"\n [class.col-md-3]=\"data.baseData.allowCreate\"\n [class.col-md-6]=\"!data.baseData.allowCreate\"\n [class.col-sm-6]=\"data.baseData.allowCreate\"\n [class.col-sm-12]=\"!data.baseData.allowCreate\"\n >\n <button class=\"actions-button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{data.baseData.multiSelectLabel}}\n </button>\n </div>\n <mat-menu #menu=\"matMenu\">\n <button *ngFor=\"let action of data.baseData.multiSelectActions\" [disabled]=\"multiActionDisabled(action)\" (click)=\"runMultiAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n\n <div\n *ngIf=\"data.baseData.allowCreate\"\n [class.col-lg-2]=\"data.baseData.multiSelectActions.length\"\n [class.col-lg-4]=\"!data.baseData.multiSelectActions.length\"\n [class.col-md-3]=\"data.baseData.multiSelectActions.length\"\n [class.col-md-6]=\"!data.baseData.multiSelectActions.length\"\n [class.col-sm-6]=\"data.baseData.multiSelectActions.length\"\n [class.col-sm-12]=\"!data.baseData.multiSelectActions.length\"\n >\n <button class=\"create-button\" (click)=\"createEntity()\" mat-raised-button>\n {{data.baseData.createButtonLabel}}\n </button>\n </div>\n</div>\n\n<div class=\"mat-elevation-z8\">\n <mat-table *ngIf=\"dataSource\" [dataSource]=\"dataSource\" matSort>\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\" [indeterminate]=\"selection.hasValue() && !isAllSelected()\"> </mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let module\" class=\"module\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(module) : null\" [checked]=\"selection.isSelected(module)\"> </mat-checkbox>\n </mat-cell>\n </ng-container>\n\n <ng-container *ngFor=\"let dCol of data.baseData.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef mat-sort-header>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell class=\"entity\" [class.enabled]=\"data.baseData.allowEdit(entity)\" (click)=\"editEntity(entity)\" *matCellDef=\"let entity\">\n {{dCol.value(entity)}}\n </mat-cell>\n </ng-container>\n\n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns\"></mat-row>\n </mat-table>\n\n <mat-paginator *ngIf=\"dataSource\" id=\"paginator\" [length]=\"dataSource.filteredData.length\" [pageIndex]=\"0\" [pageSize]=\"10\" [pageSizeOptions]=\"[5, 10, 25, 50]\"> </mat-paginator>\n</div>\n", styles: [".title{text-align:center}button{width:100%}.mat-column-select{flex:0 0 75px}.enabled:hover{cursor:pointer}@media (max-width: 767px){.actions-button,.create-button{margin-bottom:15px}}\n"], components: [{ type: i2.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i4$1.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { type: i4$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }, { type: i9.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { type: i6.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i9.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { type: i9.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { type: i7$1.MatPaginator, selector: "mat-paginator", inputs: ["disabled"], exportAs: ["matPaginator"] }], directives: [{ type: i2.MatLabel, selector: "mat-label" }, { type: i12.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }, { type: i11.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i9.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { type: i9.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { type: i9.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { type: i9.MatCellDef, selector: "[matCellDef]" }, { type: i9.MatCell, selector: "mat-cell, td[mat-cell]" }, { type: i9.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { type: i9.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }] });
3574
+ NgxMatEntityTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: NgxMatEntityTableComponent, selector: "ngx-mat-entity-table", inputs: { tableData: "tableData" }, viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, static: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true, static: true }, { propertyName: "filter", first: true, predicate: ["filter"], descendants: true, static: true }], ngImport: i0, template: "<h1 class=\"title\">{{data.baseData.title}}</h1>\n\n<div class=\"row\">\n <mat-form-field class=\"col-lg-8 col-md-6 col-sm-12\">\n <mat-label>{{data.baseData.searchLabel}}</mat-label>\n <input matInput (keyup)=\"applyFilter($event)\" />\n </mat-form-field>\n <div\n *ngIf=\"data.baseData.multiSelectActions.length\"\n [class.col-lg-2]=\"data.baseData.allowCreate\"\n [class.col-lg-4]=\"!data.baseData.allowCreate\"\n [class.col-md-3]=\"data.baseData.allowCreate\"\n [class.col-md-6]=\"!data.baseData.allowCreate\"\n [class.col-sm-6]=\"data.baseData.allowCreate\"\n [class.col-sm-12]=\"!data.baseData.allowCreate\"\n >\n <button class=\"actions-button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{data.baseData.multiSelectLabel}}\n </button>\n </div>\n <mat-menu #menu=\"matMenu\">\n <button *ngFor=\"let action of data.baseData.multiSelectActions\" [disabled]=\"multiActionDisabled(action)\" (click)=\"runMultiAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n\n <div\n *ngIf=\"data.baseData.allowCreate\"\n [class.col-lg-2]=\"data.baseData.multiSelectActions.length\"\n [class.col-lg-4]=\"!data.baseData.multiSelectActions.length\"\n [class.col-md-3]=\"data.baseData.multiSelectActions.length\"\n [class.col-md-6]=\"!data.baseData.multiSelectActions.length\"\n [class.col-sm-6]=\"data.baseData.multiSelectActions.length\"\n [class.col-sm-12]=\"!data.baseData.multiSelectActions.length\"\n >\n <button class=\"create-button\" (click)=\"createEntity()\" mat-raised-button>\n {{data.baseData.createButtonLabel}}\n </button>\n </div>\n</div>\n\n<div class=\"mat-elevation-z8\">\n <mat-table *ngIf=\"dataSource\" [dataSource]=\"dataSource\" matSort>\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\" [indeterminate]=\"selection.hasValue() && !isAllSelected()\"> </mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let module\" class=\"module\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(module) : null\" [checked]=\"selection.isSelected(module)\"> </mat-checkbox>\n </mat-cell>\n </ng-container>\n\n <ng-container *ngFor=\"let dCol of data.baseData.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef mat-sort-header>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell class=\"entity\" [class.enabled]=\"data.baseData.allowEdit(entity)\" (click)=\"editEntity(entity)\" *matCellDef=\"let entity\">\n {{dCol.value(entity)}}\n </mat-cell>\n </ng-container>\n\n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns\"></mat-row>\n </mat-table>\n\n <mat-paginator *ngIf=\"dataSource\" id=\"paginator\" [length]=\"dataSource.filteredData.length\" [pageIndex]=\"0\" [pageSize]=\"10\" [pageSizeOptions]=\"[5, 10, 25, 50]\"> </mat-paginator>\n</div>\n", styles: [".title{text-align:center}button{width:100%}.mat-column-select{flex:0 0 75px}.enabled:hover{cursor:pointer}@media (max-width: 767px){.actions-button,.create-button{margin-bottom:15px}}\n"], components: [{ type: i1$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i3.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i4$3.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { type: i4$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }, { type: i4$2.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { type: i2.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i4$2.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { type: i4$2.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { type: i7.MatPaginator, selector: "mat-paginator", inputs: ["disabled"], exportAs: ["matPaginator"] }], directives: [{ type: i1$1.MatLabel, selector: "mat-label" }, { type: i4$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }, { type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i4$2.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { type: i4$2.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { type: i4$2.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { type: i4$2.MatCellDef, selector: "[matCellDef]" }, { type: i4$2.MatCell, selector: "mat-cell, td[mat-cell]" }, { type: i4$2.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { type: i4$2.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }] });
1754
3575
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgxMatEntityTableComponent, decorators: [{
1755
3576
  type: Component,
1756
3577
  args: [{ selector: 'ngx-mat-entity-table', template: "<h1 class=\"title\">{{data.baseData.title}}</h1>\n\n<div class=\"row\">\n <mat-form-field class=\"col-lg-8 col-md-6 col-sm-12\">\n <mat-label>{{data.baseData.searchLabel}}</mat-label>\n <input matInput (keyup)=\"applyFilter($event)\" />\n </mat-form-field>\n <div\n *ngIf=\"data.baseData.multiSelectActions.length\"\n [class.col-lg-2]=\"data.baseData.allowCreate\"\n [class.col-lg-4]=\"!data.baseData.allowCreate\"\n [class.col-md-3]=\"data.baseData.allowCreate\"\n [class.col-md-6]=\"!data.baseData.allowCreate\"\n [class.col-sm-6]=\"data.baseData.allowCreate\"\n [class.col-sm-12]=\"!data.baseData.allowCreate\"\n >\n <button class=\"actions-button\" [matMenuTriggerFor]=\"menu\" mat-raised-button>\n {{data.baseData.multiSelectLabel}}\n </button>\n </div>\n <mat-menu #menu=\"matMenu\">\n <button *ngFor=\"let action of data.baseData.multiSelectActions\" [disabled]=\"multiActionDisabled(action)\" (click)=\"runMultiAction(action)\" mat-menu-item>\n {{action.displayName}}\n </button>\n </mat-menu>\n\n <div\n *ngIf=\"data.baseData.allowCreate\"\n [class.col-lg-2]=\"data.baseData.multiSelectActions.length\"\n [class.col-lg-4]=\"!data.baseData.multiSelectActions.length\"\n [class.col-md-3]=\"data.baseData.multiSelectActions.length\"\n [class.col-md-6]=\"!data.baseData.multiSelectActions.length\"\n [class.col-sm-6]=\"data.baseData.multiSelectActions.length\"\n [class.col-sm-12]=\"!data.baseData.multiSelectActions.length\"\n >\n <button class=\"create-button\" (click)=\"createEntity()\" mat-raised-button>\n {{data.baseData.createButtonLabel}}\n </button>\n </div>\n</div>\n\n<div class=\"mat-elevation-z8\">\n <mat-table *ngIf=\"dataSource\" [dataSource]=\"dataSource\" matSort>\n <!-- select Column -->\n <ng-container matColumnDef=\"select\">\n <mat-header-cell *matHeaderCellDef>\n <mat-checkbox (change)=\"$event ? masterToggle() : null\" [checked]=\"selection.hasValue() && isAllSelected()\" [indeterminate]=\"selection.hasValue() && !isAllSelected()\"> </mat-checkbox>\n </mat-header-cell>\n <mat-cell *matCellDef=\"let module\" class=\"module\">\n <mat-checkbox (click)=\"$event.stopPropagation()\" (change)=\"$event ? selection.toggle(module) : null\" [checked]=\"selection.isSelected(module)\"> </mat-checkbox>\n </mat-cell>\n </ng-container>\n\n <ng-container *ngFor=\"let dCol of data.baseData.displayColumns\" [matColumnDef]=\"dCol.displayName\">\n <mat-header-cell *matHeaderCellDef mat-sort-header>\n {{dCol.displayName}}\n </mat-header-cell>\n <mat-cell class=\"entity\" [class.enabled]=\"data.baseData.allowEdit(entity)\" (click)=\"editEntity(entity)\" *matCellDef=\"let entity\">\n {{dCol.value(entity)}}\n </mat-cell>\n </ng-container>\n\n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns\"></mat-row>\n </mat-table>\n\n <mat-paginator *ngIf=\"dataSource\" id=\"paginator\" [length]=\"dataSource.filteredData.length\" [pageIndex]=\"0\" [pageSize]=\"10\" [pageSizeOptions]=\"[5, 10, 25, 50]\"> </mat-paginator>\n</div>\n", styles: [".title{text-align:center}button{width:100%}.mat-column-select{flex:0 0 75px}.enabled:hover{cursor:pointer}@media (max-width: 767px){.actions-button,.create-button{margin-bottom:15px}}\n"] }]
@@ -1887,16 +3708,83 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImpo
1887
3708
  class EntityArrayDecoratorConfigInternal extends PropertyDecoratorConfigInternal {
1888
3709
  constructor(data) {
1889
3710
  super(data);
1890
- this.createInline = data.createInline != undefined ? data.createInline : true;
1891
- this.displayStyle = data.displayStyle;
3711
+ this.createInline = data.createInline ?? true;
1892
3712
  this.itemType = data.itemType;
3713
+ this.allowDuplicates = data.allowDuplicates ?? false;
3714
+ this.duplicatesErrorDialog = getDefaultDuplicateErrorDialogData(data);
1893
3715
  this.EntityClass = data.EntityClass;
1894
3716
  this.displayColumns = data.displayColumns;
1895
- this.createInline = data.createInline != undefined ? data.createInline : true;
1896
- this.missingErrorMessage = data.missingErrorMessage ? data.missingErrorMessage : 'Needs to contain at least one value';
1897
- this.defaultWidths = data.defaultWidths ? data.defaultWidths : [12, 12, 12];
1898
- this.addButtonLabel = data.addButtonLabel ? data.addButtonLabel : 'Add';
1899
- this.removeButtonLabel = data.removeButtonLabel ? data.removeButtonLabel : 'Remove';
3717
+ this.createInline = data.createInline ?? true;
3718
+ this.missingErrorMessage = data.missingErrorMessage ?? 'Needs to contain at least one value';
3719
+ this.defaultWidths = data.defaultWidths ?? [12, 12, 12];
3720
+ this.addButtonLabel = data.addButtonLabel ?? 'Add';
3721
+ this.removeButtonLabel = data.removeButtonLabel ?? 'Remove';
3722
+ }
3723
+ }
3724
+ /**
3725
+ * The internal DateArrayDecoratorConfig. Sets default values.
3726
+ */
3727
+ class DateArrayDecoratorConfigInternal extends PropertyDecoratorConfigInternal {
3728
+ constructor(data) {
3729
+ super(data);
3730
+ this.itemType = data.itemType;
3731
+ this.allowDuplicates = data.allowDuplicates ?? false;
3732
+ this.duplicatesErrorDialog = getDefaultDuplicateErrorDialogData(data);
3733
+ this.displayColumns = data.displayColumns;
3734
+ this.defaultWidths = data.defaultWidths ?? [12, 12, 12];
3735
+ this.addButtonLabel = data.addButtonLabel ?? 'Add';
3736
+ this.removeButtonLabel = data.removeButtonLabel ?? 'Remove';
3737
+ this.missingErrorMessage = data.missingErrorMessage ?? 'Needs to contain at least one value';
3738
+ this.min = data.min;
3739
+ this.max = data.max;
3740
+ this.filter = data.filter;
3741
+ }
3742
+ }
3743
+ /**
3744
+ * The internal DateTimeArrayDecoratorConfig. Sets default values.
3745
+ */
3746
+ class DateTimeArrayDecoratorConfigInternal extends PropertyDecoratorConfigInternal {
3747
+ constructor(data) {
3748
+ super(data);
3749
+ this.itemType = data.itemType;
3750
+ this.allowDuplicates = data.allowDuplicates ?? false;
3751
+ this.duplicatesErrorDialog = getDefaultDuplicateErrorDialogData(data);
3752
+ this.displayColumns = data.displayColumns;
3753
+ this.defaultWidths = data.defaultWidths ?? [12, 12, 12];
3754
+ this.addButtonLabel = data.addButtonLabel ?? 'Add';
3755
+ this.removeButtonLabel = data.removeButtonLabel ?? 'Remove';
3756
+ this.missingErrorMessage = data.missingErrorMessage ?? 'Needs to contain at least one value';
3757
+ this.times = data.times ?? DateUtilities.getDefaultTimes();
3758
+ this.timeDisplayName = data.timeDisplayName ?? 'Time';
3759
+ this.minDate = data.minDate;
3760
+ this.maxDate = data.maxDate;
3761
+ this.filterDate = data.filterDate;
3762
+ this.minTime = data.minTime;
3763
+ this.maxTime = data.maxTime;
3764
+ this.filterTime = data.filterTime;
3765
+ }
3766
+ }
3767
+ /**
3768
+ * The internal DateRangeArrayDecoratorConfig. Sets default values.
3769
+ */
3770
+ class DateRangeArrayDecoratorConfigInternal extends PropertyDecoratorConfigInternal {
3771
+ constructor(data) {
3772
+ super(data);
3773
+ this.itemType = data.itemType;
3774
+ this.allowDuplicates = data.allowDuplicates ?? false;
3775
+ this.duplicatesErrorDialog = getDefaultDuplicateErrorDialogData(data);
3776
+ this.displayColumns = data.displayColumns;
3777
+ this.defaultWidths = data.defaultWidths ?? [12, 12, 12];
3778
+ this.addButtonLabel = data.addButtonLabel ?? 'Add';
3779
+ this.removeButtonLabel = data.removeButtonLabel ?? 'Remove';
3780
+ this.missingErrorMessage = data.missingErrorMessage ?? 'Needs to contain at least one value';
3781
+ this.placeholderStart = data.placeholderStart ?? 'Start';
3782
+ this.placeholderEnd = data.placeholderEnd ?? 'End';
3783
+ this.minStart = data.minStart;
3784
+ this.maxStart = data.maxStart;
3785
+ this.minEnd = data.minEnd;
3786
+ this.maxEnd = data.maxEnd;
3787
+ this.filter = data.filter;
1900
3788
  }
1901
3789
  }
1902
3790
  /**
@@ -1905,13 +3793,14 @@ class EntityArrayDecoratorConfigInternal extends PropertyDecoratorConfigInternal
1905
3793
  class StringChipsArrayDecoratorConfigInternal extends PropertyDecoratorConfigInternal {
1906
3794
  constructor(data) {
1907
3795
  super(data);
1908
- this.deleteIcon = data.deleteIcon ? data.deleteIcon : 'fas fa-circle-minus';
1909
- this.displayStyle = data.displayStyle;
3796
+ this.deleteIcon = data.deleteIcon ?? 'fas fa-circle-minus';
1910
3797
  this.itemType = data.itemType;
3798
+ this.allowDuplicates = data.allowDuplicates ?? false;
3799
+ this.duplicatesErrorDialog = getDefaultDuplicateErrorDialogData(data);
1911
3800
  this.maxLength = data.maxLength;
1912
3801
  this.minLength = data.minLength;
1913
3802
  this.regex = data.regex;
1914
- this.defaultWidths = data.defaultWidths ? data.defaultWidths : [6, 12, 12];
3803
+ this.defaultWidths = data.defaultWidths ?? [6, 12, 12];
1915
3804
  }
1916
3805
  }
1917
3806
  /**
@@ -1921,15 +3810,34 @@ class AutocompleteStringChipsArrayDecoratorConfigInternal extends PropertyDecora
1921
3810
  constructor(data) {
1922
3811
  super(data);
1923
3812
  this.autocompleteValues = data.autocompleteValues;
1924
- this.deleteIcon = data.deleteIcon ? data.deleteIcon : 'fas fa-circle-minus';
1925
- this.displayStyle = data.displayStyle;
3813
+ this.deleteIcon = data.deleteIcon ?? 'fas fa-circle-minus';
1926
3814
  this.itemType = data.itemType;
3815
+ this.allowDuplicates = data.allowDuplicates ?? false;
3816
+ this.duplicatesErrorDialog = getDefaultDuplicateErrorDialogData(data);
1927
3817
  this.maxLength = data.maxLength;
1928
3818
  this.minLength = data.minLength;
1929
3819
  this.regex = data.regex;
1930
- this.defaultWidths = data.defaultWidths ? data.defaultWidths : [6, 12, 12];
3820
+ this.defaultWidths = data.defaultWidths ?? [6, 12, 12];
1931
3821
  }
1932
3822
  }
3823
+ /**
3824
+ * Gets the default dialog data for the error dialog to display when the user tries to add a duplicate value.
3825
+ *
3826
+ * @param data - The Array Decorator data.
3827
+ * @returns The dialog data with set default values.
3828
+ */
3829
+ function getDefaultDuplicateErrorDialogData(data) {
3830
+ return {
3831
+ type: data.duplicatesErrorDialog?.type ?? 'info-only',
3832
+ // eslint-disable-next-line max-len
3833
+ text: data.duplicatesErrorDialog?.text ?? ['Adding duplicate entries to the array is not allowed.'],
3834
+ title: data.duplicatesErrorDialog?.title ?? 'Error adding duplicate item',
3835
+ confirmButtonLabel: data.duplicatesErrorDialog?.confirmButtonLabel,
3836
+ cancelButtonLabel: data.duplicatesErrorDialog?.cancelButtonLabel,
3837
+ requireConfirmation: data.duplicatesErrorDialog?.requireConfirmation,
3838
+ confirmationText: data.duplicatesErrorDialog?.confirmationText
3839
+ };
3840
+ }
1933
3841
 
1934
3842
  /**
1935
3843
  * Decorator for setting and getting array property metadata.
@@ -1942,6 +3850,12 @@ function array(metadata) {
1942
3850
  switch (metadata.itemType) {
1943
3851
  case DecoratorTypes.OBJECT:
1944
3852
  return baseProperty(new EntityArrayDecoratorConfigInternal(metadata), DecoratorTypes.ARRAY);
3853
+ case DecoratorTypes.DATE:
3854
+ return baseProperty(new DateArrayDecoratorConfigInternal(metadata), DecoratorTypes.ARRAY_DATE);
3855
+ case DecoratorTypes.DATE_TIME:
3856
+ return baseProperty(new DateTimeArrayDecoratorConfigInternal(metadata), DecoratorTypes.ARRAY_DATE_TIME);
3857
+ case DecoratorTypes.DATE_RANGE:
3858
+ return baseProperty(new DateRangeArrayDecoratorConfigInternal(metadata), DecoratorTypes.ARRAY_DATE_RANGE);
1945
3859
  case DecoratorTypes.STRING:
1946
3860
  return baseProperty(new StringChipsArrayDecoratorConfigInternal(metadata), DecoratorTypes.ARRAY_STRING_CHIPS);
1947
3861
  case DecoratorTypes.STRING_AUTOCOMPLETE:
@@ -1982,7 +3896,7 @@ class CheckboxBooleanDecoratorConfigInternal extends PropertyDecoratorConfigInte
1982
3896
  constructor(data) {
1983
3897
  super(data);
1984
3898
  this.displayStyle = data.displayStyle;
1985
- this.required = data.required === undefined ? false : data.required;
3899
+ this.required = data.required ?? false;
1986
3900
  }
1987
3901
  }
1988
3902
  /**
@@ -1992,7 +3906,7 @@ class ToggleBooleanDecoratorConfigInternal extends PropertyDecoratorConfigIntern
1992
3906
  constructor(data) {
1993
3907
  super(data);
1994
3908
  this.displayStyle = data.displayStyle;
1995
- this.required = data.required === undefined ? false : data.required;
3909
+ this.required = data.required ?? false;
1996
3910
  }
1997
3911
  }
1998
3912
 
@@ -2020,6 +3934,76 @@ function boolean(metadata) {
2020
3934
  class BooleanDecoratorConfig extends PropertyDecoratorConfig {
2021
3935
  }
2022
3936
 
3937
+ /**
3938
+ * The internal DefaultDateDecoratorConfig. Sets default values.
3939
+ */
3940
+ class DefaultDateDecoratorConfigInternal extends PropertyDecoratorConfigInternal {
3941
+ constructor(data) {
3942
+ super(data);
3943
+ this.displayStyle = data.displayStyle;
3944
+ this.max = data.max;
3945
+ this.min = data.min;
3946
+ this.filter = data.filter;
3947
+ }
3948
+ }
3949
+ /**
3950
+ * The internal DateRangeDateDecoratorConfig. Sets default values.
3951
+ */
3952
+ class DateRangeDateDecoratorConfigInternal extends PropertyDecoratorConfigInternal {
3953
+ constructor(data) {
3954
+ super(data);
3955
+ this.displayStyle = data.displayStyle;
3956
+ this.minStart = data.minStart;
3957
+ this.maxStart = data.maxStart;
3958
+ this.minEnd = data.minEnd;
3959
+ this.maxEnd = data.maxEnd;
3960
+ this.filter = data.filter;
3961
+ this.placeholderStart = data.placeholderStart ?? 'Start';
3962
+ this.placeholderEnd = data.placeholderEnd ?? 'End';
3963
+ }
3964
+ }
3965
+ /**
3966
+ * The internal DateTimeDateDecoratorConfig. Sets default values.
3967
+ */
3968
+ class DateTimeDateDecoratorConfigInternal extends PropertyDecoratorConfigInternal {
3969
+ constructor(data) {
3970
+ super(data);
3971
+ this.displayStyle = data.displayStyle;
3972
+ this.times = data.times ?? DateUtilities.getDefaultTimes();
3973
+ this.timeDisplayName = data.timeDisplayName ?? 'Time';
3974
+ this.minDate = data.minDate;
3975
+ this.maxDate = data.maxDate;
3976
+ this.filterDate = data.filterDate;
3977
+ this.minTime = data.minTime;
3978
+ this.maxTime = data.maxTime;
3979
+ this.filterTime = data.filterTime;
3980
+ }
3981
+ }
3982
+
3983
+ /**
3984
+ * Decorator for setting and getting date property metadata.
3985
+ *
3986
+ * @param metadata - The metadata of the date property.
3987
+ * @returns The method that defines the metadata.
3988
+ */
3989
+ function date(metadata) {
3990
+ if (metadata.displayStyle === 'date') {
3991
+ return baseProperty(new DefaultDateDecoratorConfigInternal(metadata), DecoratorTypes.DATE);
3992
+ }
3993
+ else if (metadata.displayStyle === 'datetime') {
3994
+ return baseProperty(new DateTimeDateDecoratorConfigInternal(metadata), DecoratorTypes.DATE_TIME);
3995
+ }
3996
+ else {
3997
+ return baseProperty(new DateRangeDateDecoratorConfigInternal(metadata), DecoratorTypes.DATE_RANGE);
3998
+ }
3999
+ }
4000
+
4001
+ /**
4002
+ * Definition for the @date metadata.
4003
+ */
4004
+ class DateDecoratorConfig extends PropertyDecoratorConfig {
4005
+ }
4006
+
2023
4007
  /**
2024
4008
  * The internal DefaultNumberDecoratorConfig. Sets default values.
2025
4009
  */
@@ -2043,9 +4027,9 @@ class DropdownNumberDecoratorConfigInternal extends PropertyDecoratorConfigInter
2043
4027
  }
2044
4028
 
2045
4029
  /**
2046
- * Decorator for setting and getting string property metadata.
4030
+ * Decorator for setting and getting number property metadata.
2047
4031
  *
2048
- * @param metadata - The metadata of the string property.
4032
+ * @param metadata - The metadata of the number property.
2049
4033
  * @returns The method that defines the metadata.
2050
4034
  */
2051
4035
  function number(metadata) {
@@ -2070,7 +4054,7 @@ class DefaultObjectDecoratorConfigInternal extends PropertyDecoratorConfigIntern
2070
4054
  constructor(data) {
2071
4055
  super(data);
2072
4056
  this.displayStyle = data.displayStyle;
2073
- this.type = data.type;
4057
+ this.EntityClass = data.EntityClass;
2074
4058
  }
2075
4059
  }
2076
4060
 
@@ -2096,6 +4080,162 @@ class ObjectDecoratorConfig extends PropertyDecoratorConfig {
2096
4080
  class StringDecoratorConfig extends PropertyDecoratorConfig {
2097
4081
  }
2098
4082
 
4083
+ /**
4084
+ * The internal DefaultFileDecoratorConfig. Sets default values.
4085
+ */
4086
+ class DefaultFileDecoratorConfigInternal extends PropertyDecoratorConfigInternal {
4087
+ constructor(data) {
4088
+ super(data);
4089
+ this.type = data.type;
4090
+ this.preview = false;
4091
+ this.multiple = data.multiple;
4092
+ this.deleteIcon = data.deleteIcon ?? 'fas fa-circle-minus';
4093
+ this.allowedMimeTypes = data.allowedMimeTypes ?? ['*'];
4094
+ this.maxSize = data.maxSize ?? 10;
4095
+ this.maxSizeTotal = data.maxSizeTotal ?? 100;
4096
+ this.mimeTypeErrorDialog = data.mimeTypeErrorDialog ?? getDefaultMimeTypeErrorDialogData(data);
4097
+ this.maxSizeErrorDialog = data.maxSizeErrorDialog ?? getDefaultMaxSizeErrorDialogData(data);
4098
+ this.maxSizeTotalErrorDialog = data.maxSizeTotalErrorDialog ?? getDefaultMaxSizeTotalErrorDialogData(data);
4099
+ this.dragAndDrop = data.dragAndDrop ?? data.multiple;
4100
+ }
4101
+ }
4102
+ /**
4103
+ * The internal ImageFileDecoratorConfig. Sets default values.
4104
+ */
4105
+ class ImageFileDecoratorConfigInternal extends PropertyDecoratorConfigInternal {
4106
+ constructor(data) {
4107
+ super(data);
4108
+ this.type = data.type;
4109
+ this.allowedMimeTypes = data.allowedMimeTypes ?? ['image/*'];
4110
+ this.multiple = data.multiple;
4111
+ this.preview = data.preview ?? true;
4112
+ this.deleteIcon = data.deleteIcon ?? 'fas fa-circle-minus';
4113
+ this.maxSize = data.maxSize ?? 10;
4114
+ this.maxSizeTotal = data.maxSizeTotal ?? 100;
4115
+ this.mimeTypeErrorDialog = data.mimeTypeErrorDialog ?? getDefaultMimeTypeErrorDialogData(data);
4116
+ this.maxSizeErrorDialog = data.maxSizeErrorDialog ?? getDefaultMaxSizeErrorDialogData(data);
4117
+ this.maxSizeTotalErrorDialog = data.maxSizeTotalErrorDialog ?? getDefaultMaxSizeTotalErrorDialogData(data);
4118
+ this.previewPlaceholderUrl = data.previewPlaceholderUrl;
4119
+ this.dragAndDrop = data.dragAndDrop ?? data.multiple;
4120
+ }
4121
+ }
4122
+ /**
4123
+ * Gets the default dialog data for the error dialog to display
4124
+ * when the user tries to add a file with a wrong type.
4125
+ *
4126
+ * @param data - The File Decorator data.
4127
+ * @returns The dialog data with set default values.
4128
+ */
4129
+ function getDefaultMimeTypeErrorDialogData(data) {
4130
+ return {
4131
+ type: data.mimeTypeErrorDialog?.type ?? 'info-only',
4132
+ // eslint-disable-next-line max-len
4133
+ text: data.mimeTypeErrorDialog?.text ?? (data.multiple ? ['One of the uploaded files has the wrong type.'] : ['The uploaded file has the wrong type.']),
4134
+ title: data.mimeTypeErrorDialog?.title ?? (data.multiple ? 'Error adding files' : 'Error adding file'),
4135
+ confirmButtonLabel: data.mimeTypeErrorDialog?.confirmButtonLabel,
4136
+ cancelButtonLabel: data.mimeTypeErrorDialog?.cancelButtonLabel,
4137
+ requireConfirmation: data.mimeTypeErrorDialog?.requireConfirmation,
4138
+ confirmationText: data.mimeTypeErrorDialog?.confirmationText
4139
+ };
4140
+ }
4141
+ /**
4142
+ * Gets the default dialog data for the error dialog to display
4143
+ * when the user tries to add a single file that is bigger than the allowed maxSize.
4144
+ *
4145
+ * @param data - The File Decorator data.
4146
+ * @returns The dialog data with set default values.
4147
+ */
4148
+ function getDefaultMaxSizeErrorDialogData(data) {
4149
+ return {
4150
+ type: data.mimeTypeErrorDialog?.type ?? 'info-only',
4151
+ // eslint-disable-next-line max-len
4152
+ text: data.mimeTypeErrorDialog?.text ?? (data.multiple ? ['One of the uploaded files is too big'] : ['The uploaded files is too big']),
4153
+ title: data.mimeTypeErrorDialog?.title ?? (data.multiple ? 'Error adding files' : 'Error adding file'),
4154
+ confirmButtonLabel: data.mimeTypeErrorDialog?.confirmButtonLabel,
4155
+ cancelButtonLabel: data.mimeTypeErrorDialog?.cancelButtonLabel,
4156
+ requireConfirmation: data.mimeTypeErrorDialog?.requireConfirmation,
4157
+ confirmationText: data.mimeTypeErrorDialog?.confirmationText
4158
+ };
4159
+ }
4160
+ /**
4161
+ * Gets the default dialog data for the error dialog to display
4162
+ * when the user tries to add a single file that is bigger than the allowed maxSize.
4163
+ *
4164
+ * @param data - The File Decorator data.
4165
+ * @returns The dialog data with set default values.
4166
+ */
4167
+ function getDefaultMaxSizeTotalErrorDialogData(data) {
4168
+ return {
4169
+ type: data.mimeTypeErrorDialog?.type ?? 'info-only',
4170
+ // eslint-disable-next-line max-len
4171
+ text: data.mimeTypeErrorDialog?.text ?? ['The size of all files combined is too big'],
4172
+ title: data.mimeTypeErrorDialog?.title ?? (data.multiple ? 'Error adding files' : 'Error adding file'),
4173
+ confirmButtonLabel: data.mimeTypeErrorDialog?.confirmButtonLabel,
4174
+ cancelButtonLabel: data.mimeTypeErrorDialog?.cancelButtonLabel,
4175
+ requireConfirmation: data.mimeTypeErrorDialog?.requireConfirmation,
4176
+ confirmationText: data.mimeTypeErrorDialog?.confirmationText
4177
+ };
4178
+ }
4179
+
4180
+ /**
4181
+ * Decorator for setting and getting file property metadata.
4182
+ *
4183
+ * @param metadata - The metadata of the file property.
4184
+ * @returns The method that defines the metadata.
4185
+ * @throws When an unknown metadata type was provided.
4186
+ */
4187
+ function file(metadata) {
4188
+ switch (metadata.type) {
4189
+ case 'other':
4190
+ return baseProperty(new DefaultFileDecoratorConfigInternal(metadata), DecoratorTypes.FILE_DEFAULT);
4191
+ case 'image':
4192
+ return baseProperty(new ImageFileDecoratorConfigInternal(metadata), DecoratorTypes.FILE_IMAGE);
4193
+ default:
4194
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
4195
+ throw new Error(`Unknown metadata type ${metadata.type}`);
4196
+ }
4197
+ }
4198
+
4199
+ /**
4200
+ * Definition for the @file metadata.
4201
+ */
4202
+ class FileDecoratorConfig extends PropertyDecoratorConfig {
4203
+ }
4204
+
4205
+ /**
4206
+ * The default function to use for checking if the value is dirty.
4207
+ *
4208
+ * @param value - The current value.
4209
+ * @param valuePriorChanges - The value before any changes.
4210
+ * @returns Whether or not the provided value has been changed.
4211
+ */
4212
+ function defaultIsEqual(value, valuePriorChanges) {
4213
+ return LodashUtilities.isEqual(value, valuePriorChanges);
4214
+ }
4215
+ /**
4216
+ * The internal config for the @custom decorator.
4217
+ * Sets default values.
4218
+ */
4219
+ class CustomDecoratorConfigInternal extends PropertyDecoratorConfigInternal {
4220
+ constructor(data) {
4221
+ super(data);
4222
+ this.component = data.component;
4223
+ this.isValid = data.isValid ?? (() => true);
4224
+ this.isEqual = data.isEqual ?? defaultIsEqual;
4225
+ this.customMetadata = data.customMetadata;
4226
+ }
4227
+ }
4228
+
4229
+ /**
4230
+ * Decorator for setting and getting custom property metadata.
4231
+ *
4232
+ * @param metadata - The metadata of the custom property.
4233
+ * @returns The method that defines the metadata.
4234
+ */
4235
+ function custom(metadata) {
4236
+ return baseProperty(new CustomDecoratorConfigInternal(metadata), DecoratorTypes.CUSTOM);
4237
+ }
4238
+
2099
4239
  /**
2100
4240
  * Public API Surface of ngx-material-entity.
2101
4241
  */
@@ -2104,5 +4244,5 @@ class StringDecoratorConfig extends PropertyDecoratorConfig {
2104
4244
  * Generated bundle index. Do not edit.
2105
4245
  */
2106
4246
 
2107
- export { DecoratorTypes, Entity, EntityService, EntityUtilities, NgxMatEntityConfirmDialogComponent, NgxMatEntityConfirmDialogModule, NgxMatEntityCreateDialogComponent, NgxMatEntityCreateDialogModule, NgxMatEntityEditDialogComponent, NgxMatEntityEditDialogModule, NgxMatEntityInputComponent, NgxMatEntityInputModule, NgxMatEntityTableComponent, NgxMatEntityTableModule, array, boolean, getValidationErrorMessage, number, object, string };
4247
+ export { ArrayDecoratorConfig, DateUtilities, DecoratorTypes, Entity, EntityService, EntityUtilities, FileUtilities, NgxMatEntityBaseInputComponent, NgxMatEntityConfirmDialogComponent, NgxMatEntityConfirmDialogModule, NgxMatEntityCreateDialogComponent, NgxMatEntityCreateDialogModule, NgxMatEntityEditDialogComponent, NgxMatEntityEditDialogModule, NgxMatEntityInputComponent, NgxMatEntityInputModule, NgxMatEntityTableComponent, NgxMatEntityTableModule, array, boolean, custom, date, file, getValidationErrorMessage, number, object, string };
2108
4248
  //# sourceMappingURL=ngx-material-entity.mjs.map