commons-shared-web-ui 0.0.50 → 0.0.51

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 (186) hide show
  1. package/fesm2022/commons-shared-web-ui.mjs +13828 -0
  2. package/fesm2022/commons-shared-web-ui.mjs.map +1 -0
  3. package/index.d.ts +4258 -0
  4. package/package.json +34 -53
  5. package/.claude/settings.local.json +0 -10
  6. package/documentation/alert.md +0 -123
  7. package/documentation/button-dropdown.md +0 -126
  8. package/documentation/button.md +0 -184
  9. package/documentation/cards-usage-guidelines.md +0 -131
  10. package/documentation/configurable-form.md +0 -605
  11. package/documentation/confirmation-modal.md +0 -250
  12. package/documentation/filter-sidebar.md +0 -178
  13. package/documentation/filter-table-selector.md +0 -228
  14. package/documentation/form-builder.md +0 -597
  15. package/documentation/form-components.md +0 -384
  16. package/documentation/nav.md +0 -427
  17. package/documentation/pagination.md +0 -181
  18. package/documentation/side-nav-documentation.md +0 -169
  19. package/documentation/smart-form.md +0 -2405
  20. package/documentation/smart-table.md +0 -1221
  21. package/documentation/snackbar.md +0 -118
  22. package/documentation/style-externalization.md +0 -88
  23. package/documentation/summary-card.md +0 -279
  24. package/ng-package.json +0 -28
  25. package/src/lib/modules/alert/alert.models.ts +0 -6
  26. package/src/lib/modules/alert/alert.module.ts +0 -16
  27. package/src/lib/modules/alert/components/alert/alert.component.html +0 -27
  28. package/src/lib/modules/alert/components/alert/alert.component.scss +0 -92
  29. package/src/lib/modules/alert/components/alert/alert.component.ts +0 -81
  30. package/src/lib/modules/button/button.models.ts +0 -13
  31. package/src/lib/modules/button/button.module.ts +0 -16
  32. package/src/lib/modules/button/components/button/button.component.html +0 -22
  33. package/src/lib/modules/button/components/button/button.component.scss +0 -88
  34. package/src/lib/modules/button/components/button/button.component.ts +0 -67
  35. package/src/lib/modules/button-dropdown/button-dropdown.models.ts +0 -26
  36. package/src/lib/modules/button-dropdown/button-dropdown.module.ts +0 -22
  37. package/src/lib/modules/button-dropdown/button-dropdown.theme.scss +0 -87
  38. package/src/lib/modules/button-dropdown/components/button-dropdown/button-dropdown.component.html +0 -41
  39. package/src/lib/modules/button-dropdown/components/button-dropdown/button-dropdown.component.scss +0 -135
  40. package/src/lib/modules/button-dropdown/components/button-dropdown/button-dropdown.component.ts +0 -160
  41. package/src/lib/modules/configurable-form/component/configurable-form.component.html +0 -294
  42. package/src/lib/modules/configurable-form/component/configurable-form.component.scss +0 -503
  43. package/src/lib/modules/configurable-form/component/configurable-form.component.ts +0 -628
  44. package/src/lib/modules/configurable-form/configurable-form.examples.ts +0 -154
  45. package/src/lib/modules/configurable-form/configurable-form.model.ts +0 -131
  46. package/src/lib/modules/configurable-form/configurable-form.module.ts +0 -19
  47. package/src/lib/modules/confirmation-modal/components/confirmation-modal/confirmation-modal.component.html +0 -77
  48. package/src/lib/modules/confirmation-modal/components/confirmation-modal/confirmation-modal.component.scss +0 -395
  49. package/src/lib/modules/confirmation-modal/components/confirmation-modal/confirmation-modal.component.ts +0 -266
  50. package/src/lib/modules/confirmation-modal/confirmation-modal.models.ts +0 -71
  51. package/src/lib/modules/confirmation-modal/confirmation-modal.module.ts +0 -20
  52. package/src/lib/modules/filter/components/filter/filter.component.html +0 -131
  53. package/src/lib/modules/filter/components/filter/filter.component.scss +0 -245
  54. package/src/lib/modules/filter/components/filter/filter.component.ts +0 -216
  55. package/src/lib/modules/filter/filter.models.ts +0 -88
  56. package/src/lib/modules/filter/filter.module.ts +0 -24
  57. package/src/lib/modules/filter-sidebar/components/filter-sidebar/filter-sidebar.component.html +0 -112
  58. package/src/lib/modules/filter-sidebar/components/filter-sidebar/filter-sidebar.component.scss +0 -186
  59. package/src/lib/modules/filter-sidebar/components/filter-sidebar/filter-sidebar.component.ts +0 -163
  60. package/src/lib/modules/filter-sidebar/filter-sidebar.models.ts +0 -95
  61. package/src/lib/modules/filter-sidebar/filter-sidebar.module.ts +0 -24
  62. package/src/lib/modules/filter-table-selector/components/filter-table-selector/filter-table-selector.component.html +0 -73
  63. package/src/lib/modules/filter-table-selector/components/filter-table-selector/filter-table-selector.component.scss +0 -321
  64. package/src/lib/modules/filter-table-selector/components/filter-table-selector/filter-table-selector.component.ts +0 -361
  65. package/src/lib/modules/filter-table-selector/filter-table-selector.models.ts +0 -91
  66. package/src/lib/modules/filter-table-selector/filter-table-selector.module.ts +0 -22
  67. package/src/lib/modules/form-builder/components/field-configurator/configurator-config-panel/configurator-config-panel.component.html +0 -63
  68. package/src/lib/modules/form-builder/components/field-configurator/configurator-config-panel/configurator-config-panel.component.scss +0 -496
  69. package/src/lib/modules/form-builder/components/field-configurator/configurator-config-panel/configurator-config-panel.component.ts +0 -445
  70. package/src/lib/modules/form-builder/components/field-configurator/configurator-tree/configurator-tree.component.html +0 -75
  71. package/src/lib/modules/form-builder/components/field-configurator/configurator-tree/configurator-tree.component.scss +0 -210
  72. package/src/lib/modules/form-builder/components/field-configurator/configurator-tree/configurator-tree.component.ts +0 -55
  73. package/src/lib/modules/form-builder/components/field-configurator/field-configurator.component.html +0 -25
  74. package/src/lib/modules/form-builder/components/field-configurator/field-configurator.component.scss +0 -82
  75. package/src/lib/modules/form-builder/components/field-configurator/field-configurator.component.ts +0 -95
  76. package/src/lib/modules/form-builder/components/field-selection/field-selection.component.html +0 -20
  77. package/src/lib/modules/form-builder/components/field-selection/field-selection.component.scss +0 -37
  78. package/src/lib/modules/form-builder/components/field-selection/field-selection.component.ts +0 -94
  79. package/src/lib/modules/form-builder/components/field-selection/group-node/group-node.component.html +0 -46
  80. package/src/lib/modules/form-builder/components/field-selection/group-node/group-node.component.scss +0 -102
  81. package/src/lib/modules/form-builder/components/field-selection/group-node/group-node.component.ts +0 -50
  82. package/src/lib/modules/form-builder/components/field-selection/selection-field-node/selection-field-node.component.html +0 -35
  83. package/src/lib/modules/form-builder/components/field-selection/selection-field-node/selection-field-node.component.scss +0 -67
  84. package/src/lib/modules/form-builder/components/field-selection/selection-field-node/selection-field-node.component.ts +0 -34
  85. package/src/lib/modules/form-builder/components/field-selection/selection-section-node/selection-section-node.component.html +0 -68
  86. package/src/lib/modules/form-builder/components/field-selection/selection-section-node/selection-section-node.component.scss +0 -113
  87. package/src/lib/modules/form-builder/components/field-selection/selection-section-node/selection-section-node.component.ts +0 -74
  88. package/src/lib/modules/form-builder/configs/field-type-schema.map.ts +0 -533
  89. package/src/lib/modules/form-builder/form-builder.module.ts +0 -36
  90. package/src/lib/modules/form-builder/index.ts +0 -9
  91. package/src/lib/modules/form-builder/models/builder.models.ts +0 -7
  92. package/src/lib/modules/form-builder/models/field-configurator.models.ts +0 -38
  93. package/src/lib/modules/form-builder/models/field-selection.models.ts +0 -51
  94. package/src/lib/modules/form-builder/services/field-configurator.service.ts +0 -258
  95. package/src/lib/modules/form-builder/services/field-selection.service.ts +0 -299
  96. package/src/lib/modules/form-builder/services/form-schema-tree.service.ts +0 -670
  97. package/src/lib/modules/form-builder/tokens/builder.tokens.ts +0 -10
  98. package/src/lib/modules/form-builder/utils/constants.ts +0 -43
  99. package/src/lib/modules/form-components/components/checkbox/checkbox.component.html +0 -29
  100. package/src/lib/modules/form-components/components/checkbox/checkbox.component.scss +0 -111
  101. package/src/lib/modules/form-components/components/checkbox/checkbox.component.ts +0 -207
  102. package/src/lib/modules/form-components/components/checkbox/checkbox.models.ts +0 -35
  103. package/src/lib/modules/form-components/components/datepicker/datepicker.component.html +0 -42
  104. package/src/lib/modules/form-components/components/datepicker/datepicker.component.scss +0 -115
  105. package/src/lib/modules/form-components/components/datepicker/datepicker.component.ts +0 -267
  106. package/src/lib/modules/form-components/components/datepicker/datepicker.models.ts +0 -45
  107. package/src/lib/modules/form-components/components/dropdown/dropdown.component.html +0 -74
  108. package/src/lib/modules/form-components/components/dropdown/dropdown.component.scss +0 -252
  109. package/src/lib/modules/form-components/components/dropdown/dropdown.component.ts +0 -377
  110. package/src/lib/modules/form-components/components/dropdown/dropdown.models.ts +0 -53
  111. package/src/lib/modules/form-components/components/input/input.component.html +0 -51
  112. package/src/lib/modules/form-components/components/input/input.component.scss +0 -128
  113. package/src/lib/modules/form-components/components/input/input.component.ts +0 -250
  114. package/src/lib/modules/form-components/components/input/input.models.ts +0 -55
  115. package/src/lib/modules/form-components/components/radio/radio.component.html +0 -22
  116. package/src/lib/modules/form-components/components/radio/radio.component.scss +0 -107
  117. package/src/lib/modules/form-components/components/radio/radio.component.ts +0 -181
  118. package/src/lib/modules/form-components/components/radio/radio.models.ts +0 -39
  119. package/src/lib/modules/form-components/components/search/search.component.html +0 -15
  120. package/src/lib/modules/form-components/components/search/search.component.scss +0 -87
  121. package/src/lib/modules/form-components/components/search/search.component.ts +0 -213
  122. package/src/lib/modules/form-components/components/search/search.models.ts +0 -40
  123. package/src/lib/modules/form-components/components/toggle/toggle.component.html +0 -15
  124. package/src/lib/modules/form-components/components/toggle/toggle.component.scss +0 -81
  125. package/src/lib/modules/form-components/components/toggle/toggle.component.ts +0 -166
  126. package/src/lib/modules/form-components/components/toggle/toggle.models.ts +0 -27
  127. package/src/lib/modules/form-components/directives/click-outside.directive.ts +0 -22
  128. package/src/lib/modules/form-components/form-components.module.ts +0 -41
  129. package/src/lib/modules/material/material.module.ts +0 -94
  130. package/src/lib/modules/nav/components/nav/nav.component.html +0 -34
  131. package/src/lib/modules/nav/components/nav/nav.component.scss +0 -171
  132. package/src/lib/modules/nav/components/nav/nav.component.ts +0 -82
  133. package/src/lib/modules/nav/nav.models.ts +0 -31
  134. package/src/lib/modules/nav/nav.module.ts +0 -17
  135. package/src/lib/modules/pagination/components/pagination/pagination.component.html +0 -52
  136. package/src/lib/modules/pagination/components/pagination/pagination.component.scss +0 -155
  137. package/src/lib/modules/pagination/components/pagination/pagination.component.ts +0 -109
  138. package/src/lib/modules/pagination/pagination.module.ts +0 -17
  139. package/src/lib/modules/side-nav/components/side-nav/side-nav.component.html +0 -56
  140. package/src/lib/modules/side-nav/components/side-nav/side-nav.component.scss +0 -342
  141. package/src/lib/modules/side-nav/components/side-nav/side-nav.component.ts +0 -135
  142. package/src/lib/modules/side-nav/side-nav.models.ts +0 -38
  143. package/src/lib/modules/side-nav/side-nav.module.ts +0 -16
  144. package/src/lib/modules/smart-form/components/form-field/form-field.component.html +0 -1196
  145. package/src/lib/modules/smart-form/components/form-field/form-field.component.scss +0 -2014
  146. package/src/lib/modules/smart-form/components/form-field/form-field.component.ts +0 -2525
  147. package/src/lib/modules/smart-form/components/form-section/form-section.component.html +0 -65
  148. package/src/lib/modules/smart-form/components/form-section/form-section.component.scss +0 -209
  149. package/src/lib/modules/smart-form/components/form-section/form-section.component.ts +0 -131
  150. package/src/lib/modules/smart-form/components/smart-form/smart-form.component.html +0 -253
  151. package/src/lib/modules/smart-form/components/smart-form/smart-form.component.scss +0 -689
  152. package/src/lib/modules/smart-form/components/smart-form/smart-form.component.ts +0 -1124
  153. package/src/lib/modules/smart-form/index.ts +0 -10
  154. package/src/lib/modules/smart-form/models/form-schema.model.ts +0 -733
  155. package/src/lib/modules/smart-form/models/hierarchy-config.model.ts +0 -21
  156. package/src/lib/modules/smart-form/services/expression.service.ts +0 -75
  157. package/src/lib/modules/smart-form/services/smart-form-controller.service.ts +0 -65
  158. package/src/lib/modules/smart-form/smart-form.examples.ts +0 -1324
  159. package/src/lib/modules/smart-form/smart-form.module.ts +0 -36
  160. package/src/lib/modules/smart-form/utils/translation.utils.ts +0 -82
  161. package/src/lib/modules/smart-form/utils/trusted-url.pipe.ts +0 -25
  162. package/src/lib/modules/smart-form/utils/validation.utils.ts +0 -98
  163. package/src/lib/modules/smart-table/components/smart-table/smart-table.component.html +0 -283
  164. package/src/lib/modules/smart-table/components/smart-table/smart-table.component.scss +0 -685
  165. package/src/lib/modules/smart-table/components/smart-table/smart-table.component.ts +0 -1128
  166. package/src/lib/modules/smart-table/models/table-config.model.ts +0 -207
  167. package/src/lib/modules/smart-table/smart-table.module.ts +0 -30
  168. package/src/lib/modules/smart-table/utils/safe-html.pipe.ts +0 -28
  169. package/src/lib/modules/smart-table/utils/smart-table.utils.ts +0 -18
  170. package/src/lib/modules/snackbar/components/snackbar.component.html +0 -41
  171. package/src/lib/modules/snackbar/components/snackbar.component.scss +0 -99
  172. package/src/lib/modules/snackbar/components/snackbar.component.ts +0 -18
  173. package/src/lib/modules/snackbar/models/snackbar.models.ts +0 -10
  174. package/src/lib/modules/snackbar/services/snackbar.service.ts +0 -40
  175. package/src/lib/modules/snackbar/snackbar.module.ts +0 -11
  176. package/src/lib/modules/summary-card/components/summary-card/summary-card.component.html +0 -47
  177. package/src/lib/modules/summary-card/components/summary-card/summary-card.component.scss +0 -199
  178. package/src/lib/modules/summary-card/components/summary-card/summary-card.component.ts +0 -126
  179. package/src/lib/modules/summary-card/summary-card.module.ts +0 -18
  180. package/src/lib/shared-ui.module.ts +0 -44
  181. package/src/lib/utils/constants.ts +0 -11
  182. package/src/lib/utils/storage.utils.ts +0 -37
  183. package/src/lib/utils/string.utils.ts +0 -23
  184. package/src/lib/utils/translation.utils.ts +0 -87
  185. package/src/public-api.ts +0 -104
  186. package/tsconfig.lib.json +0 -15
@@ -1,628 +0,0 @@
1
- import { Component, EventEmitter, Input, OnInit, Output, OnChanges, SimpleChanges } from '@angular/core';
2
- import { FormBuilder, FormGroup, FormControl, FormArray, Validators, AbstractControl, ReactiveFormsModule } from '@angular/forms';
3
- import { MatSnackBar } from '@angular/material/snack-bar';
4
- import { HttpClient } from '@angular/common/http';
5
- import {
6
- FormConfig,
7
- FormField,
8
- FormSection,
9
- FormOption,
10
- JsonFormConfig,
11
- JsonFieldConfig,
12
- FieldType,
13
- UISubType
14
- } from '../configurable-form.model';
15
- import { CommonModule } from '@angular/common';
16
- import { MaterialModule } from '../../material/material.module';
17
- import { translateConfig } from '../../../utils/translation.utils';
18
-
19
- @Component({
20
- selector: 'lib-configurable-form',
21
- templateUrl: './configurable-form.component.html',
22
- styleUrls: ['./configurable-form.component.scss'],
23
- standalone: true,
24
- imports: [CommonModule, ReactiveFormsModule, MaterialModule],
25
- })
26
- export class ConfigurableFormComponent implements OnInit, OnChanges {
27
- @Input() config!: FormConfig;
28
- @Input() jsonConfig!: JsonFormConfig;
29
- @Input() data: any = {};
30
- @Input() baseApiUrl: string = '';
31
- @Input() labels: any;
32
- @Output() optionsLoad = new EventEmitter<any>();
33
-
34
- form!: FormGroup;
35
- processedConfig!: FormConfig;
36
- fieldVisibilityMap: Map<string, boolean> = new Map();
37
- passwordFieldState: Map<string, boolean> = new Map();
38
-
39
- constructor(
40
- private fb: FormBuilder,
41
- private snackBar: MatSnackBar,
42
- private http: HttpClient
43
- ) { }
44
-
45
- ngOnInit(): void {
46
- this.initializeForm();
47
- }
48
-
49
- ngOnChanges(changes: SimpleChanges): void {
50
- if (changes['config'] || changes['jsonConfig']) {
51
- this.initializeForm();
52
- }
53
- if (changes['data'] && this.form) {
54
- this.form.patchValue(this.data);
55
- }
56
- }
57
-
58
- initializeForm() {
59
- // Transform JSON config if provided, otherwise use config directly
60
- if (this.jsonConfig) {
61
- this.processedConfig = this.transformJsonConfig(this.jsonConfig);
62
- } else if (this.config) {
63
- this.processedConfig = JSON.parse(JSON.stringify(this.config));
64
- } else {
65
- return;
66
- }
67
-
68
- // Apply translations if labels and labelsObject are provided
69
- if (this.labels && this.labels.labelsObject) {
70
- translateConfig(this.processedConfig, this.labels.labelsObject);
71
- }
72
-
73
-
74
- this.normalizeFields();
75
- this.initializeFieldVisibility();
76
- this.buildForm();
77
- this.setupDependencies();
78
-
79
- // Patch initial data if provided
80
- if (this.data && Object.keys(this.data).length > 0) {
81
- this.form.patchValue(this.data);
82
- }
83
- }
84
-
85
- // Transform JSON config format to internal FormConfig format
86
- transformJsonConfig(jsonConfig: JsonFormConfig): FormConfig {
87
- const fields = jsonConfig.jsonConfig
88
- .sort((a, b) => a.sequence - b.sequence)
89
- .map(field => this.transformJsonField(field));
90
-
91
- return {
92
- sections: [{
93
- sectionTitle: jsonConfig.label,
94
- fields: fields
95
- }],
96
- entityType: jsonConfig.entityType
97
- };
98
- }
99
-
100
- // Transform individual JSON field to FormField
101
- transformJsonField(jsonField: JsonFieldConfig): FormField {
102
- const fieldType = this.mapUISubTypeToFieldType(jsonField.uiConfig.subType);
103
-
104
- return {
105
- name: jsonField.jsonKey,
106
- jsonKey: jsonField.jsonKey,
107
- label: jsonField.label,
108
- type: fieldType,
109
- sequence: jsonField.sequence,
110
- keyType: jsonField.keyType,
111
- uiConfig: jsonField.uiConfig,
112
- validationRules: jsonField.validationRules,
113
- required: jsonField.validationRules?.isMandatory || jsonField.validationRules?.isRequired,
114
- mandatory: jsonField.validationRules?.isMandatory,
115
- dependsOn: undefined, // Will be set based on dependent array
116
- dependent: jsonField.uiConfig.dependent,
117
- optionConfigs: jsonField.uiConfig.optionConfigs,
118
- class: 'col-12'
119
- };
120
- }
121
-
122
- // Map UI subtype to field type
123
- mapUISubTypeToFieldType(subType?: string): FieldType {
124
- switch (subType) {
125
- case 'UI_SUBTYPE.SHORT_TEXT':
126
- return 'text';
127
- case 'UI_SUBTYPE.LONG_TEXT':
128
- return 'textarea';
129
- case 'UI_SUBTYPE.NUMBER':
130
- return 'number';
131
- case 'UI_SUBTYPE.EMAIL':
132
- return 'email';
133
- case 'UI_SUBTYPE.PHONE':
134
- return 'tel';
135
- case 'UI_SUBTYPE.URL':
136
- return 'url';
137
- default:
138
- return 'text';
139
- }
140
- }
141
-
142
- // Normalize fields to ensure all required properties exist
143
- normalizeFields() {
144
- this.processedConfig.sections.forEach(section => {
145
- section.fields.forEach(field => {
146
- // Set default type if not specified
147
- if (!field.type) {
148
- field.type = 'text';
149
- }
150
-
151
- // Merge uiConfig with field-level properties
152
- if (field.uiConfig) {
153
- if (field.uiConfig.type === 'UI_TYPE.DROP_DOWN') {
154
- field.type = 'dropdown';
155
- }
156
- if (field.uiConfig.optionConfigs) {
157
- field.optionConfigs = field.uiConfig.optionConfigs;
158
- }
159
- if (field.uiConfig.dependent) {
160
- field.dependent = field.uiConfig.dependent;
161
- }
162
- }
163
-
164
- // Initialize visibility
165
- if (field.visible === undefined) {
166
- field.visible = true;
167
- }
168
-
169
- // Load options for dropdowns
170
- if ((field.type === 'dropdown' || field.type === 'select') && field.optionConfigs) {
171
- this.loadFieldOptions(field);
172
- }
173
- });
174
- });
175
- }
176
-
177
- // Initialize field visibility map
178
- initializeFieldVisibility() {
179
- this.processedConfig.sections.forEach(section => {
180
- section.fields.forEach(field => {
181
- this.fieldVisibilityMap.set(field.name, field.visible !== false);
182
- });
183
- });
184
- }
185
-
186
- buildForm() {
187
- const formGroupConfig: any = {};
188
-
189
- this.processedConfig.sections.forEach(section => {
190
- if (section.isRepeater) {
191
- // Create FormArray for repeater sections
192
- const arrayName = section.formArrayName || 'items';
193
- const minItems = section.minItems || 1;
194
- const initialItems = [];
195
-
196
- for (let i = 0; i < minItems; i++) {
197
- initialItems.push(this.createGroup(section.fields));
198
- }
199
-
200
- formGroupConfig[arrayName] = this.fb.array(initialItems);
201
- } else {
202
- // Add regular fields to form group
203
- section.fields.forEach(field => {
204
- if (field.subFields) {
205
- // Composite field - add all sub-fields
206
- field.subFields.forEach(subField => {
207
- if (field.required || field.mandatory) {
208
- subField.required = true;
209
- }
210
- formGroupConfig[subField.name] = this.createControl(subField);
211
- });
212
- } else {
213
- formGroupConfig[field.name] = this.createControl(field);
214
- }
215
- });
216
- }
217
- });
218
-
219
- this.form = this.fb.group(formGroupConfig);
220
-
221
- // Apply composite validators to the root form group
222
- this.processedConfig.sections.forEach(section => {
223
- if (!section.isRepeater) {
224
- section.fields.forEach(field => {
225
- if (field.type === 'composite' && field.compositeValidationRule && field.subFields) {
226
- this.form.addValidators(this.createCompositeValidator(field));
227
- }
228
- });
229
- }
230
- });
231
- this.form.updateValueAndValidity();
232
- }
233
-
234
- createCompositeValidator(field: FormField) {
235
- return (control: AbstractControl) => {
236
- const group = control as FormGroup;
237
- if (!field.subFields || field.subFields.length < 2) return null;
238
-
239
- if (field.compositeValidationRule === 'minMax') {
240
- const minControl = group.get(field.subFields[0].name);
241
- const maxControl = group.get(field.subFields[1].name);
242
-
243
- if (minControl && maxControl && minControl.value !== null && maxControl.value !== null) {
244
- if (Number(minControl.value) > Number(maxControl.value)) {
245
- return { [`invalid_minMax_${field.name}`]: true };
246
- }
247
- }
248
- }
249
-
250
- if (field.compositeValidationRule === 'percentageTotal') {
251
- let total = 0;
252
- let allPresent = true;
253
-
254
- field.subFields.forEach(sub => {
255
- const ctrl = group.get(sub.name);
256
- if (ctrl && ctrl.value !== null && ctrl.value !== '') {
257
- total += Number(ctrl.value);
258
- } else {
259
- allPresent = false;
260
- }
261
- });
262
-
263
- if (allPresent && total !== 100) {
264
- return { [`invalid_percentageTotal_${field.name}`]: true };
265
- }
266
- }
267
-
268
- return null;
269
- };
270
- }
271
-
272
- createControl(field: FormField): FormControl {
273
- const validators = [];
274
-
275
- // Add validators based on field configuration
276
- if (field.required || field.mandatory || field.validationRules?.isMandatory || field.validationRules?.isRequired) {
277
- validators.push(Validators.required);
278
- }
279
-
280
- if (field.validationRules?.minLength) {
281
- validators.push(Validators.minLength(field.validationRules.minLength));
282
- }
283
-
284
- if (field.validationRules?.maxLength) {
285
- validators.push(Validators.maxLength(field.validationRules.maxLength));
286
- }
287
-
288
- if (field.validationRules?.pattern) {
289
- validators.push(Validators.pattern(field.validationRules.pattern));
290
- }
291
-
292
- if (field.validationRules?.min !== undefined) {
293
- validators.push(Validators.min(field.validationRules.min));
294
- }
295
-
296
- if (field.validationRules?.max !== undefined) {
297
- validators.push(Validators.max(field.validationRules.max));
298
- }
299
-
300
- if (field.type === 'email') {
301
- validators.push(Validators.email);
302
- }
303
-
304
- const initialValue = field.value !== undefined ? field.value : '';
305
- return this.fb.control({ value: initialValue, disabled: field.disabled || false }, validators);
306
- }
307
-
308
- createGroup(fields: FormField[]): FormGroup {
309
- const groupConfig: any = {};
310
-
311
- fields.forEach(field => {
312
- if (field.subFields) {
313
- field.subFields.forEach(subField => {
314
- groupConfig[subField.name] = this.createControl(subField);
315
- });
316
- } else {
317
- groupConfig[field.name] = this.createControl(field);
318
- }
319
- });
320
-
321
- return this.fb.group(groupConfig);
322
- }
323
-
324
- getFormArray(name: string): FormArray {
325
- return this.form.get(name) as FormArray;
326
- }
327
-
328
- addRepeaterItem(section: FormSection) {
329
- const arrayName = section.formArrayName || 'items';
330
- const formArray = this.getFormArray(arrayName);
331
-
332
- // Check max items
333
- if (section.maxItems && formArray.length >= section.maxItems) {
334
- this.snackBar.open(this.labels.errorMaxItemsAllowed.replace('{0}', String(section.maxItems)), this.labels.closeSnackBar, { duration: 3000 });
335
- return;
336
- }
337
-
338
- formArray.push(this.createGroup(section.fields));
339
- }
340
-
341
- removeRepeaterItem(sectionName: string, index: number) {
342
- const formArray = this.getFormArray(sectionName);
343
- formArray.removeAt(index);
344
- }
345
-
346
- validate(): boolean {
347
- if (this.form.invalid) {
348
- this.form.markAllAsTouched();
349
- this.scrollToFirstInvalidControl();
350
- return false;
351
- }
352
- return true;
353
- }
354
-
355
- scrollToFirstInvalidControl() {
356
- const firstInvalidControl = document.querySelector('.is-invalid');
357
- if (firstInvalidControl) {
358
- firstInvalidControl.scrollIntoView({ behavior: 'smooth', block: 'center' });
359
- }
360
- }
361
-
362
- setupDependencies() {
363
- this.processedConfig.sections.forEach(section => {
364
- section.fields.forEach(field => {
365
-
366
-
367
- // Also setup for fields with dependent array
368
- if (field.dependent && field.dependent.length > 0) {
369
- const control = this.form.get(field.name);
370
- if (control) {
371
- control.valueChanges.subscribe(value => {
372
- this.onFieldValueChange(field, value);
373
- });
374
- }
375
- }
376
- });
377
- });
378
- }
379
-
380
- onFieldValueChange(field: FormField, value: any) {
381
- // Handle dependent fields
382
- if (field.dependent && field.dependent.length > 0) {
383
- field.dependent.forEach(dependentFieldName => {
384
- const dependentField = this.findFieldByName(dependentFieldName);
385
- if (dependentField) {
386
- // Clear the dependent field value
387
- const control = this.form.get(dependentFieldName);
388
- if (control) {
389
- control.setValue('');
390
- control.markAsUntouched();
391
- }
392
-
393
- // Load new options for the dependent field
394
- if (value) {
395
- this.loadFieldOptions(dependentField, { [field.name]: value });
396
- } else {
397
- // Clear options if parent value is cleared
398
- dependentField.loadedOptions = [];
399
- }
400
- }
401
- });
402
- }
403
- }
404
-
405
- // Load options for a dropdown field
406
- loadFieldOptions(field: FormField, parentValues?: any) {
407
- // Emit event for parent to notify about options load request
408
- // Allow parent to mark as handled to skip internal API call
409
- const event = { field, parentValue: parentValues, handled: false };
410
- this.optionsLoad.emit(event);
411
-
412
- if (event.handled) {
413
- return;
414
- }
415
-
416
- if (!field.optionConfigs) {
417
- return;
418
- }
419
-
420
- const config = field.optionConfigs;
421
-
422
- // Handle static options
423
- if (config.optionDTO === 'OPTION_DTO.STATIC' && config.staticOptions) {
424
- field.loadedOptions = config.staticOptions;
425
- return;
426
- }
427
-
428
- // Handle API-based options
429
- if (config.optionDTO === 'OPTION_DTO.REF_DATA' && config.url) {
430
- let url = config.url;
431
-
432
- // Replace placeholders in URL with parent values
433
- if (parentValues) {
434
- Object.keys(parentValues).forEach(key => {
435
- url = url.replace(`{${key}}`, parentValues[key]);
436
- });
437
- }
438
-
439
- // Prepend base API URL if provided
440
- if (this.baseApiUrl && !url.startsWith('http')) {
441
- url = `${this.baseApiUrl}/${url}`;
442
- }
443
-
444
- this.http.get<any>(url).subscribe({
445
- next: (response) => {
446
- // Extract data from response
447
- const data = response.data || response.content || response;
448
- field.loadedOptions = this.extractOptions(data, config);
449
- },
450
- error: (error) => {
451
- console.error('Error loading options:', error);
452
- field.loadedOptions = [];
453
- }
454
- });
455
- }
456
- }
457
-
458
- // Extract options from API response
459
- extractOptions(data: any[], config: any): FormOption[] {
460
- if (!Array.isArray(data)) {
461
- return [];
462
- }
463
-
464
- return data.map(item => ({
465
- label: item[config.labelKey || 'name'],
466
- value: item[config.requestKey || 'code'] || item[config.valueKey || 'id'],
467
- code: item.code,
468
- name: item.name
469
- }));
470
- }
471
-
472
- // Get options for a field (either static or loaded)
473
- getFieldOptions(field: FormField): FormOption[] {
474
- return field.loadedOptions || field.options || [];
475
- }
476
-
477
- // Check if field is visible
478
- isFieldVisible(field: FormField): boolean {
479
- return this.fieldVisibilityMap.get(field.name) !== false;
480
- }
481
-
482
- // Toggle field visibility
483
- toggleFieldVisibility(field: FormField, visible: boolean) {
484
- this.fieldVisibilityMap.set(field.name, visible);
485
-
486
- const control = this.form.get(field.name);
487
- if (control) {
488
- if (visible) {
489
- // Re-enable and restore validators
490
- control.enable();
491
- this.updateControlValidators(control, field);
492
- } else {
493
- // Disable and clear validators
494
- control.disable();
495
- control.clearValidators();
496
- control.updateValueAndValidity();
497
- }
498
- }
499
- }
500
-
501
- // Update control validators based on field config
502
- updateControlValidators(control: AbstractControl, field: FormField) {
503
- const validators = [];
504
-
505
- if (field.required || field.mandatory || field.validationRules?.isMandatory) {
506
- validators.push(Validators.required);
507
- }
508
-
509
- if (field.validationRules?.minLength) {
510
- validators.push(Validators.minLength(field.validationRules.minLength));
511
- }
512
-
513
- if (field.validationRules?.maxLength) {
514
- validators.push(Validators.maxLength(field.validationRules.maxLength));
515
- }
516
-
517
- if (field.validationRules?.pattern) {
518
- validators.push(Validators.pattern(field.validationRules.pattern));
519
- }
520
-
521
- control.setValidators(validators);
522
- control.updateValueAndValidity();
523
- }
524
-
525
- onFileChange(event: any, field: FormField) {
526
- const files: FileList = event.target.files;
527
-
528
- if (!files || files.length === 0) {
529
- return;
530
- }
531
-
532
- // Initialize uploadedFiles if not present
533
- // Initialize uploadedFiles if not present
534
- if (!field.uploadedFiles) {
535
- field.uploadedFiles = [];
536
- }
537
-
538
- const uploadedFiles: any[] = [];
539
- // Handle files
540
- for (let i = 0; i < files.length; i++) {
541
- const file = files[i];
542
-
543
- // Check file size (5MB limit)
544
- if (file.size > 5 * 1024 * 1024) {
545
- this.snackBar.open(this.labels.errorFileLimitExceeded.replace('{0}', file.name), this.labels.closeSnackBar, { duration: 3000 });
546
- continue;
547
- }
548
-
549
- uploadedFiles.push({
550
- name: file.name,
551
- size: file.size,
552
- type: file.type,
553
- file: file
554
- });
555
- }
556
-
557
- if (field.multiple) {
558
- field.uploadedFiles.push(...uploadedFiles);
559
- } else {
560
- field.uploadedFiles = uploadedFiles;
561
- }
562
-
563
- // Update form control value for validation
564
- this.updateFileControlValue(field);
565
-
566
- // Clear the input
567
- event.target.value = '';
568
- }
569
-
570
- // Remove uploaded file
571
- removeFile(field: FormField, index: number) {
572
- if (field.uploadedFiles) {
573
- field.uploadedFiles.splice(index, 1);
574
- this.updateFileControlValue(field);
575
- }
576
- }
577
-
578
- // Update file control value for validation
579
- updateFileControlValue(field: FormField) {
580
- const control = this.form.get(field.name);
581
- if (control) {
582
- const hasFiles = field.uploadedFiles && field.uploadedFiles.length > 0;
583
- control.setValue(hasFiles ? field.uploadedFiles : null);
584
- control.markAsTouched();
585
- }
586
- }
587
-
588
- // Get character count for text field
589
- getCharacterCount(fieldName: string): number {
590
- const control = this.form.get(fieldName);
591
- if (control && control.value) {
592
- return control.value.toString().length;
593
- }
594
- return 0;
595
- }
596
-
597
- // Toggle section collapse
598
- toggleSection(section: FormSection) {
599
- section.collapsed = !section.collapsed;
600
- }
601
-
602
-
603
-
604
- // Helper method to find field by name
605
- private findFieldByName(name: string): FormField | undefined {
606
- for (const section of this.processedConfig.sections) {
607
- const field = section.fields.find(f => f.name === name);
608
- if (field) {
609
- return field;
610
- }
611
- }
612
- return undefined;
613
- }
614
-
615
- // Get the processed config for template use
616
- get sections(): FormSection[] {
617
- return this.processedConfig?.sections || [];
618
- }
619
-
620
- togglePassword(fieldName: string) {
621
- this.passwordFieldState.set(fieldName, !this.passwordFieldState.get(fieldName));
622
- }
623
-
624
- isPasswordVisible(fieldName: string): boolean {
625
- return this.passwordFieldState.get(fieldName) || false;
626
- }
627
- }
628
-