@decaf-ts/for-angular 0.0.23 → 0.0.24
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.
- package/components/component-renderer/component-renderer.component.d.ts +3 -2
- package/components/crud-field/crud-field.component.d.ts +4 -2
- package/components/fieldset/fieldset.component.d.ts +10 -1
- package/components/for-angular-components.module.d.ts +3 -2
- package/components/index.d.ts +1 -0
- package/components/layout/layout.component.d.ts +1 -24
- package/components/model-renderer/model-renderer.component.d.ts +6 -1
- package/components/steped-form/steped-form.component.d.ts +243 -0
- package/engine/NgxBaseComponent.d.ts +2 -2
- package/engine/NgxCrudFormField.d.ts +1 -0
- package/engine/NgxFormService.d.ts +381 -48
- package/engine/NgxRenderingEngine.d.ts +4 -2
- package/engine/interfaces.d.ts +1 -1
- package/engine/types.d.ts +4 -3
- package/esm2022/components/component-renderer/component-renderer.component.mjs +10 -4
- package/esm2022/components/crud-field/crud-field.component.mjs +14 -3
- package/esm2022/components/crud-form/crud-form.component.mjs +3 -3
- package/esm2022/components/empty-state/empty-state.component.mjs +2 -2
- package/esm2022/components/fieldset/fieldset.component.mjs +5 -3
- package/esm2022/components/for-angular-components.module.mjs +10 -5
- package/esm2022/components/index.mjs +2 -1
- package/esm2022/components/layout/layout.component.mjs +4 -29
- package/esm2022/components/list/list.component.mjs +3 -3
- package/esm2022/components/model-renderer/model-renderer.component.mjs +10 -3
- package/esm2022/components/steped-form/steped-form.component.mjs +291 -0
- package/esm2022/engine/NgxBaseComponent.mjs +10 -4
- package/esm2022/engine/NgxCrudFormField.mjs +19 -17
- package/esm2022/engine/NgxFormService.mjs +438 -57
- package/esm2022/engine/NgxRenderingEngine.mjs +21 -10
- package/esm2022/engine/ValidatorFactory.mjs +4 -4
- package/esm2022/engine/interfaces.mjs +1 -1
- package/esm2022/engine/types.mjs +1 -1
- package/fesm2022/decaf-ts-for-angular.mjs +818 -136
- package/fesm2022/decaf-ts-for-angular.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UIKeys, parseValueByType,
|
|
1
|
+
import { UIKeys, parseValueByType, HTML5CheckTypes, escapeHtml, HTML5InputTypes, parseToNumber, RenderingEngine, RenderingError } from '@decaf-ts/ui-decorators';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
3
|
import { InjectionToken, NgModule, isDevMode, reflectComponentType, inject, EnvironmentInjector, EventEmitter, ViewContainerRef, TemplateRef, ViewChild, Input, Output, Component, ElementRef, HostListener, CUSTOM_ELEMENTS_SCHEMA, Inject, ChangeDetectorRef, Renderer2, Injector, Directive } from '@angular/core';
|
|
4
4
|
import { CommonModule, NgComponentOutlet, Location } from '@angular/common';
|
|
@@ -14,9 +14,9 @@ import { apply, metadata } from '@decaf-ts/reflection';
|
|
|
14
14
|
import { IonInput, IonItem, IonCheckbox, IonRadioGroup, IonRadio, IonSelect, IonSelectOption, IonLabel, IonText, IonTextarea, IonIcon, IonButton, IonCard, IonCardContent, IonAccordionGroup, IonAccordion, IonList, IonReorder, IonReorderGroup, IonSearchbar, IonChip, IonListHeader, IonItemSliding, IonItemOptions, IonItemOption, IonContent, IonPopover, IonRefresher, IonThumbnail, IonSkeletonText, IonRefresherContent, IonInfiniteScroll, IonInfiniteScrollContent, IonLoading } from '@ionic/angular/standalone';
|
|
15
15
|
import { addIcons } from 'ionicons';
|
|
16
16
|
import * as allIcons from 'ionicons/icons';
|
|
17
|
-
import { chevronUpOutline, chevronDownOutline, createOutline, alertCircleOutline, chevronForwardOutline, chevronBackOutline } from 'ionicons/icons';
|
|
17
|
+
import { chevronUpOutline, chevronDownOutline, createOutline, alertCircleOutline, chevronForwardOutline, chevronBackOutline, arrowBackOutline, arrowForwardOutline } from 'ionicons/icons';
|
|
18
18
|
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
|
19
|
-
import { forkJoin, fromEvent, debounceTime, Subject } from 'rxjs';
|
|
19
|
+
import { forkJoin, fromEvent, debounceTime, Subject, timer } from 'rxjs';
|
|
20
20
|
import { map } from 'rxjs/operators';
|
|
21
21
|
import { Repository, OrderDirection, Condition } from '@decaf-ts/core';
|
|
22
22
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
@@ -226,12 +226,12 @@ class ValidatorFactory {
|
|
|
226
226
|
if (!Validation.keys().includes(key))
|
|
227
227
|
throw new Error('Unsupported custom validation');
|
|
228
228
|
const validatorFn = (control) => {
|
|
229
|
-
const {
|
|
229
|
+
const { type } = fieldProps;
|
|
230
230
|
const { validatorKey, props } = resolveValidatorKeyProps(key, fieldProps[key], type);
|
|
231
231
|
const validator = Validation.get(validatorKey);
|
|
232
232
|
// parseValueByType does not support undefined values
|
|
233
233
|
const value = typeof control.value !== 'undefined'
|
|
234
|
-
? parseValueByType(type,
|
|
234
|
+
? parseValueByType(type, control.value, fieldProps)
|
|
235
235
|
: undefined;
|
|
236
236
|
// Create a proxy to enable access to parent and child values
|
|
237
237
|
let proxy = ValidatorFactory.createProxy({});
|
|
@@ -875,12 +875,61 @@ class NgxFormService {
|
|
|
875
875
|
* @memberOf NgxFormService
|
|
876
876
|
*/
|
|
877
877
|
static { this.formRegistry = new Map(); }
|
|
878
|
+
static { this.pageMapper = {}; }
|
|
879
|
+
/**
|
|
880
|
+
* @description Creates a new form group or form array with the specified identifier.
|
|
881
|
+
* @summary Generates a FormGroup or FormArray based on the provided properties. If pages are specified
|
|
882
|
+
* and greater than 1, creates a FormArray; otherwise creates a FormGroup. The form can optionally
|
|
883
|
+
* be registered in the global form registry for later access throughout the application.
|
|
884
|
+
*
|
|
885
|
+
* @param {string} id - Unique identifier for the form
|
|
886
|
+
* @param {Partial<IComponentInput>} [props={}] - Configuration properties for the form
|
|
887
|
+
* @param {boolean} [registry=true] - Whether to register the form in the global registry
|
|
888
|
+
* @return {FormGroup | FormArray} The created form instance
|
|
889
|
+
*
|
|
890
|
+
* @mermaid
|
|
891
|
+
* sequenceDiagram
|
|
892
|
+
* participant C as Component
|
|
893
|
+
* participant NFS as NgxFormService
|
|
894
|
+
* participant FR as Form Registry
|
|
895
|
+
* participant AF as Angular Forms
|
|
896
|
+
*
|
|
897
|
+
* C->>NFS: createForm(id, props, registry)
|
|
898
|
+
* NFS->>FR: Check if form exists
|
|
899
|
+
* alt Form doesn't exist
|
|
900
|
+
* alt props.pages > 1
|
|
901
|
+
* NFS->>AF: new FormArray([])
|
|
902
|
+
* else
|
|
903
|
+
* NFS->>AF: new FormGroup({})
|
|
904
|
+
* end
|
|
905
|
+
* alt registry is true
|
|
906
|
+
* NFS->>FR: addRegistry(id, form)
|
|
907
|
+
* end
|
|
908
|
+
* end
|
|
909
|
+
* NFS-->>C: Return FormGroup | FormArray
|
|
910
|
+
*
|
|
911
|
+
* @static
|
|
912
|
+
* @memberOf NgxFormService
|
|
913
|
+
*/
|
|
914
|
+
static createForm(id, props = {}, registry = true) {
|
|
915
|
+
const form = this.formRegistry.get(id) ?? (props?.pages && props?.pages > 1 ? new FormArray([]) : new FormGroup({}));
|
|
916
|
+
if (!this.formRegistry.has(id) && registry)
|
|
917
|
+
this.addRegistry(id, form);
|
|
918
|
+
return form;
|
|
919
|
+
}
|
|
878
920
|
/**
|
|
879
921
|
* @description Adds a form to the registry.
|
|
880
|
-
* @summary Registers a FormGroup with a unique identifier
|
|
881
|
-
*
|
|
882
|
-
*
|
|
883
|
-
*
|
|
922
|
+
* @summary Registers a FormGroup or FormArray with a unique identifier for global access throughout
|
|
923
|
+
* the application. This allows forms to be retrieved and managed centrally. Throws an error if
|
|
924
|
+
* the identifier is already in use to prevent conflicts.
|
|
925
|
+
*
|
|
926
|
+
* @param {string} formId - The unique identifier for the form
|
|
927
|
+
* @param {FormParent} formGroup - The FormGroup or FormArray to be registered
|
|
928
|
+
* @return {void}
|
|
929
|
+
* @throws {Error} If a FormGroup with the given id is already registered
|
|
930
|
+
*
|
|
931
|
+
* @static
|
|
932
|
+
* @memberOf NgxFormService
|
|
884
933
|
*/
|
|
885
934
|
static addRegistry(formId, formGroup) {
|
|
886
935
|
if (this.formRegistry.has(formId))
|
|
@@ -889,8 +938,15 @@ class NgxFormService {
|
|
|
889
938
|
}
|
|
890
939
|
/**
|
|
891
940
|
* @description Removes a form from the registry.
|
|
892
|
-
* @summary Deletes a FormGroup from the registry using its unique identifier.
|
|
893
|
-
*
|
|
941
|
+
* @summary Deletes a FormGroup or FormArray from the registry using its unique identifier.
|
|
942
|
+
* This cleans up the registry and allows the identifier to be reused. The form itself
|
|
943
|
+
* is not destroyed, only removed from the central registry.
|
|
944
|
+
*
|
|
945
|
+
* @param {string} formId - The unique identifier of the form to be removed
|
|
946
|
+
* @return {void}
|
|
947
|
+
*
|
|
948
|
+
* @static
|
|
949
|
+
* @memberOf NgxFormService
|
|
894
950
|
*/
|
|
895
951
|
static removeRegistry(formId) {
|
|
896
952
|
this.formRegistry.delete(formId);
|
|
@@ -898,9 +954,38 @@ class NgxFormService {
|
|
|
898
954
|
/**
|
|
899
955
|
* @description Resolves the parent group and control name from a path.
|
|
900
956
|
* @summary Traverses the form group structure to find the parent group and control name for a given path.
|
|
901
|
-
*
|
|
902
|
-
*
|
|
903
|
-
*
|
|
957
|
+
* Handles complex nested structures including arrays and sub-groups. Creates missing intermediate
|
|
958
|
+
* groups as needed and properly configures FormArray controls for multiple value scenarios.
|
|
959
|
+
*
|
|
960
|
+
* @param {FormGroup} formGroup - The root FormGroup to traverse
|
|
961
|
+
* @param {string} path - The dot-separated path to the control (e.g., 'user.address.street')
|
|
962
|
+
* @param {IComponentInput} componentProps - Properties defining the component configuration
|
|
963
|
+
* @param {KeyValue} parentProps - Properties from the parent component for context
|
|
964
|
+
* @return {FormParentGroup} A tuple containing the parent FormGroup and the control name
|
|
965
|
+
*
|
|
966
|
+
* @private
|
|
967
|
+
* @mermaid
|
|
968
|
+
* sequenceDiagram
|
|
969
|
+
* participant NFS as NgxFormService
|
|
970
|
+
* participant FG as FormGroup
|
|
971
|
+
* participant FA as FormArray
|
|
972
|
+
*
|
|
973
|
+
* NFS->>NFS: Split path into parts
|
|
974
|
+
* loop For each path part
|
|
975
|
+
* alt Control doesn't exist
|
|
976
|
+
* alt isMultiple and part is childOf
|
|
977
|
+
* NFS->>FA: new FormArray([new FormGroup({})])
|
|
978
|
+
* else
|
|
979
|
+
* NFS->>FG: new FormGroup({})
|
|
980
|
+
* end
|
|
981
|
+
* NFS->>FG: addControl(part, newControl)
|
|
982
|
+
* end
|
|
983
|
+
* NFS->>NFS: Navigate to next level
|
|
984
|
+
* end
|
|
985
|
+
* NFS-->>NFS: Return [parentGroup, controlName]
|
|
986
|
+
*
|
|
987
|
+
* @static
|
|
988
|
+
* @memberOf NgxFormService
|
|
904
989
|
*/
|
|
905
990
|
static resolveParentGroup(formGroup, path, componentProps, parentProps) {
|
|
906
991
|
const isMultiple = parentProps?.['multiple'] || parentProps?.['type'] === 'Array' || false;
|
|
@@ -1079,19 +1164,62 @@ class NgxFormService {
|
|
|
1079
1164
|
if (!parentGroup.get(controlName)) {
|
|
1080
1165
|
const control = NgxFormService.fromProps(componentProps, componentProps.updateMode || 'change');
|
|
1081
1166
|
NgxFormService.register(control, componentProps);
|
|
1082
|
-
parentGroup
|
|
1167
|
+
if (parentGroup instanceof FormGroup) {
|
|
1168
|
+
parentGroup.addControl(controlName, control);
|
|
1169
|
+
}
|
|
1170
|
+
if (parentGroup instanceof FormArray) {
|
|
1171
|
+
const root = parentGroup.controls[componentProps?.['page'] - 1];
|
|
1172
|
+
if (root) {
|
|
1173
|
+
root.addControl(controlName, control);
|
|
1174
|
+
}
|
|
1175
|
+
else {
|
|
1176
|
+
parentGroup.push({ [controlName]: control });
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1083
1179
|
}
|
|
1084
|
-
componentProps['
|
|
1180
|
+
const root = parentGroup instanceof FormArray ? parentGroup.controls[componentProps?.['page'] - 1] : parentGroup;
|
|
1181
|
+
componentProps['formGroup'] = root;
|
|
1085
1182
|
componentProps['formControl'] = parentGroup.get(controlName);
|
|
1086
1183
|
componentProps['multiple'] = isMultiple;
|
|
1087
1184
|
}
|
|
1088
1185
|
/**
|
|
1089
1186
|
* @description Retrieves a control from a registered form.
|
|
1090
1187
|
* @summary Finds and returns an AbstractControl from a registered form using the form id and optional path.
|
|
1091
|
-
*
|
|
1092
|
-
*
|
|
1093
|
-
*
|
|
1094
|
-
* @
|
|
1188
|
+
* This method provides centralized access to form controls across the application by leveraging
|
|
1189
|
+
* the form registry system.
|
|
1190
|
+
*
|
|
1191
|
+
* @param {string} formId - The unique identifier of the form in the registry
|
|
1192
|
+
* @param {string} [path] - The optional dot-separated path to a specific control within the form
|
|
1193
|
+
* @return {AbstractControl} The requested AbstractControl (FormGroup, FormArray, or FormControl)
|
|
1194
|
+
* @throws {Error} If the form is not found in the registry or the control is not found in the form
|
|
1195
|
+
*
|
|
1196
|
+
* @mermaid
|
|
1197
|
+
* sequenceDiagram
|
|
1198
|
+
* participant C as Component
|
|
1199
|
+
* participant NFS as NgxFormService
|
|
1200
|
+
* participant FR as Form Registry
|
|
1201
|
+
*
|
|
1202
|
+
* C->>NFS: getControlFromForm(formId, path?)
|
|
1203
|
+
* NFS->>FR: Get form by formId
|
|
1204
|
+
* alt Form not found
|
|
1205
|
+
* FR-->>NFS: null
|
|
1206
|
+
* NFS-->>C: Throw Error
|
|
1207
|
+
* else Form found
|
|
1208
|
+
* FR-->>NFS: Return form
|
|
1209
|
+
* alt path provided
|
|
1210
|
+
* NFS->>NFS: form.get(path)
|
|
1211
|
+
* alt Control not found
|
|
1212
|
+
* NFS-->>C: Throw Error
|
|
1213
|
+
* else
|
|
1214
|
+
* NFS-->>C: Return control
|
|
1215
|
+
* end
|
|
1216
|
+
* else
|
|
1217
|
+
* NFS-->>C: Return form
|
|
1218
|
+
* end
|
|
1219
|
+
* end
|
|
1220
|
+
*
|
|
1221
|
+
* @static
|
|
1222
|
+
* @memberOf NgxFormService
|
|
1095
1223
|
*/
|
|
1096
1224
|
static getControlFromForm(formId, path) {
|
|
1097
1225
|
const form = this.formRegistry.get(formId);
|
|
@@ -1104,13 +1232,77 @@ class NgxFormService {
|
|
|
1104
1232
|
throw new Error(`Control with path '${path}' not found in form '${formId}'.`);
|
|
1105
1233
|
return control;
|
|
1106
1234
|
}
|
|
1235
|
+
/**
|
|
1236
|
+
* @description Creates a form from UI model metadata children.
|
|
1237
|
+
* @summary Generates a FormGroup from an array of UIModelMetadata objects, extracting component
|
|
1238
|
+
* properties and creating appropriate form controls. This method is specifically designed to work
|
|
1239
|
+
* with the UI decorator system and provides automatic form generation from metadata.
|
|
1240
|
+
*
|
|
1241
|
+
* @param {string} id - Unique identifier for the form
|
|
1242
|
+
* @param {boolean} [registry=false] - Whether to register the created form in the global registry
|
|
1243
|
+
* @param {UIModelMetadata[]} [children] - Array of UI model metadata objects to create controls from
|
|
1244
|
+
* @return {FormGroup} The created FormGroup with controls for each child metadata
|
|
1245
|
+
*
|
|
1246
|
+
* @mermaid
|
|
1247
|
+
* sequenceDiagram
|
|
1248
|
+
* participant C as Component
|
|
1249
|
+
* participant NFS as NgxFormService
|
|
1250
|
+
* participant AF as Angular Forms
|
|
1251
|
+
*
|
|
1252
|
+
* C->>NFS: createFormFromChildren(id, registry, children)
|
|
1253
|
+
* NFS->>AF: new FormGroup({})
|
|
1254
|
+
* loop For each child metadata
|
|
1255
|
+
* NFS->>NFS: addFormControl(form, child.props)
|
|
1256
|
+
* NFS->>AF: Create and add FormControl
|
|
1257
|
+
* end
|
|
1258
|
+
* alt registry is true
|
|
1259
|
+
* NFS->>NFS: addRegistry(id, form)
|
|
1260
|
+
* end
|
|
1261
|
+
* NFS-->>C: Return FormGroup
|
|
1262
|
+
*
|
|
1263
|
+
* @static
|
|
1264
|
+
* @memberOf NgxFormService
|
|
1265
|
+
*/
|
|
1266
|
+
static createFormFromChildren(id, registry = false, children) {
|
|
1267
|
+
const form = new FormGroup({});
|
|
1268
|
+
if (children?.length)
|
|
1269
|
+
children.forEach(child => {
|
|
1270
|
+
this.addFormControl(form, child.props);
|
|
1271
|
+
});
|
|
1272
|
+
if (registry)
|
|
1273
|
+
this.addRegistry(id, form);
|
|
1274
|
+
return form;
|
|
1275
|
+
}
|
|
1107
1276
|
/**
|
|
1108
1277
|
* @description Creates a form from component configurations.
|
|
1109
1278
|
* @summary Generates a FormGroup based on an array of component configurations and optionally registers it.
|
|
1110
|
-
*
|
|
1111
|
-
*
|
|
1112
|
-
*
|
|
1113
|
-
* @
|
|
1279
|
+
* This method processes component input configurations to create appropriate form controls with
|
|
1280
|
+
* validation and initial values.
|
|
1281
|
+
*
|
|
1282
|
+
* @param {string} id - The unique identifier for the form
|
|
1283
|
+
* @param {IComponentConfig[]} components - An array of component configurations defining the form structure
|
|
1284
|
+
* @param {boolean} [registry=false] - Whether to register the created form in the global registry
|
|
1285
|
+
* @return {FormGroup} The created FormGroup with controls for each component configuration
|
|
1286
|
+
*
|
|
1287
|
+
* @mermaid
|
|
1288
|
+
* sequenceDiagram
|
|
1289
|
+
* participant C as Component
|
|
1290
|
+
* participant NFS as NgxFormService
|
|
1291
|
+
* participant AF as Angular Forms
|
|
1292
|
+
*
|
|
1293
|
+
* C->>NFS: createFormFromComponents(id, components, registry)
|
|
1294
|
+
* NFS->>AF: new FormGroup({})
|
|
1295
|
+
* loop For each component config
|
|
1296
|
+
* NFS->>NFS: addFormControl(form, component.inputs)
|
|
1297
|
+
* NFS->>AF: Create and add FormControl
|
|
1298
|
+
* end
|
|
1299
|
+
* alt registry is true
|
|
1300
|
+
* NFS->>NFS: addRegistry(id, form)
|
|
1301
|
+
* end
|
|
1302
|
+
* NFS-->>C: Return FormGroup
|
|
1303
|
+
*
|
|
1304
|
+
* @static
|
|
1305
|
+
* @memberOf NgxFormService
|
|
1114
1306
|
*/
|
|
1115
1307
|
static createFormFromComponents(id, components, registry = false) {
|
|
1116
1308
|
const form = new FormGroup({});
|
|
@@ -1124,14 +1316,61 @@ class NgxFormService {
|
|
|
1124
1316
|
/**
|
|
1125
1317
|
* @description Adds a control to a form based on component properties.
|
|
1126
1318
|
* @summary Creates and adds a form control to a form (existing or new) based on the provided component properties.
|
|
1127
|
-
*
|
|
1128
|
-
*
|
|
1129
|
-
*
|
|
1319
|
+
* Handles multi-page forms by managing FormArray structures and proper indexing. This method supports
|
|
1320
|
+
* complex form scenarios including nested controls and page-based form organization.
|
|
1321
|
+
*
|
|
1322
|
+
* @param {string} id - The unique identifier of the form
|
|
1323
|
+
* @param {FieldProperties} componentProperties - The properties of the component to create the control from
|
|
1324
|
+
* @param {FieldProperties} [parentProps] - Optional parent properties for context and configuration
|
|
1325
|
+
* @return {AbstractControl} The form or created control
|
|
1326
|
+
*
|
|
1327
|
+
* @mermaid
|
|
1328
|
+
* sequenceDiagram
|
|
1329
|
+
* participant C as Component
|
|
1330
|
+
* participant NFS as NgxFormService
|
|
1331
|
+
* participant F as Form
|
|
1332
|
+
*
|
|
1333
|
+
* C->>NFS: addControlFromProps(id, componentProps, parentProps?)
|
|
1334
|
+
* NFS->>NFS: createForm(id, parentProps, true)
|
|
1335
|
+
* alt Multi-page form (parentProps.pages > 1)
|
|
1336
|
+
* NFS->>NFS: Calculate page index
|
|
1337
|
+
* NFS->>F: Get or create FormGroup at index
|
|
1338
|
+
* NFS->>NFS: Set form to page FormGroup
|
|
1339
|
+
* end
|
|
1340
|
+
* alt componentProperties has path
|
|
1341
|
+
* NFS->>NFS: addFormControl(form, componentProperties, parentProps)
|
|
1342
|
+
* end
|
|
1343
|
+
* NFS-->>C: Return form/control
|
|
1344
|
+
*
|
|
1345
|
+
* @static
|
|
1346
|
+
* @memberOf NgxFormService
|
|
1130
1347
|
*/
|
|
1131
1348
|
static addControlFromProps(id, componentProperties, parentProps) {
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1349
|
+
let form = this.createForm(id, parentProps, true);
|
|
1350
|
+
const formLength = form.length;
|
|
1351
|
+
if (parentProps?.pages && parentProps?.pages > 1) {
|
|
1352
|
+
let index = componentProperties.page || parentProps.page;
|
|
1353
|
+
if (!(typeof index === 'number') || index === 0)
|
|
1354
|
+
throw Error(`Property 'page' is required and greather than 0 on ${componentProperties.name}`);
|
|
1355
|
+
if (index > formLength) {
|
|
1356
|
+
if (form?.['lastIndex'] && index === form['lastIndex']['page']) {
|
|
1357
|
+
index = form['lastIndex']['index'];
|
|
1358
|
+
}
|
|
1359
|
+
else {
|
|
1360
|
+
form['lastIndex'] = {
|
|
1361
|
+
page: index,
|
|
1362
|
+
index: formLength + 1
|
|
1363
|
+
};
|
|
1364
|
+
index = formLength + 1;
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
let group = form.controls[index - 1];
|
|
1368
|
+
if (!group) {
|
|
1369
|
+
group = new FormGroup({});
|
|
1370
|
+
form.insert(index, group);
|
|
1371
|
+
}
|
|
1372
|
+
form = group;
|
|
1373
|
+
}
|
|
1135
1374
|
if (componentProperties.path)
|
|
1136
1375
|
this.addFormControl(form, componentProperties, parentProps);
|
|
1137
1376
|
return form;
|
|
@@ -1139,8 +1378,45 @@ class NgxFormService {
|
|
|
1139
1378
|
/**
|
|
1140
1379
|
* @description Retrieves form data from a FormGroup.
|
|
1141
1380
|
* @summary Extracts and processes the data from a FormGroup, handling different input types and nested form groups.
|
|
1142
|
-
*
|
|
1143
|
-
*
|
|
1381
|
+
* Performs type conversion for various HTML5 input types, validates nested controls, and manages
|
|
1382
|
+
* multiple control scenarios. Automatically enables all group controls after data extraction.
|
|
1383
|
+
*
|
|
1384
|
+
* @param {FormGroup} formGroup - The FormGroup to extract data from
|
|
1385
|
+
* @return {Record<string, unknown>} An object containing the processed form data with proper type conversions
|
|
1386
|
+
*
|
|
1387
|
+
* @mermaid
|
|
1388
|
+
* sequenceDiagram
|
|
1389
|
+
* participant C as Component
|
|
1390
|
+
* participant NFS as NgxFormService
|
|
1391
|
+
* participant FG as FormGroup
|
|
1392
|
+
* participant FC as FormControl
|
|
1393
|
+
*
|
|
1394
|
+
* C->>NFS: getFormData(formGroup)
|
|
1395
|
+
* loop For each control in formGroup
|
|
1396
|
+
* alt Control is not FormControl
|
|
1397
|
+
* NFS->>NFS: Recursive getFormData(control)
|
|
1398
|
+
* alt parentProps.multiple and !isValid
|
|
1399
|
+
* NFS->>NFS: reset(control)
|
|
1400
|
+
* end
|
|
1401
|
+
* else Control is FormControl
|
|
1402
|
+
* NFS->>FC: Get control value
|
|
1403
|
+
* NFS->>NFS: Apply type conversion based on props.type
|
|
1404
|
+
* alt HTML5CheckTypes
|
|
1405
|
+
* NFS->>NFS: Keep boolean value
|
|
1406
|
+
* else NUMBER type
|
|
1407
|
+
* NFS->>NFS: parseToNumber(value)
|
|
1408
|
+
* else DATE/DATETIME types
|
|
1409
|
+
* NFS->>NFS: new Date(value)
|
|
1410
|
+
* else Other types
|
|
1411
|
+
* NFS->>NFS: escapeHtml(value)
|
|
1412
|
+
* end
|
|
1413
|
+
* end
|
|
1414
|
+
* end
|
|
1415
|
+
* NFS->>NFS: enableAllGroupControls(formGroup)
|
|
1416
|
+
* NFS-->>C: Return processed data object
|
|
1417
|
+
*
|
|
1418
|
+
* @static
|
|
1419
|
+
* @memberOf NgxFormService
|
|
1144
1420
|
*/
|
|
1145
1421
|
static getFormData(formGroup) {
|
|
1146
1422
|
const data = {};
|
|
@@ -1185,10 +1461,51 @@ class NgxFormService {
|
|
|
1185
1461
|
/**
|
|
1186
1462
|
* @description Validates fields in a form control or form group.
|
|
1187
1463
|
* @summary Recursively validates all fields in a form control or form group, marking them as touched and dirty.
|
|
1188
|
-
*
|
|
1189
|
-
*
|
|
1190
|
-
*
|
|
1191
|
-
* @
|
|
1464
|
+
* Performs comprehensive validation including uniqueness checks for primary keys in FormArray scenarios.
|
|
1465
|
+
* This method ensures all validation rules are applied and form state is properly updated.
|
|
1466
|
+
*
|
|
1467
|
+
* @param {AbstractControl} control - The control or form group to validate
|
|
1468
|
+
* @param {string} [pk] - Optional primary key field name for uniqueness validation
|
|
1469
|
+
* @param {string} [path] - The path to the control within the form for error reporting
|
|
1470
|
+
* @return {boolean} True if all fields are valid, false otherwise
|
|
1471
|
+
* @throws {Error} If no control is found at the specified path or if the control type is unknown
|
|
1472
|
+
*
|
|
1473
|
+
* @mermaid
|
|
1474
|
+
* sequenceDiagram
|
|
1475
|
+
* participant C as Component
|
|
1476
|
+
* participant NFS as NgxFormService
|
|
1477
|
+
* participant FC as FormControl
|
|
1478
|
+
* participant FG as FormGroup
|
|
1479
|
+
* participant FA as FormArray
|
|
1480
|
+
*
|
|
1481
|
+
* C->>NFS: validateFields(control, pk?, path?)
|
|
1482
|
+
* alt Control is FormControl
|
|
1483
|
+
* NFS->>FC: markAsTouched()
|
|
1484
|
+
* NFS->>FC: markAsDirty()
|
|
1485
|
+
* NFS->>FC: updateValueAndValidity()
|
|
1486
|
+
* alt Is in FormArray group
|
|
1487
|
+
* NFS->>NFS: Check uniqueness in group
|
|
1488
|
+
* alt Not unique
|
|
1489
|
+
* NFS->>FC: setErrors({notUnique: true})
|
|
1490
|
+
* end
|
|
1491
|
+
* end
|
|
1492
|
+
* NFS-->>C: Return control.valid
|
|
1493
|
+
* else Control is FormGroup
|
|
1494
|
+
* loop For each child control
|
|
1495
|
+
* NFS->>NFS: Recursive validateFields(child)
|
|
1496
|
+
* end
|
|
1497
|
+
* NFS-->>C: Return allValid
|
|
1498
|
+
* else Control is FormArray
|
|
1499
|
+
* loop For each array control
|
|
1500
|
+
* NFS->>NFS: Recursive validateFields(child)
|
|
1501
|
+
* end
|
|
1502
|
+
* NFS-->>C: Return allValid
|
|
1503
|
+
* else Unknown control type
|
|
1504
|
+
* NFS-->>C: Throw Error
|
|
1505
|
+
* end
|
|
1506
|
+
*
|
|
1507
|
+
* @static
|
|
1508
|
+
* @memberOf NgxFormService
|
|
1192
1509
|
*/
|
|
1193
1510
|
static validateFields(control, pk, path) {
|
|
1194
1511
|
control = path ? control.get(path) : control;
|
|
@@ -1228,13 +1545,13 @@ class NgxFormService {
|
|
|
1228
1545
|
});
|
|
1229
1546
|
}
|
|
1230
1547
|
}
|
|
1231
|
-
function getControlName(control) {
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
}
|
|
1237
|
-
return
|
|
1548
|
+
// function getControlName(control: AbstractControl): string | null {
|
|
1549
|
+
// const group = control.parent as FormGroup;
|
|
1550
|
+
// if (!group)
|
|
1551
|
+
// return null;
|
|
1552
|
+
// return Object.keys(group.controls).find(name => control === group.get(name)) || null;
|
|
1553
|
+
// }
|
|
1554
|
+
return control.valid;
|
|
1238
1555
|
}
|
|
1239
1556
|
/**
|
|
1240
1557
|
* @description Generates validators from component properties.
|
|
@@ -1252,10 +1569,38 @@ class NgxFormService {
|
|
|
1252
1569
|
}
|
|
1253
1570
|
/**
|
|
1254
1571
|
* @description Creates a FormControl from component properties.
|
|
1255
|
-
* @summary Generates a FormControl with validators based on the provided
|
|
1256
|
-
*
|
|
1257
|
-
*
|
|
1258
|
-
*
|
|
1572
|
+
* @summary Generates a FormControl with validators and initial configuration based on the provided
|
|
1573
|
+
* component properties. Handles different input types, sets initial values, and configures
|
|
1574
|
+
* validation rules and update modes.
|
|
1575
|
+
*
|
|
1576
|
+
* @param {FieldProperties} props - The component properties defining the control configuration
|
|
1577
|
+
* @param {FieldUpdateMode} [updateMode='change'] - The update mode for the control ('change', 'blur', 'submit')
|
|
1578
|
+
* @return {FormControl} The created FormControl with proper configuration and validators
|
|
1579
|
+
*
|
|
1580
|
+
* @mermaid
|
|
1581
|
+
* sequenceDiagram
|
|
1582
|
+
* participant C as Component
|
|
1583
|
+
* participant NFS as NgxFormService
|
|
1584
|
+
* participant VF as ValidatorFactory
|
|
1585
|
+
* participant AF as Angular Forms
|
|
1586
|
+
*
|
|
1587
|
+
* C->>NFS: fromProps(props, updateMode?)
|
|
1588
|
+
* NFS->>NFS: validatorsFromProps(props)
|
|
1589
|
+
* NFS->>VF: Create validators from props
|
|
1590
|
+
* VF-->>NFS: Return validator array
|
|
1591
|
+
* NFS->>NFS: Compose validators
|
|
1592
|
+
* alt props.value exists and not checkbox
|
|
1593
|
+
* alt props.type is DATE
|
|
1594
|
+
* NFS->>NFS: Validate date format
|
|
1595
|
+
* end
|
|
1596
|
+
* NFS->>NFS: Set initial value
|
|
1597
|
+
* end
|
|
1598
|
+
* NFS->>AF: new FormControl(config)
|
|
1599
|
+
* AF-->>NFS: Return FormControl
|
|
1600
|
+
* NFS-->>C: Return configured FormControl
|
|
1601
|
+
*
|
|
1602
|
+
* @static
|
|
1603
|
+
* @memberOf NgxFormService
|
|
1259
1604
|
*/
|
|
1260
1605
|
static fromProps(props, updateMode = 'change') {
|
|
1261
1606
|
const validators = this.validatorsFromProps(props);
|
|
@@ -1273,21 +1618,50 @@ class NgxFormService {
|
|
|
1273
1618
|
});
|
|
1274
1619
|
}
|
|
1275
1620
|
/**
|
|
1276
|
-
* @description Retrieves properties from a FormControl.
|
|
1277
|
-
* @summary Gets the FieldProperties associated with a
|
|
1278
|
-
*
|
|
1279
|
-
*
|
|
1621
|
+
* @description Retrieves properties from a FormControl, FormArray, or FormGroup.
|
|
1622
|
+
* @summary Gets the FieldProperties associated with a form control from the internal WeakMap.
|
|
1623
|
+
* This method provides access to the original component properties that were used to create
|
|
1624
|
+
* the control, enabling validation, rendering, and behavior configuration.
|
|
1625
|
+
*
|
|
1626
|
+
* @param {FormControl | FormArray | FormGroup} control - The form control to get properties for
|
|
1627
|
+
* @return {FieldProperties} The properties associated with the control, or empty object if not found
|
|
1628
|
+
*
|
|
1629
|
+
* @static
|
|
1630
|
+
* @memberOf NgxFormService
|
|
1280
1631
|
*/
|
|
1281
1632
|
static getPropsFromControl(control) {
|
|
1282
1633
|
return this.controls.get(control) || {};
|
|
1283
1634
|
}
|
|
1284
1635
|
/**
|
|
1285
|
-
* @description Finds a parent element with a specific tag.
|
|
1286
|
-
* @summary Traverses up the DOM tree to find the nearest parent element with the specified tag.
|
|
1287
|
-
*
|
|
1288
|
-
*
|
|
1289
|
-
*
|
|
1290
|
-
* @
|
|
1636
|
+
* @description Finds a parent element with a specific tag in the DOM tree.
|
|
1637
|
+
* @summary Traverses up the DOM tree to find the nearest parent element with the specified tag name.
|
|
1638
|
+
* This is useful for finding container elements or specific parent components in the DOM hierarchy.
|
|
1639
|
+
* The search is case-insensitive for tag name matching.
|
|
1640
|
+
*
|
|
1641
|
+
* @param {HTMLElement} el - The starting element to traverse from
|
|
1642
|
+
* @param {string} tag - The tag name to search for (case-insensitive)
|
|
1643
|
+
* @return {HTMLElement} The found parent element with the specified tag
|
|
1644
|
+
* @throws {Error} If no parent with the specified tag is found in the DOM tree
|
|
1645
|
+
*
|
|
1646
|
+
* @mermaid
|
|
1647
|
+
* sequenceDiagram
|
|
1648
|
+
* participant C as Component
|
|
1649
|
+
* participant NFS as NgxFormService
|
|
1650
|
+
* participant DOM as DOM Tree
|
|
1651
|
+
*
|
|
1652
|
+
* C->>NFS: getParentEl(element, tagName)
|
|
1653
|
+
* loop Traverse up DOM tree
|
|
1654
|
+
* NFS->>DOM: Get parentElement
|
|
1655
|
+
* DOM-->>NFS: Return parent or null
|
|
1656
|
+
* alt Parent exists and tag matches
|
|
1657
|
+
* NFS-->>C: Return parent element
|
|
1658
|
+
* else Parent is null
|
|
1659
|
+
* NFS-->>C: Throw Error
|
|
1660
|
+
* end
|
|
1661
|
+
* end
|
|
1662
|
+
*
|
|
1663
|
+
* @static
|
|
1664
|
+
* @memberOf NgxFormService
|
|
1291
1665
|
*/
|
|
1292
1666
|
static getParentEl(el, tag) {
|
|
1293
1667
|
let parent;
|
|
@@ -1300,10 +1674,17 @@ class NgxFormService {
|
|
|
1300
1674
|
throw new Error(`No parent with the tag ${tag} was found for provided element`);
|
|
1301
1675
|
}
|
|
1302
1676
|
/**
|
|
1303
|
-
* @description Registers a control with its properties.
|
|
1304
|
-
* @summary Associates a control with its properties
|
|
1305
|
-
*
|
|
1306
|
-
*
|
|
1677
|
+
* @description Registers a control with its properties in the internal WeakMap.
|
|
1678
|
+
* @summary Associates a form control with its component properties for later retrieval.
|
|
1679
|
+
* This enables the service to maintain metadata about controls without creating memory leaks,
|
|
1680
|
+
* as WeakMap automatically cleans up references when controls are garbage collected.
|
|
1681
|
+
*
|
|
1682
|
+
* @param {AbstractControl} control - The control to register (FormControl, FormGroup, or FormArray)
|
|
1683
|
+
* @param {FieldProperties} props - The properties to associate with the control
|
|
1684
|
+
* @return {void}
|
|
1685
|
+
*
|
|
1686
|
+
* @static
|
|
1687
|
+
* @memberOf NgxFormService
|
|
1307
1688
|
*/
|
|
1308
1689
|
static register(control, props) {
|
|
1309
1690
|
this.controls.set(control, props);
|
|
@@ -1391,6 +1772,8 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
1391
1772
|
* @type {string | undefined}
|
|
1392
1773
|
*/
|
|
1393
1774
|
static { this._operation = undefined; }
|
|
1775
|
+
static { this._projectable = true; }
|
|
1776
|
+
static { this._parentProps = undefined; }
|
|
1394
1777
|
/**
|
|
1395
1778
|
* @description Constructs a new NgxRenderingEngine instance
|
|
1396
1779
|
* @summary Initializes a new instance of the Angular rendering engine by calling the parent
|
|
@@ -1459,7 +1842,6 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
1459
1842
|
const hiddenOn = inputs?.hidden || [];
|
|
1460
1843
|
if (hiddenOn.includes(operation))
|
|
1461
1844
|
return { inputs, injector };
|
|
1462
|
-
// const hiddenOn = inputs?.hidden || [];
|
|
1463
1845
|
const result = {
|
|
1464
1846
|
component,
|
|
1465
1847
|
inputs,
|
|
@@ -1469,6 +1851,8 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
1469
1851
|
result.inputs['rendererId'] = fieldDef.rendererId;
|
|
1470
1852
|
// process children
|
|
1471
1853
|
if (fieldDef.children?.length) {
|
|
1854
|
+
if (!NgxRenderingEngine._parentProps && inputs?.pages)
|
|
1855
|
+
NgxRenderingEngine._parentProps = { pages: inputs?.pages };
|
|
1472
1856
|
result.children = fieldDef.children.map((child) => {
|
|
1473
1857
|
if (child?.children?.length) {
|
|
1474
1858
|
child.children = child.children.filter(c => {
|
|
@@ -1477,15 +1861,18 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
1477
1861
|
return c;
|
|
1478
1862
|
});
|
|
1479
1863
|
}
|
|
1480
|
-
|
|
1481
|
-
NgxFormService.addControlFromProps(registryFormId, child.props, inputs);
|
|
1864
|
+
NgxFormService.addControlFromProps(registryFormId, child.props, { ...inputs, ...NgxRenderingEngine._parentProps || {} });
|
|
1482
1865
|
return this.fromFieldDefinition(child, vcr, injector, tpl, registryFormId);
|
|
1483
1866
|
});
|
|
1484
1867
|
}
|
|
1485
1868
|
// generating DOM
|
|
1869
|
+
const projectable = NgxRenderingEngine._projectable;
|
|
1486
1870
|
vcr.clear();
|
|
1487
|
-
const template = vcr.createEmbeddedView(tpl, injector).rootNodes;
|
|
1488
|
-
const
|
|
1871
|
+
const template = !projectable ? [] : vcr.createEmbeddedView(tpl, injector).rootNodes;
|
|
1872
|
+
const hasChildren = Object.values(possibleInputs).some(({ propName }) => propName === 'children');
|
|
1873
|
+
const hasModel = Object.values(possibleInputs).some(({ propName }) => propName === 'children');
|
|
1874
|
+
const componentInputs = Object.assign(inputs, (hasModel ? { model: this._model } : {}), (hasChildren ? { children: fieldDef?.['children'] || [] } : {}));
|
|
1875
|
+
const componentInstance = NgxRenderingEngine.createComponent(component, componentInputs, componentMetadata, vcr, injector, template);
|
|
1489
1876
|
result.instance = NgxRenderingEngine._instance = componentInstance.instance;
|
|
1490
1877
|
return result;
|
|
1491
1878
|
}
|
|
@@ -1533,8 +1920,11 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
1533
1920
|
*
|
|
1534
1921
|
* @return {Promise<void>} A promise that resolves when the instance is destroyed
|
|
1535
1922
|
*/
|
|
1536
|
-
static async destroy() {
|
|
1923
|
+
static async destroy(formId) {
|
|
1924
|
+
if (formId)
|
|
1925
|
+
NgxFormService.removeRegistry(formId);
|
|
1537
1926
|
NgxRenderingEngine._instance = undefined;
|
|
1927
|
+
NgxRenderingEngine._parentProps = undefined;
|
|
1538
1928
|
}
|
|
1539
1929
|
/**
|
|
1540
1930
|
* @description Renders a model into an Angular component output
|
|
@@ -1566,18 +1956,20 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
1566
1956
|
* FromField-->>Render: AngularDynamicOutput
|
|
1567
1957
|
* Render-->>Client: return AngularDynamicOutput
|
|
1568
1958
|
*/
|
|
1569
|
-
render(model, globalProps, vcr, injector, tpl) {
|
|
1959
|
+
render(model, globalProps, vcr, injector, tpl, projectable = true) {
|
|
1570
1960
|
let result;
|
|
1571
1961
|
try {
|
|
1572
1962
|
this._model = model;
|
|
1963
|
+
NgxRenderingEngine._projectable = projectable;
|
|
1573
1964
|
const formId = Date.now().toString(36).toUpperCase();
|
|
1574
1965
|
const fieldDef = this.toFieldDefinition(model, globalProps);
|
|
1575
1966
|
const props = fieldDef.props;
|
|
1576
1967
|
if (!NgxRenderingEngine._operation)
|
|
1577
1968
|
NgxRenderingEngine._operation = props?.['operation'] || undefined;
|
|
1969
|
+
const formGroup = NgxFormService.createForm(formId, props);
|
|
1578
1970
|
result = this.fromFieldDefinition(fieldDef, vcr, injector, tpl, formId);
|
|
1579
|
-
result.instance['formGroup'] =
|
|
1580
|
-
|
|
1971
|
+
result.instance['formGroup'] = formGroup;
|
|
1972
|
+
NgxRenderingEngine.destroy(formId);
|
|
1581
1973
|
}
|
|
1582
1974
|
catch (e) {
|
|
1583
1975
|
throw new InternalError(`Failed to render Model ${model.constructor.name}: ${e}`);
|
|
@@ -1774,6 +2166,7 @@ class ComponentRendererComponent {
|
|
|
1774
2166
|
* @memberOf ComponentRendererComponent
|
|
1775
2167
|
*/
|
|
1776
2168
|
this.injector = inject(EnvironmentInjector);
|
|
2169
|
+
this.children = [];
|
|
1777
2170
|
/**
|
|
1778
2171
|
* @description Event emitter for events from the rendered component.
|
|
1779
2172
|
* @summary This output property emits events that originate from the dynamically rendered
|
|
@@ -1884,6 +2277,8 @@ class ComponentRendererComponent {
|
|
|
1884
2277
|
const props = globals?.['item'] || globals?.['props'] || {};
|
|
1885
2278
|
if (props?.['tag'])
|
|
1886
2279
|
delete props['tag'];
|
|
2280
|
+
if (props?.['children'] && !this.children.length)
|
|
2281
|
+
this.children = props['children'];
|
|
1887
2282
|
const inputKeys = Object.keys(props);
|
|
1888
2283
|
const unmappedKeys = [];
|
|
1889
2284
|
for (const input of inputKeys) {
|
|
@@ -1896,7 +2291,8 @@ class ComponentRendererComponent {
|
|
|
1896
2291
|
}
|
|
1897
2292
|
}
|
|
1898
2293
|
this.vcr.clear();
|
|
1899
|
-
|
|
2294
|
+
const template = this.children?.length ? this.vcr.createEmbeddedView(this.inner, this.injector).rootNodes : [];
|
|
2295
|
+
this.component = NgxRenderingEngine.createComponent(component, props, metadata, this.vcr, this.injector, template);
|
|
1900
2296
|
this.subscribeEvents();
|
|
1901
2297
|
}
|
|
1902
2298
|
createParentComponent() {
|
|
@@ -1987,11 +2383,11 @@ class ComponentRendererComponent {
|
|
|
1987
2383
|
}
|
|
1988
2384
|
}
|
|
1989
2385
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1990
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ComponentRendererComponent, isStandalone: true, selector: "ngx-decaf-component-renderer", inputs: { tag: "tag", globals: "globals", model: "model", parent: "parent" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "
|
|
2386
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ComponentRendererComponent, isStandalone: true, selector: "ngx-decaf-component-renderer", inputs: { tag: "tag", globals: "globals", children: "children", model: "model", parent: "parent" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "vcr", first: true, predicate: ["componentViewContainer"], descendants: true, read: ViewContainerRef, static: true }, { propertyName: "inner", first: true, predicate: ["inner"], descendants: true, read: TemplateRef, static: true }], ngImport: i0, template: "<!-- Keep to avoid id conflicts -->\n<div [id]=\"uid\"></div>\n\n<ng-template #componentViewContainer></ng-template>\n<ng-template #inner>\n @if(parent?.children?.length) {\n @for(child of parent.children; track child) {\n @if(!child.children?.length) {\n <ng-container\n *ngComponentOutlet=\"\n child.component;\n injector: child.injector;\n inputs: child.inputs;\n content:child.content;\n \"\n />\n } @else {\n <ngx-decaf-component-renderer [parent]=\"child\"> </ngx-decaf-component-renderer>\n }\n }\n }\n @if(children?.length) {\n @for(child of children; track child) {\n @if(child.children?.length) {\n <ngx-decaf-component-renderer [parent]=\"child\"> </ngx-decaf-component-renderer>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\" />\n }\n }\n }\n</ng-template>\n\n\n", styles: [""], dependencies: [{ kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }] }); }
|
|
1991
2387
|
}
|
|
1992
2388
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ComponentRendererComponent, decorators: [{
|
|
1993
2389
|
type: Component,
|
|
1994
|
-
args: [{ selector: 'ngx-decaf-component-renderer', imports: [NgComponentOutlet], standalone: true, host: { '[attr.id]': '
|
|
2390
|
+
args: [{ selector: 'ngx-decaf-component-renderer', imports: [NgComponentOutlet], standalone: true, host: { '[attr.id]': 'uid' }, template: "<!-- Keep to avoid id conflicts -->\n<div [id]=\"uid\"></div>\n\n<ng-template #componentViewContainer></ng-template>\n<ng-template #inner>\n @if(parent?.children?.length) {\n @for(child of parent.children; track child) {\n @if(!child.children?.length) {\n <ng-container\n *ngComponentOutlet=\"\n child.component;\n injector: child.injector;\n inputs: child.inputs;\n content:child.content;\n \"\n />\n } @else {\n <ngx-decaf-component-renderer [parent]=\"child\"> </ngx-decaf-component-renderer>\n }\n }\n }\n @if(children?.length) {\n @for(child of children; track child) {\n @if(child.children?.length) {\n <ngx-decaf-component-renderer [parent]=\"child\"> </ngx-decaf-component-renderer>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\" />\n }\n }\n }\n</ng-template>\n\n\n" }]
|
|
1995
2391
|
}], ctorParameters: () => [], propDecorators: { vcr: [{
|
|
1996
2392
|
type: ViewChild,
|
|
1997
2393
|
args: ['componentViewContainer', { static: true, read: ViewContainerRef }]
|
|
@@ -2000,6 +2396,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2000
2396
|
args: [{ required: true }]
|
|
2001
2397
|
}], globals: [{
|
|
2002
2398
|
type: Input
|
|
2399
|
+
}], children: [{
|
|
2400
|
+
type: Input
|
|
2003
2401
|
}], listenEvent: [{
|
|
2004
2402
|
type: Output
|
|
2005
2403
|
}], model: [{
|
|
@@ -2117,24 +2515,26 @@ class NgxCrudFormField {
|
|
|
2117
2515
|
*/
|
|
2118
2516
|
getErrors(parent) {
|
|
2119
2517
|
const formControl = this.formControl;
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
key
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
if (
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2518
|
+
if (formControl) {
|
|
2519
|
+
const accordionComponent = parent.closest('ngx-decaf-fieldset')?.querySelector('ion-accordion-group');
|
|
2520
|
+
if ((!formControl.pristine || formControl.touched) && !formControl.valid) {
|
|
2521
|
+
const errors = Object.keys(formControl.errors ?? {}).map(key => ({
|
|
2522
|
+
key: key,
|
|
2523
|
+
message: key,
|
|
2524
|
+
}));
|
|
2525
|
+
if (errors.length) {
|
|
2526
|
+
if (accordionComponent && !this.validationErrorEventDispateched) {
|
|
2527
|
+
const validationErrorEvent = new CustomEvent(EventConstants.VALIDATION_ERROR, {
|
|
2528
|
+
detail: { fieldName: this.name, hasErrors: true },
|
|
2529
|
+
bubbles: true
|
|
2530
|
+
});
|
|
2531
|
+
accordionComponent.dispatchEvent(validationErrorEvent);
|
|
2532
|
+
this.validationErrorEventDispateched = true;
|
|
2533
|
+
}
|
|
2134
2534
|
}
|
|
2535
|
+
for (const error of errors)
|
|
2536
|
+
return `* ${this.sf(this.translateService.instant(`errors.${error?.['message']}`), this[error?.['key']] ?? "")}`;
|
|
2135
2537
|
}
|
|
2136
|
-
for (const error of errors)
|
|
2137
|
-
return `* ${this.sf(this.translateService.instant(`errors.${error?.['message']}`), this[error?.['key']] ?? "")}`;
|
|
2138
2538
|
}
|
|
2139
2539
|
}
|
|
2140
2540
|
}
|
|
@@ -2408,6 +2808,15 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxCrudFormField {
|
|
|
2408
2808
|
* @memberOf CrudFieldComponent
|
|
2409
2809
|
*/
|
|
2410
2810
|
this.value = '';
|
|
2811
|
+
/**
|
|
2812
|
+
* @description Whether the field should be hidden.
|
|
2813
|
+
* @summary When true, the field will not be visible in the UI but will still be part of the form model.
|
|
2814
|
+
* This is useful for fields that need to be included in form submission but should not be displayed to the user.
|
|
2815
|
+
*
|
|
2816
|
+
* @type {boolean}
|
|
2817
|
+
* @memberOf CrudFieldComponent
|
|
2818
|
+
*/
|
|
2819
|
+
this.hidden = false;
|
|
2411
2820
|
/**
|
|
2412
2821
|
* @description Interface style for select inputs.
|
|
2413
2822
|
* @summary Specifies the interface style for select inputs, such as 'alert', 'action-sheet', or 'popover'.
|
|
@@ -2688,7 +3097,7 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxCrudFormField {
|
|
|
2688
3097
|
component.dispatchEvent(event);
|
|
2689
3098
|
}
|
|
2690
3099
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CrudFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
2691
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: CrudFieldComponent, isStandalone: true, selector: "ngx-decaf-crud-field", inputs: { operation: "operation", name: "name", path: "path", childOf: "childOf", type: "type", value: "value", disabled: "disabled", label: "label", placeholder: "placeholder", format: "format", hidden: "hidden", max: "max", maxlength: "maxlength", min: "min", minlength: "minlength", pattern: "pattern", readonly: "readonly", required: "required", step: "step", equals: "equals", different: "different", lessThan: "lessThan", lessThanOrEqual: "lessThanOrEqual", greaterThan: "greaterThan", greaterThanOrEqual: "greaterThanOrEqual", cols: "cols", rows: "rows", alignment: "alignment", checked: "checked", justify: "justify", cancelText: "cancelText", interface: "interface", options: "options", mode: "mode", spellcheck: "spellcheck", inputmode: "inputmode", autocomplete: "autocomplete", fill: "fill", labelPlacement: "labelPlacement", updateOn: "updateOn", formGroup: "formGroup", formControl: "formControl", multiple: "multiple", uid: "uid", translatable: "translatable", activeFormGroup: "activeFormGroup", pk: "pk" }, host: { listeners: { "window:fieldsetAddGroupEvent": "handleFieldsetCreateGroupEvent($event)", "window:fieldsetUpdateGroupEvent": "handleFieldsetUpdateGroupEvent($event)", "window:fieldsetRemoveGroupEvent": "handleFieldsetRemoveGroupEvent($event)" }, properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "@if(operation === 'read' || operation === 'delete') {\n <ng-container #component>\n <div [class]=\"'dcf-input-item ' + operation\">\n <ion-item>\n <ion-label>\n {{ label | translate }}<br />\n @if(value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n <br />\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n <ng-container [formGroup]=\"getActiveFormGroup\">\n <div #container [class]=\"'dcf-input-item ' + (operation || 'create')\" (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\">\n @if(type === 'textarea') {\n <ion-textarea\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [required]=\"required !== undefined ? required : null\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [inputmode]=\"inputmode\"\n [spellcheck]=\"spellcheck\"\n [rows]=\"rows\"\n [labelPlacement]=\"labelPlacement\"\n [value]=\"value\"\n [fill]=\"fill\"\n [errorText]=\"getErrors(container)\"\n [placeholder]=\"translatable ? (placeholder | translate) : placeholder\"\n [formControlName]=\"name\"\n [label]=\"translatable ? (label | translate) : label\"\n #component>\n </ion-textarea>\n }\n @else if(type === 'checkbox') {\n <ion-item>\n <ion-checkbox\n #checkboxElement\n\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span [innerHTML]=\"label | translate\"></span>\n </ion-checkbox>\n </ion-item>\n }\n @else if(type === 'radio') {\n <ion-radio-group [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track option) {\n <ion-item>\n <ion-radio\n [errorText]=\"getErrors(container)\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ translatable ? (option?.text | translate) : option?.text }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"translatable ? (label | translate) : label\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"translatable ? (placeholder | translate) : placeholder\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @for(option of options; track option.value) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n </ion-select>\n }\n @else {\n <ion-input\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [required]=\"required !== undefined ? required : false\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [max]=\"max !== undefined ? max : null\"\n [min]=\"min !== undefined ? min : null\"\n [pattern]=\"pattern !== undefined ? pattern : null\"\n [step]=\"step !== undefined ? step : null\"\n [fill]=\"fill\"\n [placeholder]=\"translatable ? (placeholder | translate) : placeholder\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [label]=\"translatable ? (label | translate) : label\" #component />\n }\n </div>\n </ng-container>\n}\n\n", styles: [".dcf-input-item.create,.dcf-input-item.update{margin-bottom:1.8rem;margin-top:0!important}.dcf-input-item.create.checkbox+.checkbox,.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}.dcf-input-item.create ion-item,.dcf-input-item.update ion-item{--border-color: transparent}.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)}}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item ion-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}@media (prefers-color-scheme: light){.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}}.dcf-input-item ion-item span,.dcf-input-item ion-item ion-text{font-weight:400!important;font-size:.925rem;min-height:.5rem!important}.dcf-input-item ion-item span:not(.dcf-display-block),.dcf-input-item ion-item ion-text:not(.dcf-display-block){display:inline-block}.dcf-input-item ion-item span.dcf-display-block,.dcf-input-item ion-item ion-text.dcf-display-block{display:block!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-item{--inner-padding-start: .75rem}ion-checkbox::part(container){border-radius:50%;padding:3px}@media (prefers-color-scheme: light){ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}ion-item .dcf-radio-group-label,ion-radio-group .dcf-radio-group-label{font-weight:600}ion-item .dcf-radio-group-label~ion-item,ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-item+.dcf-helper,ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:600!important;line-height:1.1rem;box-sizing:border-box;z-index:9999;margin-top:0;animation-duration:.1s;animation-timing-function:ease-out;animation-fill-mode:both;animation-name:fadeTopSmallAnimation;display:flex;align-items:flex-start;gap:.25rem}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;color:var(--dcf-color-gray-7)!important;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}@keyframes fadeTopSmallAnimation{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeBottomSmallAnimation{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeTopMediumAnimation{0%{opacity:0;transform:translateY(-50px)}to{opacity:1;transform:translateY(0)}}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonRadioGroup, selector: "ion-radio-group", inputs: ["allowEmptySelection", "compareWith", "errorText", "helperText", "name", "value"] }, { kind: "component", type: IonRadio, selector: "ion-radio", inputs: ["alignment", "color", "disabled", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }] }); }
|
|
3100
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: CrudFieldComponent, isStandalone: true, selector: "ngx-decaf-crud-field", inputs: { operation: "operation", name: "name", path: "path", childOf: "childOf", type: "type", value: "value", disabled: "disabled", label: "label", placeholder: "placeholder", format: "format", hidden: "hidden", max: "max", maxlength: "maxlength", min: "min", minlength: "minlength", pattern: "pattern", readonly: "readonly", required: "required", step: "step", equals: "equals", different: "different", lessThan: "lessThan", lessThanOrEqual: "lessThanOrEqual", greaterThan: "greaterThan", greaterThanOrEqual: "greaterThanOrEqual", cols: "cols", rows: "rows", alignment: "alignment", checked: "checked", justify: "justify", cancelText: "cancelText", interface: "interface", options: "options", mode: "mode", spellcheck: "spellcheck", inputmode: "inputmode", autocomplete: "autocomplete", fill: "fill", labelPlacement: "labelPlacement", updateOn: "updateOn", formGroup: "formGroup", formControl: "formControl", multiple: "multiple", uid: "uid", page: "page", translatable: "translatable", activeFormGroup: "activeFormGroup", pk: "pk" }, host: { listeners: { "window:fieldsetAddGroupEvent": "handleFieldsetCreateGroupEvent($event)", "window:fieldsetUpdateGroupEvent": "handleFieldsetUpdateGroupEvent($event)", "window:fieldsetRemoveGroupEvent": "handleFieldsetRemoveGroupEvent($event)" }, properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "@if(operation === 'read' || operation === 'delete') {\n <ng-container #component>\n <div [class]=\"'dcf-input-item ' + operation\">\n <ion-item>\n <ion-label>\n {{ label | translate }}<br />\n @if(value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n <br />\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n <ng-container [formGroup]=\"getActiveFormGroup\">\n <div #container [class]=\"'dcf-input-item ' + (operation || 'create')\" (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\">\n @if(type === 'textarea') {\n <ion-textarea\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [required]=\"required !== undefined ? required : null\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [inputmode]=\"inputmode\"\n [spellcheck]=\"spellcheck\"\n [rows]=\"rows\"\n [labelPlacement]=\"labelPlacement\"\n [value]=\"value\"\n [fill]=\"fill\"\n [errorText]=\"getErrors(container)\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [label]=\"label | translate\"\n #component>\n </ion-textarea>\n }\n @else if(type === 'checkbox') {\n <ion-item>\n <ion-checkbox\n #checkboxElement\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span [innerHTML]=\"label | translate\"></span>\n </ion-checkbox>\n </ion-item>\n }\n @else if(type === 'radio') {\n <ion-radio-group [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track option) {\n <ion-item>\n <ion-radio\n [errorText]=\"getErrors(container)\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ translatable ? (option?.text | translate) : option?.text }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"translatable ? (label | translate) : label\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @for(option of options; track option.value) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n </ion-select>\n }\n @else {\n <ion-input\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [required]=\"required !== undefined ? required : false\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [max]=\"max !== undefined ? max : null\"\n [min]=\"min !== undefined ? min : null\"\n [pattern]=\"pattern !== undefined ? pattern : null\"\n [step]=\"step !== undefined ? step : null\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [label]=\"label | translate\" #component />\n }\n </div>\n </ng-container>\n}\n\n", styles: [".dcf-input-item.create,.dcf-input-item.update{margin-bottom:1.8rem;margin-top:0!important}.dcf-input-item.create.checkbox+.checkbox,.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}.dcf-input-item.create ion-item,.dcf-input-item.update ion-item{--border-color: transparent}.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)}}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item ion-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}@media (prefers-color-scheme: light){.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}}.dcf-input-item ion-item span,.dcf-input-item ion-item ion-text{font-weight:400!important;font-size:.925rem;min-height:.5rem!important}.dcf-input-item ion-item span:not(.dcf-display-block),.dcf-input-item ion-item ion-text:not(.dcf-display-block){display:inline-block}.dcf-input-item ion-item span.dcf-display-block,.dcf-input-item ion-item ion-text.dcf-display-block{display:block!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-item{--inner-padding-start: .75rem}ion-checkbox::part(container){border-radius:50%;padding:3px}@media (prefers-color-scheme: light){ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}ion-item .dcf-radio-group-label,ion-radio-group .dcf-radio-group-label{font-weight:600}ion-item .dcf-radio-group-label~ion-item,ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-item+.dcf-helper,ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:600!important;line-height:1.1rem;box-sizing:border-box;z-index:9999;margin-top:0;animation-duration:.1s;animation-timing-function:ease-out;animation-fill-mode:both;animation-name:fadeTopSmallAnimation;display:flex;align-items:flex-start;gap:.25rem}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;color:var(--dcf-color-gray-7)!important;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}@keyframes fadeTopSmallAnimation{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeBottomSmallAnimation{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeTopMediumAnimation{0%{opacity:0;transform:translateY(-50px)}to{opacity:1;transform:translateY(0)}}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonRadioGroup, selector: "ion-radio-group", inputs: ["allowEmptySelection", "compareWith", "errorText", "helperText", "name", "value"] }, { kind: "component", type: IonRadio, selector: "ion-radio", inputs: ["alignment", "color", "disabled", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }] }); }
|
|
2692
3101
|
};
|
|
2693
3102
|
CrudFieldComponent = __decorate([
|
|
2694
3103
|
Dynamic()
|
|
@@ -2709,7 +3118,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2709
3118
|
IonText,
|
|
2710
3119
|
IonTextarea,
|
|
2711
3120
|
IonIcon
|
|
2712
|
-
], selector: 'ngx-decaf-crud-field', schemas: [CUSTOM_ELEMENTS_SCHEMA], host: { '[attr.id]': 'uid' }, template: "@if(operation === 'read' || operation === 'delete') {\n <ng-container #component>\n <div [class]=\"'dcf-input-item ' + operation\">\n <ion-item>\n <ion-label>\n {{ label | translate }}<br />\n @if(value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n <br />\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n <ng-container [formGroup]=\"getActiveFormGroup\">\n <div #container [class]=\"'dcf-input-item ' + (operation || 'create')\" (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\">\n @if(type === 'textarea') {\n <ion-textarea\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [required]=\"required !== undefined ? required : null\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [inputmode]=\"inputmode\"\n [spellcheck]=\"spellcheck\"\n [rows]=\"rows\"\n [labelPlacement]=\"labelPlacement\"\n [value]=\"value\"\n [fill]=\"fill\"\n [errorText]=\"getErrors(container)\"\n [placeholder]=\"
|
|
3121
|
+
], selector: 'ngx-decaf-crud-field', schemas: [CUSTOM_ELEMENTS_SCHEMA], host: { '[attr.id]': 'uid' }, template: "@if(operation === 'read' || operation === 'delete') {\n <ng-container #component>\n <div [class]=\"'dcf-input-item ' + operation\">\n <ion-item>\n <ion-label>\n {{ label | translate }}<br />\n @if(value) {\n <ion-text [innerHTML]=\"type === 'password' ? '********' : value\"></ion-text>\n } @else {\n <br />\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n <ng-container [formGroup]=\"getActiveFormGroup\">\n <div #container [class]=\"'dcf-input-item ' + (operation || 'create')\" (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\">\n @if(type === 'textarea') {\n <ion-textarea\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\n [required]=\"required !== undefined ? required : null\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [inputmode]=\"inputmode\"\n [spellcheck]=\"spellcheck\"\n [rows]=\"rows\"\n [labelPlacement]=\"labelPlacement\"\n [value]=\"value\"\n [fill]=\"fill\"\n [errorText]=\"getErrors(container)\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [label]=\"label | translate\"\n #component>\n </ion-textarea>\n }\n @else if(type === 'checkbox') {\n <ion-item>\n <ion-checkbox\n #checkboxElement\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span [innerHTML]=\"label | translate\"></span>\n </ion-checkbox>\n </ion-item>\n }\n @else if(type === 'radio') {\n <ion-radio-group [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track option) {\n <ion-item>\n <ion-radio\n [errorText]=\"getErrors(container)\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [alignment]=\"alignment\"\n [justify]=\"justify\"\n [readonly]=\"readonly\"\n [value]=\"option.value\"\n >{{ translatable ? (option?.text | translate) : option?.text }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"translatable ? (label | translate) : label\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @for(option of options; track option.value) {\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n </ion-select>\n }\n @else {\n <ion-input\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\n [required]=\"required !== undefined ? required : false\"\n [minlength]=\"minlength !== undefined ? minlength : null\"\n [maxlength]=\"maxlength !== undefined ? maxlength : null\"\n [readonly]=\"readonly !== undefined ? readonly : null\"\n [max]=\"max !== undefined ? max : null\"\n [min]=\"min !== undefined ? min : null\"\n [pattern]=\"pattern !== undefined ? pattern : null\"\n [step]=\"step !== undefined ? step : null\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [label]=\"label | translate\" #component />\n }\n </div>\n </ng-container>\n}\n\n", styles: [".dcf-input-item.create,.dcf-input-item.update{margin-bottom:1.8rem;margin-top:0!important}.dcf-input-item.create.checkbox+.checkbox,.dcf-input-item.update.checkbox+.checkbox{margin-top:-.25rem!important}.dcf-input-item.create ion-item,.dcf-input-item.update ion-item{--border-color: transparent}.dcf-input-item.create ion-item.dcf-text-wrap ion-label>*,.dcf-input-item.update ion-item.dcf-text-wrap ion-label>*{white-space:wrap!important;word-break:break-all!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)}}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item ion-item{--padding-end: 0rem;--padding-start: 0px !important;--padding-top: 0px !important;--background: transparent;--background-hover-opacity: .1;--background-activated-opacity: .15;--background-focused-opacity: .15}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}@media (prefers-color-scheme: light){.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}}.dcf-input-item ion-item span,.dcf-input-item ion-item ion-text{font-weight:400!important;font-size:.925rem;min-height:.5rem!important}.dcf-input-item ion-item span:not(.dcf-display-block),.dcf-input-item ion-item ion-text:not(.dcf-display-block){display:inline-block}.dcf-input-item ion-item span.dcf-display-block,.dcf-input-item ion-item ion-text.dcf-display-block{display:block!important}ion-textarea textarea{scrollbar-width:thin!important;margin-bottom:.5rem!important}ion-select.dcf-select-label-placement-floating::part(label){line-height:1.2rem!important}.dcf-proccessing,.dcf-proccessing *{pointer-events:none;touch-action:none;cursor:text}ion-checkbox{--size: 1.5rem;--checkbox-background-checked: var(--dcf-color-primary);--checkmark-width: 2px}ion-item{--inner-padding-start: .75rem}ion-checkbox::part(container){border-radius:50%;padding:3px}@media (prefers-color-scheme: light){ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}ion-item .dcf-radio-group-label,ion-radio-group .dcf-radio-group-label{font-weight:600}ion-item .dcf-radio-group-label~ion-item,ion-radio-group .dcf-radio-group-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}ion-item+.dcf-helper,ion-radio-group+.dcf-helper{padding-left:.75rem;position:relative}.dcf-error{position:absolute;color:var(--dcf-color-danger)!important;font-size:.8rem!important;font-weight:600!important;line-height:1.1rem;box-sizing:border-box;z-index:9999;margin-top:0;animation-duration:.1s;animation-timing-function:ease-out;animation-fill-mode:both;animation-name:fadeTopSmallAnimation;display:flex;align-items:flex-start;gap:.25rem}.dcf-error .ti,.dcf-error ion-icon{position:relative;top:2px!important;min-width:20px;font-size:1rem!important;text-align:left}.dcf-helper{font-size:.875rem!important;font-weight:500;margin-top:.25rem;margin-bottom:-.75rem}.dcf-helper.dcf-has-action{cursor:pointer;color:var(--dcf-color-gray-7)!important;text-decoration:underline}.dcf-error+.dcf-helper{padding-top:1rem}@keyframes fadeTopSmallAnimation{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeBottomSmallAnimation{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeTopMediumAnimation{0%{opacity:0;transform:translateY(-50px)}to{opacity:1;transform:translateY(0)}}::ng-deep ion-textarea{min-height:80px!important;scrollbar-color:#888 #f0f0f0;scrollbar-width:thin}\n"] }]
|
|
2713
3122
|
}], propDecorators: { operation: [{
|
|
2714
3123
|
type: Input,
|
|
2715
3124
|
args: [{ required: true }]
|
|
@@ -2806,6 +3215,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
2806
3215
|
type: Input
|
|
2807
3216
|
}], uid: [{
|
|
2808
3217
|
type: Input
|
|
3218
|
+
}], page: [{
|
|
3219
|
+
type: Input
|
|
2809
3220
|
}], translatable: [{
|
|
2810
3221
|
type: Input
|
|
2811
3222
|
}], activeFormGroup: [{
|
|
@@ -3235,7 +3646,9 @@ class NgxBaseComponent {
|
|
|
3235
3646
|
* an initialization message with the component name. This method is typically called
|
|
3236
3647
|
* during the component's lifecycle setup.
|
|
3237
3648
|
*/
|
|
3238
|
-
initialize() {
|
|
3649
|
+
async initialize(parseProps = true, skip) {
|
|
3650
|
+
if (!this.initialized && parseProps)
|
|
3651
|
+
return this.parseProps(this, skip || []);
|
|
3239
3652
|
this.initialized = true;
|
|
3240
3653
|
}
|
|
3241
3654
|
/**
|
|
@@ -3315,11 +3728,15 @@ class NgxBaseComponent {
|
|
|
3315
3728
|
* @protected
|
|
3316
3729
|
* @memberOf NgxBaseComponent
|
|
3317
3730
|
*/
|
|
3318
|
-
parseProps(instance) {
|
|
3731
|
+
parseProps(instance, skip) {
|
|
3319
3732
|
Object.keys(instance).forEach((key) => {
|
|
3320
|
-
if (Object.keys(this.props).includes(key))
|
|
3733
|
+
if (Object.keys(this.props).includes(key) && !skip.includes(key)) {
|
|
3321
3734
|
this[key] = this.props[key];
|
|
3735
|
+
delete this.props[key];
|
|
3736
|
+
}
|
|
3322
3737
|
});
|
|
3738
|
+
if (!this.initialized)
|
|
3739
|
+
this.initialized = true;
|
|
3323
3740
|
}
|
|
3324
3741
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgxBaseComponent, deps: [{ token: 'instanceToken' }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3325
3742
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: NgxBaseComponent, isStandalone: true, selector: "ng-component", inputs: { rendererId: "rendererId", model: "model", props: "props", item: "item", pk: "pk", route: "route", operations: "operations", uid: "uid", mapper: "mapper", locale: "locale", translatable: "translatable", className: "className", mode: "mode", renderChild: "renderChild" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef, static: true }], usesOnChanges: true, ngImport: i0, template: '<div></div>', isInline: true }); }
|
|
@@ -3594,14 +4011,14 @@ let CrudFormComponent = class CrudFormComponent {
|
|
|
3594
4011
|
});
|
|
3595
4012
|
}
|
|
3596
4013
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CrudFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3597
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", inputs: { model: "model", modelId: "modelId", updateOn: "updateOn", target: "target", method: "method", options: "options", action: "action", operation: "operation", handlers: "handlers", formGroup: "formGroup", childOf: "childOf", rendererId: "rendererId", uid: "uid", allowClear: "allowClear" }, outputs: { submitEvent: "submitEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["reactiveForm"], descendants: true, read: ElementRef }], ngImport: i0, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form #reactiveForm [id]=\"rendererId\" [formGroup]=\"formGroup\" (submit)=\"submit($event)\" novalidate [target]=\"target\">\n <ng-content #formContent></ng-content>\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div>\n <ion-button
|
|
4014
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", inputs: { model: "model", modelId: "modelId", updateOn: "updateOn", target: "target", method: "method", options: "options", action: "action", operation: "operation", handlers: "handlers", formGroup: "formGroup", childOf: "childOf", rendererId: "rendererId", uid: "uid", allowClear: "allowClear" }, outputs: { submitEvent: "submitEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["reactiveForm"], descendants: true, read: ElementRef }], ngImport: i0, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form #reactiveForm [id]=\"rendererId\" [formGroup]=\"formGroup\" (submit)=\"submit($event)\" novalidate [target]=\"target\">\n <ng-content #formContent></ng-content>\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : options.buttons.submit.text}}\n </ion-button>\n </div>\n @if(!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n Back\n </ion-button>\n </div>\n }\n </div>\n </form>\n} @else {\n <div [class]=\"'dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if(operation === OperationKeys.READ && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n Delete\n </ion-button>\n </div>\n\n }\n @if(operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n\n <div>\n <ion-button\n type=\"submit\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{options.buttons.submit.text}}\n </ion-button>\n </div>\n }\n\n @if(options.buttons.clear) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? 'Back' : options.buttons.clear?.text}}\n </ion-button>\n </div>\n\n }\n </div>\n}\n\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 768px){.dcf-buttons-container.dcf-flex{flex-direction:row-reverse}}@media (max-width: 767px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}form{padding:2rem 1rem}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
|
|
3598
4015
|
};
|
|
3599
4016
|
CrudFormComponent = __decorate([
|
|
3600
4017
|
Dynamic()
|
|
3601
4018
|
], CrudFormComponent);
|
|
3602
4019
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CrudFormComponent, decorators: [{
|
|
3603
4020
|
type: Component,
|
|
3604
|
-
args: [{ standalone: true, selector: 'ngx-decaf-crud-form', imports: [ReactiveFormsModule, IonButton, IonIcon], host: { '[attr.id]': 'uid' }, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form #reactiveForm [id]=\"rendererId\" [formGroup]=\"formGroup\" (submit)=\"submit($event)\" novalidate [target]=\"target\">\n <ng-content #formContent></ng-content>\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div>\n <ion-button
|
|
4021
|
+
args: [{ standalone: true, selector: 'ngx-decaf-crud-form', imports: [ReactiveFormsModule, IonButton, IonIcon], host: { '[attr.id]': 'uid' }, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form #reactiveForm [id]=\"rendererId\" [formGroup]=\"formGroup\" (submit)=\"submit($event)\" novalidate [target]=\"target\">\n <ng-content #formContent></ng-content>\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div>\n <ion-button type=\"submit\" [expand]=\"action ? 'block' : 'default'\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{ action ? action : options.buttons.submit.text}}\n </ion-button>\n </div>\n @if(!action) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n Back\n </ion-button>\n </div>\n }\n </div>\n </form>\n} @else {\n <div [class]=\"'dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left ' + operation\" [id]=\"uid\">\n @if(operation === OperationKeys.READ && modelId) {\n <div>\n <ion-button\n (click)=\"handleDelete()\"\n color=\"danger\"\n type=\"button\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n Delete\n </ion-button>\n </div>\n\n }\n @if(operation === OperationKeys.CREATE || operation === OperationKeys.UPDATE) {\n\n <div>\n <ion-button\n type=\"submit\">\n @if(options.buttons.submit.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.submit.iconSlot\" [name]=\"options.buttons.submit.icon\"></ion-icon>\n }\n {{options.buttons.submit.text}}\n </ion-button>\n </div>\n }\n\n @if(options.buttons.clear) {\n <div>\n <ion-button fill=\"clear\" (click)=\"handleReset()\">\n @if(options.buttons.clear?.icon) {\n <ion-icon aria-hidden=\"true\" [slot]=\"options.buttons.clear?.iconSlot\" [name]=\"options.buttons.clear?.icon\"></ion-icon>\n }\n {{ [OperationKeys.DELETE, OperationKeys.READ, OperationKeys.UPDATE].includes(operation) ? 'Back' : options.buttons.clear?.text}}\n </ion-button>\n </div>\n\n }\n </div>\n}\n\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 768px){.dcf-buttons-container.dcf-flex{flex-direction:row-reverse}}@media (max-width: 767px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}form{padding:2rem 1rem}\n"] }]
|
|
3605
4022
|
}], propDecorators: { model: [{
|
|
3606
4023
|
type: Input
|
|
3607
4024
|
}], modelId: [{
|
|
@@ -3842,7 +4259,7 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxBaseComponent {
|
|
|
3842
4259
|
* @memberOf EmptyStateComponent
|
|
3843
4260
|
*/
|
|
3844
4261
|
async ngOnInit() {
|
|
3845
|
-
this.
|
|
4262
|
+
this.initialize();
|
|
3846
4263
|
this.translatable = stringToBoolean(this.translatable);
|
|
3847
4264
|
this.showIcon = stringToBoolean(this.showIcon);
|
|
3848
4265
|
this.locale = this.getLocale(this.translatable);
|
|
@@ -4580,7 +4997,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxBaseComponent {
|
|
|
4580
4997
|
return this.mapper;
|
|
4581
4998
|
}
|
|
4582
4999
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FieldsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4583
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FieldsetComponent, isStandalone: true, selector: "ngx-decaf-fieldset", inputs: { name: "name", childOf: "childOf", uid: "uid", customTypes: "customTypes", operation: "operation", formGroup: "formGroup", title: "title", description: "description", target: "target", multiple: "multiple", value: "value", handlers: "handlers" }, host: { properties: { "attr.id": "overriode " } }, viewQueries: [{ propertyName: "accordionComponent", first: true, predicate: ["accordionComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n (fieldsetRemoveGroupEvent)=\"handleRemoveItem(undefined, $event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n #component>\n <ion-accordion-group [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" (validationErrorEvent)=\"handleValidationError($event)\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item slot=\"header\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ name | translate }}</legend>\n </div>\n @if(!isRequired && ['create', 'update'].includes(operation)) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveComponent($event)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if(multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if(items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if(item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n @if(!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem(item.title, $index)\">\n <ion-icon name=\"create-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n\n @if(!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveItem(item.title)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\n }\n\n <ng-content></ng-content>\n\n @if(multiple && ['create', 'update'].includes(operation)) {\n @if(isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n <div class=\"dcf-margin-bottom dcf-grid dcf-grid-collapse dcf-flex\">\n @if(updatingItem) {\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n }\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{buttonLabel}}\n </ion-button>\n\n </div>\n }\n\n </div>\n </ion-accordion>\n </ion-accordion-group>\n</fieldset>\n\n", styles: ["ion-accordion-group ion-item[slot=header] .dcf-delete{width:30px}ion-accordion-group ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion-group ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}::ng-deep ion-accordion ngx-decaf-crud-field:last-child ion-item{--inner-border-width: 0px !important;--border-width: 0px !important}.dcf-fieldset{margin-bottom:1.8rem;margin-top:1rem;padding-bottom:0;padding-top:1rem;background:var(--dcf-card-background);border-radius:6px;height:100%}@media (prefers-color-scheme: light){.dcf-fieldset{border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-dark)!important}}@media (prefers-color-scheme: dark){.dcf-fieldset{border:1px solid var(--dcf-color-step-400)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-gray-2)}}.dcf-fieldset.read,.dcf-fieldset.delete{margin-top:1.25rem;padding-bottom:1rem}.dcf-fieldset.read [slot=content],.dcf-fieldset.delete [slot=content]{padding-top:0!important}.dcf-fieldset.read ion-accordion,.dcf-fieldset.delete ion-accordion{margin-bottom:0rem!important}@media (prefers-color-scheme: dark){.dcf-fieldset.read,.dcf-fieldset.delete{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset ion-accordion{background:var(--dcf-card-background);margin-bottom:1rem}.dcf-fieldset ion-accordion.accordion-collapsing,.dcf-fieldset ion-accordion.accordion-collapsed{margin-bottom:1rem}.dcf-fieldset ion-accordion ion-item[slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: 12px}.dcf-fieldset ion-accordion ion-item[slot=header] legend{font-weight:600;font-size:1rem;margin:0}@media (prefers-color-scheme: light){.dcf-fieldset ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}.dcf-fieldset ion-accordion [slot=content]{padding-top:2rem!important;padding-inline:.75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:1rem;flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{margin-top:-1rem;margin-bottom:1rem;padding:0!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important;border:1px solid transparent;box-sizing:border-box}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:1rem;transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.8rem;color:var(--dcf-color-gray-7)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: IonAccordionGroup, selector: "ion-accordion-group", inputs: ["animated", "disabled", "expand", "mode", "multiple", "readonly", "value"] }, { kind: "component", type: IonAccordion, selector: "ion-accordion", inputs: ["disabled", "mode", "readonly", "toggleIcon", "toggleIconSlot", "value"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonReorder, selector: "ion-reorder" }, { kind: "component", type: IonReorderGroup, selector: "ion-reorder-group", inputs: ["disabled"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
|
|
5000
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: FieldsetComponent, isStandalone: true, selector: "ngx-decaf-fieldset", inputs: { name: "name", childOf: "childOf", page: "page", uid: "uid", customTypes: "customTypes", operation: "operation", formGroup: "formGroup", title: "title", description: "description", target: "target", multiple: "multiple", value: "value", handlers: "handlers" }, host: { properties: { "attr.id": "overriode " } }, viewQueries: [{ propertyName: "accordionComponent", first: true, predicate: ["accordionComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n (fieldsetRemoveGroupEvent)=\"handleRemoveItem(undefined, $event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n #component>\n <ion-accordion-group [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" (validationErrorEvent)=\"handleValidationError($event)\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item slot=\"header\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ name | translate }}</legend>\n </div>\n @if(!isRequired && ['create', 'update'].includes(operation)) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveComponent($event)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if(multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if(items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if(item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n @if(!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem(item.title, $index)\">\n <ion-icon name=\"create-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n\n @if(!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveItem(item.title)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\n }\n\n <ng-content select=\"[slot=content]\"></ng-content>\n\n @if(multiple && ['create', 'update'].includes(operation)) {\n @if(isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n <div class=\"dcf-margin-bottom dcf-grid dcf-grid-collapse dcf-flex\">\n @if(updatingItem) {\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n }\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{buttonLabel}}\n </ion-button>\n\n </div>\n }\n\n </div>\n </ion-accordion>\n </ion-accordion-group>\n</fieldset>\n\n", styles: ["ion-accordion-group ion-item[slot=header] .dcf-delete{width:30px}ion-accordion-group ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion-group ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}::ng-deep ion-accordion ngx-decaf-crud-field:last-child ion-item{--inner-border-width: 0px !important;--border-width: 0px !important}.dcf-fieldset{margin-bottom:1.8rem;margin-top:1rem;padding-bottom:0;padding-top:1rem;background:var(--dcf-card-background);border-radius:6px;height:100%}@media (prefers-color-scheme: light){.dcf-fieldset{border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-dark)!important}}@media (prefers-color-scheme: dark){.dcf-fieldset{border:1px solid var(--dcf-color-step-400)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-gray-2)}}.dcf-fieldset.read,.dcf-fieldset.delete{margin-top:1.25rem;padding-bottom:1rem}.dcf-fieldset.read [slot=content],.dcf-fieldset.delete [slot=content]{padding-top:0!important}.dcf-fieldset.read ion-accordion,.dcf-fieldset.delete ion-accordion{margin-bottom:0rem!important}@media (prefers-color-scheme: dark){.dcf-fieldset.read,.dcf-fieldset.delete{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset ion-accordion{background:var(--dcf-card-background);margin-bottom:1rem}.dcf-fieldset ion-accordion.accordion-collapsing,.dcf-fieldset ion-accordion.accordion-collapsed{margin-bottom:1rem}.dcf-fieldset ion-accordion ion-item[slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: 12px}.dcf-fieldset ion-accordion ion-item[slot=header] legend{font-weight:600;font-size:1rem;margin:0}@media (prefers-color-scheme: light){.dcf-fieldset ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}.dcf-fieldset ion-accordion [slot=content]{padding-top:2rem!important;padding-inline:.75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:1rem;flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{margin-top:-1rem;margin-bottom:1rem;padding:0!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important;border:1px solid transparent;box-sizing:border-box}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:1rem;transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.8rem;color:var(--dcf-color-gray-7)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: IonAccordionGroup, selector: "ion-accordion-group", inputs: ["animated", "disabled", "expand", "mode", "multiple", "readonly", "value"] }, { kind: "component", type: IonAccordion, selector: "ion-accordion", inputs: ["disabled", "mode", "readonly", "toggleIcon", "toggleIconSlot", "value"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonReorder, selector: "ion-reorder" }, { kind: "component", type: IonReorderGroup, selector: "ion-reorder-group", inputs: ["disabled"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
|
|
4584
5001
|
};
|
|
4585
5002
|
FieldsetComponent = __decorate([
|
|
4586
5003
|
Dynamic(),
|
|
@@ -4601,7 +5018,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
4601
5018
|
IonReorderGroup,
|
|
4602
5019
|
IonButton,
|
|
4603
5020
|
IonIcon,
|
|
4604
|
-
], host: { '[attr.id]': 'overriode ' }, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n (fieldsetRemoveGroupEvent)=\"handleRemoveItem(undefined, $event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n #component>\n <ion-accordion-group [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" (validationErrorEvent)=\"handleValidationError($event)\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item slot=\"header\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ name | translate }}</legend>\n </div>\n @if(!isRequired && ['create', 'update'].includes(operation)) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveComponent($event)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if(multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if(items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if(item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n @if(!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem(item.title, $index)\">\n <ion-icon name=\"create-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n\n @if(!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveItem(item.title)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\n }\n\n <ng-content></ng-content>\n\n @if(multiple && ['create', 'update'].includes(operation)) {\n @if(isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n <div class=\"dcf-margin-bottom dcf-grid dcf-grid-collapse dcf-flex\">\n @if(updatingItem) {\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n }\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{buttonLabel}}\n </ion-button>\n\n </div>\n }\n\n </div>\n </ion-accordion>\n </ion-accordion-group>\n</fieldset>\n\n", styles: ["ion-accordion-group ion-item[slot=header] .dcf-delete{width:30px}ion-accordion-group ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion-group ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}::ng-deep ion-accordion ngx-decaf-crud-field:last-child ion-item{--inner-border-width: 0px !important;--border-width: 0px !important}.dcf-fieldset{margin-bottom:1.8rem;margin-top:1rem;padding-bottom:0;padding-top:1rem;background:var(--dcf-card-background);border-radius:6px;height:100%}@media (prefers-color-scheme: light){.dcf-fieldset{border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-dark)!important}}@media (prefers-color-scheme: dark){.dcf-fieldset{border:1px solid var(--dcf-color-step-400)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-gray-2)}}.dcf-fieldset.read,.dcf-fieldset.delete{margin-top:1.25rem;padding-bottom:1rem}.dcf-fieldset.read [slot=content],.dcf-fieldset.delete [slot=content]{padding-top:0!important}.dcf-fieldset.read ion-accordion,.dcf-fieldset.delete ion-accordion{margin-bottom:0rem!important}@media (prefers-color-scheme: dark){.dcf-fieldset.read,.dcf-fieldset.delete{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset ion-accordion{background:var(--dcf-card-background);margin-bottom:1rem}.dcf-fieldset ion-accordion.accordion-collapsing,.dcf-fieldset ion-accordion.accordion-collapsed{margin-bottom:1rem}.dcf-fieldset ion-accordion ion-item[slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: 12px}.dcf-fieldset ion-accordion ion-item[slot=header] legend{font-weight:600;font-size:1rem;margin:0}@media (prefers-color-scheme: light){.dcf-fieldset ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}.dcf-fieldset ion-accordion [slot=content]{padding-top:2rem!important;padding-inline:.75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:1rem;flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{margin-top:-1rem;margin-bottom:1rem;padding:0!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important;border:1px solid transparent;box-sizing:border-box}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:1rem;transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.8rem;color:var(--dcf-color-gray-7)}\n"] }]
|
|
5021
|
+
], host: { '[attr.id]': 'overriode ' }, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n (fieldsetRemoveGroupEvent)=\"handleRemoveItem(undefined, $event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n #component>\n <ion-accordion-group [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" (validationErrorEvent)=\"handleValidationError($event)\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item slot=\"header\" (click)=\"handleAccordionToggle($event)\">\n <div class=\"dcf-grid dcf-grid-collapse dcf-flex dcf-flex-middle dcf-width-1-1\">\n <div class=\"dcf-width-expand\">\n <legend>{{ name | translate }}</legend>\n </div>\n @if(!isRequired && ['create', 'update'].includes(operation)) {\n <div class=\"dcf-width-auto dcf-delete\">\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveComponent($event)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </div>\n }\n </div>\n </ion-item>\n <div slot=\"content\" [attr.aria-hidden]=\"!isOpen\">\n @if(multiple && items.length) {\n <ion-list class=\"dcf-fields-list\">\n <ion-reorder-group [formGroup]=\"formGroup.parent\" [disabled]=\"updatingItem\" (ionItemReorder)=\"handleReorderItems($any($event))\" #accordionComponent>\n @for(item of items; track item.index) {\n <ion-item [class.not-unique]=\"item.title === isUniqueError\" [class.updating]=\"updatingItem?.[pk] === item.title\" lines=\"full\" [button]=\"false\">\n @if(items?.length > 1 && !updatingItem) {\n <ion-reorder slot=\"start\">\n <ion-icon name=\"swap-vertical-outline\"></ion-icon>\n </ion-reorder>\n } @else {\n <div slot=\"start\">\n <ion-icon class=\"dcf-reorder-disabled\" size=\"small\" name=\"swap-vertical-outline\" disabled></ion-icon>\n </div>\n }\n <ion-label [color]=\"(item.title === isUniqueError && !updatingItem?.[pk] === item.title) ? 'danger' : ''\">{{ item.index }}. {{ item.title }}\n @if(item.description?.length > 0) {\n <br />\n <ion-text class=\"dcf-subtitle\">{{item.description}}</ion-text>\n }\n </ion-label>\n @if(!updatingItem || updatingItem?.[pk] !== item.title) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleUpdateItem(item.title, $index)\">\n <ion-icon name=\"create-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n\n @if(!updatingItem) {\n <ion-button fill=\"clear\" size=\"small\" (click)=\"handleRemoveItem(item.title)\">\n <ion-icon name=\"trash-outline\" color=\"dark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n }\n </ion-item>\n }\n </ion-reorder-group>\n </ion-list>\n }\n\n <ng-content select=\"[slot=content]\"></ng-content>\n\n @if(multiple && ['create', 'update'].includes(operation)) {\n @if(isUniqueError) {\n <div class=\"dcf-not-unique-container dcf-animation dcf-animation-bottom-small dcf-animation-fast\">\n <div class=\" dcf-grid dcf-grid-collapse dcf-width-1-1 \">\n <div class=\"dcf-auto\" [attr.style]=\"'max-width: 50px'\">\n <ion-icon name=\"alert-circle-outline\"></ion-icon>\n </div>\n <div class=\"dcf-width-expand\">\n <ion-text color=\"danger\" class=\"dcf-text-small\">{{ locale + '.not_unique' | translate : { value: isUniqueError } }}</ion-text>\n </div>\n </div>\n </div>\n }\n <div class=\"dcf-margin-bottom dcf-grid dcf-grid-collapse dcf-flex\">\n @if(updatingItem) {\n <ion-button size=\"small\" fill=\"clear\" color=\"danger\" (click)=\"handleCancelUpdateItem()\">\n {{ buttonCancelLabel }}\n </ion-button>\n }\n <ion-button size=\"small\" fill=\"clear\" class=\"dcf-button-add\" (click)=\"handleCreateItem()\">\n <ion-icon name=\"add-outline\" slot=\"start\"></ion-icon>\n {{buttonLabel}}\n </ion-button>\n\n </div>\n }\n\n </div>\n </ion-accordion>\n </ion-accordion-group>\n</fieldset>\n\n", styles: ["ion-accordion-group ion-item[slot=header] .dcf-delete{width:30px}ion-accordion-group ion-item[slot=header] .dcf-delete ion-button{transform:translateY(-2px)}ion-accordion-group ion-item[slot=header] .dcf-delete ion-icon{font-size:1.15rem}::ng-deep ion-accordion ngx-decaf-crud-field:last-child ion-item{--inner-border-width: 0px !important;--border-width: 0px !important}.dcf-fieldset{margin-bottom:1.8rem;margin-top:1rem;padding-bottom:0;padding-top:1rem;background:var(--dcf-card-background);border-radius:6px;height:100%}@media (prefers-color-scheme: light){.dcf-fieldset{border:1px solid var(--dcf-color-gray-3)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-dark)!important}}@media (prefers-color-scheme: dark){.dcf-fieldset{border:1px solid var(--dcf-color-step-400)}.dcf-fieldset .dcf-button-add{color:var(--ion-color-gray-2)}}.dcf-fieldset.read,.dcf-fieldset.delete{margin-top:1.25rem;padding-bottom:1rem}.dcf-fieldset.read [slot=content],.dcf-fieldset.delete [slot=content]{padding-top:0!important}.dcf-fieldset.read ion-accordion,.dcf-fieldset.delete ion-accordion{margin-bottom:0rem!important}@media (prefers-color-scheme: dark){.dcf-fieldset.read,.dcf-fieldset.delete{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset ion-accordion{background:var(--dcf-card-background);margin-bottom:1rem}.dcf-fieldset ion-accordion.accordion-collapsing,.dcf-fieldset ion-accordion.accordion-collapsed{margin-bottom:1rem}.dcf-fieldset ion-accordion ion-item[slot=header]{--border-color: transparent;--border-radius: 6px;--inner-border-width: 0;--padding-start: 12px}.dcf-fieldset ion-accordion ion-item[slot=header] legend{font-weight:600;font-size:1rem;margin:0}@media (prefers-color-scheme: light){.dcf-fieldset ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}.dcf-fieldset ion-accordion [slot=content]{padding-top:2rem!important;padding-inline:.75rem}.dcf-not-unique-container{display:flex;justify-content:center;align-items:center;margin-bottom:1rem;flex:1 1 auto}.dcf-not-unique-container>div{display:flex;justify-content:center;align-items:center}.dcf-not-unique-container ion-icon{transform:translatey(2px);margin-right:5px}.dcf-fields-list{margin-top:-1rem;margin-bottom:1rem;padding:0!important}.dcf-fields-list ion-item{--min-height: 50px;--padding-top: .25rem;--padding-bottom: .25rem;--padding-start: .75rem;--padding-end: .75rem;--inner-padding-start: 0px !important;--inner-padding-end: 0px !important;--border-color: var(--dcf-color-gray-2) !important;border:1px solid transparent;box-sizing:border-box}.dcf-fields-list ion-item ion-icon.dcf-reorder-disabled{width:1rem;transform:translatey(2px);color:var(--dcf-color-gray-4)}.dcf-fields-list ion-item.updating{--background: rgba(var(--dcf-color-primary-rgb), .1) !important}.dcf-fields-list ion-item.not-unique{--background: rgba(var(--dcf-color-danger-rgb), .05) !important}.dcf-fields-list ion-item .dcf-subtitle{font-size:.8rem;color:var(--dcf-color-gray-7)}\n"] }]
|
|
4605
5022
|
}], ctorParameters: () => [], propDecorators: { accordionComponent: [{
|
|
4606
5023
|
type: ViewChild,
|
|
4607
5024
|
args: ['accordionComponent', { static: false }]
|
|
@@ -4609,6 +5026,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
4609
5026
|
type: Input
|
|
4610
5027
|
}], childOf: [{
|
|
4611
5028
|
type: Input
|
|
5029
|
+
}], page: [{
|
|
5030
|
+
type: Input
|
|
4612
5031
|
}], uid: [{
|
|
4613
5032
|
type: Input
|
|
4614
5033
|
}], customTypes: [{
|
|
@@ -5832,6 +6251,11 @@ class ModelRendererComponent {
|
|
|
5832
6251
|
* @description Global variables to be passed to the rendered component
|
|
5833
6252
|
*/
|
|
5834
6253
|
this.globals = {};
|
|
6254
|
+
/**
|
|
6255
|
+
* @description Set if render content projection is allowed
|
|
6256
|
+
* @default true
|
|
6257
|
+
*/
|
|
6258
|
+
this.projectable = true;
|
|
5835
6259
|
/**
|
|
5836
6260
|
* @description Event emitter for custom events from the rendered component
|
|
5837
6261
|
*/
|
|
@@ -5849,7 +6273,7 @@ class ModelRendererComponent {
|
|
|
5849
6273
|
typeof model === 'string'
|
|
5850
6274
|
? Model.build({}, model)
|
|
5851
6275
|
: model;
|
|
5852
|
-
this.output = model.render(this.globals || {}, this.vcr, this.injector, this.inner);
|
|
6276
|
+
this.output = model.render(this.globals || {}, this.vcr, this.injector, this.inner, this.projectable);
|
|
5853
6277
|
if (this.output?.inputs)
|
|
5854
6278
|
this.rendererId = sf(AngularEngineKeys.RENDERED_ID, this.output.inputs['rendererId']);
|
|
5855
6279
|
this.instance = this.output?.instance;
|
|
@@ -5907,7 +6331,7 @@ class ModelRendererComponent {
|
|
|
5907
6331
|
}
|
|
5908
6332
|
}
|
|
5909
6333
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ModelRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5910
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ModelRendererComponent, isStandalone: true, selector: "ngx-decaf-model-renderer", inputs: { model: "model", globals: "globals", rendererId: "rendererId" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "rendererId" } }, viewQueries: [{ propertyName: "inner", first: true, predicate: ["inner"], descendants: true, read: TemplateRef, static: true }, { propertyName: "vcr", first: true, predicate: ["componentOuter"], descendants: true, read: ViewContainerRef, static: true }], usesOnChanges: true, ngImport: i0, template: " <!-- Keep to avoid id conflicts -->\n <div [id]=\"rendererId\"></div>\n\n <ng-template #componentOuter></ng-template>\n <ng-template #inner>\n <div [id]=\"rendererId || null\">\n @for (child of output?.children; track child) {\n @if(child?.children?.length) {\n <ngx-decaf-component-renderer [parent]=\"child\" />\n } @else {\n <ng-container\n #childComponents\n *ngComponentOutlet=\"\n child.component;\n injector: child.injector;\n inputs: child.inputs;\n content:child.content;\n \"\n />\n }\n }\n </div>\n </ng-template>\n", styles: [""], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "model", "parent"], outputs: ["listenEvent"] }] }); }
|
|
6334
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ModelRendererComponent, isStandalone: true, selector: "ngx-decaf-model-renderer", inputs: { model: "model", globals: "globals", projectable: "projectable", rendererId: "rendererId" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "rendererId" } }, viewQueries: [{ propertyName: "inner", first: true, predicate: ["inner"], descendants: true, read: TemplateRef, static: true }, { propertyName: "vcr", first: true, predicate: ["componentOuter"], descendants: true, read: ViewContainerRef, static: true }], usesOnChanges: true, ngImport: i0, template: " <!-- Keep to avoid id conflicts -->\n <div [id]=\"rendererId\"></div>\n\n <ng-template #componentOuter></ng-template>\n <ng-template #inner>\n <div [id]=\"rendererId || null\">\n @for (child of output?.children; track child) {\n @if(child?.children?.length) {\n <ngx-decaf-component-renderer [parent]=\"child\" />\n } @else {\n <ng-container\n #childComponents\n *ngComponentOutlet=\"\n child.component;\n injector: child.injector;\n inputs: child.inputs;\n content:child.content;\n \"\n />\n }\n }\n </div>\n </ng-template>\n", styles: [""], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }] }); }
|
|
5911
6335
|
}
|
|
5912
6336
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ModelRendererComponent, decorators: [{
|
|
5913
6337
|
type: Component,
|
|
@@ -5917,6 +6341,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
5917
6341
|
args: [{ required: true }]
|
|
5918
6342
|
}], globals: [{
|
|
5919
6343
|
type: Input
|
|
6344
|
+
}], projectable: [{
|
|
6345
|
+
type: Input
|
|
5920
6346
|
}], inner: [{
|
|
5921
6347
|
type: ViewChild,
|
|
5922
6348
|
args: ['inner', { read: TemplateRef, static: true }]
|
|
@@ -6050,40 +6476,15 @@ class LayoutComponent extends NgxBaseComponent {
|
|
|
6050
6476
|
*
|
|
6051
6477
|
* @memberOf LayoutComponent
|
|
6052
6478
|
*/
|
|
6053
|
-
ngOnInit() {
|
|
6054
|
-
this.initialize();
|
|
6055
|
-
}
|
|
6056
|
-
/**
|
|
6057
|
-
* @description Initializes the layout component with processed properties.
|
|
6058
|
-
* @summary Overrides the base component's initialize method to set up the grid layout.
|
|
6059
|
-
* This method processes input properties, normalizes the breakpoint value, converts
|
|
6060
|
-
* rows and columns to their array representations, and marks the component as initialized.
|
|
6061
|
-
* The initialization ensures all properties are in the correct format for rendering.
|
|
6062
|
-
*
|
|
6063
|
-
* @mermaid
|
|
6064
|
-
* sequenceDiagram
|
|
6065
|
-
* participant L as LayoutComponent
|
|
6066
|
-
* participant B as NgxBaseComponent
|
|
6067
|
-
*
|
|
6068
|
-
* L->>B: parseProps(this)
|
|
6069
|
-
* Note over L: Process component properties
|
|
6070
|
-
* L->>L: Normalize breakpoint to lowercase
|
|
6071
|
-
* L->>L: Convert rows to array format
|
|
6072
|
-
* L->>L: Convert cols to array format
|
|
6073
|
-
* L->>L: Set initialized = true
|
|
6074
|
-
*
|
|
6075
|
-
* @override
|
|
6076
|
-
* @memberOf LayoutComponent
|
|
6077
|
-
*/
|
|
6078
|
-
initialize() {
|
|
6079
|
-
this.parseProps(this);
|
|
6479
|
+
async ngOnInit() {
|
|
6480
|
+
await this.initialize();
|
|
6080
6481
|
this.breakpoint = this.breakpoint.slice(0, 2).toLowerCase();
|
|
6081
6482
|
this.cols = this._cols;
|
|
6082
6483
|
this.rows = this._rows;
|
|
6083
6484
|
this.initialized = true;
|
|
6084
6485
|
}
|
|
6085
6486
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
6086
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LayoutComponent, isStandalone: true, selector: "ngx-decaf-layout", inputs: { cols: "cols", rows: "rows", breakpoint: "breakpoint", children: "children" }, usesInheritance: true, ngImport: i0, template: "\n@if(initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n <div [id]=\"uid\" class=\"dcf-grid dcf-grid-collapse dcf-grid-match\">\n @if(row) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <ion-card class=\"dcf-grid-title\">\n {{row.title | translate}}\n </ion-card>\n </div>\n }\n @for (child of row.cols; track trackItemFn($index, child.col); let colIndex = $index) {\n <div [class]=\"(child.col === cols.length ? 'dcf-width-1-1' : 'dcf-width-'+child.col+'-'+cols.length+'@'+breakpoint)\">\n <div [class]=\"'dcf-grid-child '+child.col \">\n @if(child.tag === 'ngx-decaf-crud-form') {\n <ion-card [class]=\"'dcf-height-1-1 ' + className\">\n <ion-card-content>\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ion-card-content>\n </ion-card>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\"\n />\n }\n </div>\n </div>\n }\n </div>\n }\n}\n", styles: [".dcf-grid>div:not(.dcf-grid-title) ::ng-deep ngx-decaf-component-renderer>*>*{height:100%;display:flex;justify-content:center!important;align-items:center!important}.dcf-grid ion-card.dcf-height-1-1>ion-card-content{margin-top:2rem}.dcf-grid.dcf-grid-small .dcf-grid-child{margin-bottom:2rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child{margin-bottom:1.25rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child ion-card{margin-bottom:1.25rem}.dcf-grid-title{font-size:1.05rem!important;background:none;box-shadow:none;margin-bottom:0;padding-bottom:0;font-weight:600;color:var(--dcf-color-dark);display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: ModelRendererComponent, selector: "ngx-decaf-model-renderer", inputs: ["model", "globals", "rendererId"], outputs: ["listenEvent"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "model", "parent"], outputs: ["listenEvent"] }] }); }
|
|
6487
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: LayoutComponent, isStandalone: true, selector: "ngx-decaf-layout", inputs: { cols: "cols", rows: "rows", breakpoint: "breakpoint", children: "children" }, usesInheritance: true, ngImport: i0, template: "\n@if(initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n <div [id]=\"uid\" class=\"dcf-grid dcf-grid-collapse dcf-grid-match\">\n @if(row) {\n <div class=\"dcf-width-1-1 dcf-grid-title\">\n <ion-card class=\"dcf-grid-title\">\n {{row.title | translate}}\n </ion-card>\n </div>\n }\n @for (child of row.cols; track trackItemFn($index, child.col); let colIndex = $index) {\n <div [class]=\"(child.col === cols.length ? 'dcf-width-1-1' : 'dcf-width-'+child.col+'-'+cols.length+'@'+breakpoint)\">\n <div [class]=\"'dcf-grid-child '+child.col \">\n @if(child.tag === 'ngx-decaf-crud-form') {\n <ion-card [class]=\"'dcf-height-1-1 ' + className\">\n <ion-card-content>\n <ngx-decaf-model-renderer\n [model]=\"child.props.name\"\n (listenEvent)=\"handleEvent($event)\"\n />\n </ion-card-content>\n </ion-card>\n } @else {\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]=\"{props: child.props}\"\n />\n }\n </div>\n </div>\n }\n </div>\n }\n}\n", styles: [".dcf-grid>div:not(.dcf-grid-title) ::ng-deep ngx-decaf-component-renderer>*>*{height:100%;display:flex;justify-content:center!important;align-items:center!important}.dcf-grid ion-card.dcf-height-1-1>ion-card-content{margin-top:2rem}.dcf-grid.dcf-grid-small .dcf-grid-child{margin-bottom:2rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child{margin-bottom:1.25rem}.dcf-grid.dcf-grid-collapse .dcf-grid-child ion-card{margin-bottom:1.25rem}.dcf-grid-title{font-size:1.05rem!important;background:none;box-shadow:none;margin-bottom:0;padding-bottom:0;font-weight:600;color:var(--dcf-color-dark);display:flex;align-items:center;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: ModelRendererComponent, selector: "ngx-decaf-model-renderer", inputs: ["model", "globals", "projectable", "rendererId"], outputs: ["listenEvent"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }] }); }
|
|
6087
6488
|
}
|
|
6088
6489
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LayoutComponent, decorators: [{
|
|
6089
6490
|
type: Component,
|
|
@@ -7237,7 +7638,7 @@ let ListComponent = class ListComponent extends NgxBaseComponent {
|
|
|
7237
7638
|
await this.refresh();
|
|
7238
7639
|
if (this.operations.includes(OperationKeys.CREATE) && this.route)
|
|
7239
7640
|
this.empty.link = `${this.route}/${OperationKeys.CREATE}`;
|
|
7240
|
-
this.initialize();
|
|
7641
|
+
await this.initialize();
|
|
7241
7642
|
if (this.model instanceof Model && this._repository)
|
|
7242
7643
|
this._repository.observe(this.observer);
|
|
7243
7644
|
}
|
|
@@ -7933,7 +8334,7 @@ let ListComponent = class ListComponent extends NgxBaseComponent {
|
|
|
7933
8334
|
}, []);
|
|
7934
8335
|
}
|
|
7935
8336
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
7936
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ListComponent, isStandalone: true, selector: "ngx-decaf-list", inputs: { type: "type", translatable: "translatable", showSearchbar: "showSearchbar", data: "data", source: "source", start: "start", limit: "limit", loadMoreData: "loadMoreData", lines: "lines", inset: "inset", scrollThreshold: "scrollThreshold", scrollPosition: "scrollPosition", loadingText: "loadingText", showRefresher: "showRefresher", loadingSpinner: "loadingSpinner", enableFilter: "enableFilter", sortDirection: "sortDirection", sortBy: "sortBy", disableSort: "disableSort", emptyIcon: "emptyIcon", empty: "empty" }, outputs: { refreshEvent: "refreshEvent", clickEvent: "clickEvent" }, host: { listeners: { "window:ListItemClickEvent": "handleClick($event)", "window:searchbarEvent": "handleSearch($event)", "window:BackButtonNavigationEndEvent": "refresh($event)" } }, usesInheritance: true, ngImport: i0, template: "\n@if(showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n@if(showSearchbar && data?.length) {\n @if(model && enableFilter) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n}\n\n@if(data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\" #component>\n @if(item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if(loadMoreData) {\n @if(pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if(refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if(!searchValue?.length) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\"\n [buttonText]=\"empty.showButton ? (locale + '.'+ empty.button | translate) : ''\"\n [buttonLink]=\"empty.showButton ? empty.route : ''\"\n />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n ngClass=\"empty-search\"\n [translatable]=\"true\"\n title=\"search.title\"\n subtitle=\"search.subtitle\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: PaginationComponent, selector: "ngx-decaf-pagination", inputs: ["totalPages", "current"], outputs: ["clickEvent"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonThumbnail, selector: "ion-thumbnail" }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: IonInfiniteScroll, selector: "ion-infinite-scroll", inputs: ["disabled", "position", "threshold"] }, { kind: "component", type: IonInfiniteScrollContent, selector: "ion-infinite-scroll-content", inputs: ["loadingSpinner", "loadingText"] }, { kind: "component", type: SearchbarComponent, selector: "ngx-decaf-searchbar", inputs: ["autocomplete", "autocorrect", "animated", "buttonCancelText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value", "queryKeys", "isVisible", "wrapper", "wrapperColor", "emitEventToWindow"], outputs: ["searchEvent"] }, { kind: "component", type: EmptyStateComponent, selector: "ngx-decaf-empty-state", inputs: ["title", "titleColor", "subtitle", "subtitleColor", "showIcon", "icon", "iconSize", "iconColor", "buttonLink", "buttonText", "buttonFill", "buttonColor", "buttonSize", "searchValue"] }, { kind: "component", type: FilterComponent, selector: "ngx-decaf-filter", inputs: ["indexes", "conditions", "sortBy", "disableSort"], outputs: ["filterEvent", "searchEvent"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "model", "parent"], outputs: ["listenEvent"] }] }); }
|
|
8337
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ListComponent, isStandalone: true, selector: "ngx-decaf-list", inputs: { type: "type", translatable: "translatable", showSearchbar: "showSearchbar", data: "data", source: "source", start: "start", limit: "limit", loadMoreData: "loadMoreData", lines: "lines", inset: "inset", scrollThreshold: "scrollThreshold", scrollPosition: "scrollPosition", loadingText: "loadingText", showRefresher: "showRefresher", loadingSpinner: "loadingSpinner", enableFilter: "enableFilter", sortDirection: "sortDirection", sortBy: "sortBy", disableSort: "disableSort", emptyIcon: "emptyIcon", empty: "empty" }, outputs: { refreshEvent: "refreshEvent", clickEvent: "clickEvent" }, host: { listeners: { "window:ListItemClickEvent": "handleClick($event)", "window:searchbarEvent": "handleSearch($event)", "window:BackButtonNavigationEndEvent": "refresh($event)" } }, usesInheritance: true, ngImport: i0, template: "\n@if(showRefresher) {\n <ion-refresher slot=\"fixed\" [pullFactor]=\"1\" [pullMin]=\"100\" [pullMax]=\"200\" (ionRefresh)=\"handleRefresh($event)\">\n <ion-refresher-content />\n </ion-refresher>\n}\n\n@if(showSearchbar && data?.length) {\n @if(model && enableFilter) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\n } @else {\n <ngx-decaf-searchbar [emitEventToWindow]=\"false\" [debounce]=\"500\" (searchEvent)=\"handleSearch($event)\" />\n }\n}\n\n@if(data?.length) {\n <ion-list [id]=\"uid\" [inset]=\"inset\" [lines]=\"lines\" #component>\n @if(item?.tag) {\n @for(child of items; track trackItemFn($index, child)) {\n <ngx-decaf-component-renderer\n [tag]=\"item.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{\n item: child,\n mapper: mapper,\n route: route\n }'>\n </ngx-decaf-component-renderer>\n }\n } @else {\n <ng-content></ng-content>\n }\n </ion-list>\n\n @if(loadMoreData) {\n @if(pages > 0 && type === 'paginated' && !searchValue?.length) {\n <ngx-decaf-pagination\n [totalPages]=\"pages\"\n [current]=\"page\"\n (clickEvent)=\"handlePaginate($event)\"\n />\n\n } @else {\n <ion-infinite-scroll\n [class]=\"searchValue?.length ? 'dcf-hidden' : ''\"\n\n [position]=\"scrollPosition\"\n [threshold]=\"scrollThreshold\"\n (ionInfinite)=\"handleRefresh($event)\">\n <ion-infinite-scroll-content [loadingSpinner]=\"loadingSpinner\" [loadingText]=\"loadingText\" />\n </ion-infinite-scroll>\n }\n }\n} @else {\n @if(refreshing) {\n @for(skl of skeletonData; track $index) {\n <ion-item>\n <ion-thumbnail slot=\"start\">\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n </ion-thumbnail>\n <ion-label>\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n </ion-label>\n </ion-item>\n }\n\n } @else {\n @if(!searchValue?.length) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\"\n [buttonText]=\"empty.showButton ? (locale + '.'+ empty.button | translate) : ''\"\n [buttonLink]=\"empty.showButton ? empty.route : ''\"\n />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n ngClass=\"empty-search\"\n [translatable]=\"true\"\n title=\"search.title\"\n subtitle=\"search.subtitle\"\n [searchValue]=\"searchValue\"\n />\n }\n }\n}\n\n", styles: ["ion-infinite-scroll{max-height:50px}ion-infinite-scroll:not(.infinite-scroll-loading) ::ng-deep{max-height:1.5rem}ion-infinite-scroll ::ng-deep ion-spinner{--color: var(--dcf-color-primary);padding-top:1rem}@media (max-width: 768px){#end,[slot=end]{display:none!important}}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: IonRefresher, selector: "ion-refresher", inputs: ["closeDuration", "disabled", "mode", "pullFactor", "pullMax", "pullMin", "snapbackDuration"] }, { kind: "component", type: PaginationComponent, selector: "ngx-decaf-pagination", inputs: ["totalPages", "current"], outputs: ["clickEvent"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonThumbnail, selector: "ion-thumbnail" }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonRefresherContent, selector: "ion-refresher-content", inputs: ["pullingIcon", "pullingText", "refreshingSpinner", "refreshingText"] }, { kind: "component", type: IonInfiniteScroll, selector: "ion-infinite-scroll", inputs: ["disabled", "position", "threshold"] }, { kind: "component", type: IonInfiniteScrollContent, selector: "ion-infinite-scroll-content", inputs: ["loadingSpinner", "loadingText"] }, { kind: "component", type: SearchbarComponent, selector: "ngx-decaf-searchbar", inputs: ["autocomplete", "autocorrect", "animated", "buttonCancelText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value", "queryKeys", "isVisible", "wrapper", "wrapperColor", "emitEventToWindow"], outputs: ["searchEvent"] }, { kind: "component", type: EmptyStateComponent, selector: "ngx-decaf-empty-state", inputs: ["title", "titleColor", "subtitle", "subtitleColor", "showIcon", "icon", "iconSize", "iconColor", "buttonLink", "buttonText", "buttonFill", "buttonColor", "buttonSize", "searchValue"] }, { kind: "component", type: FilterComponent, selector: "ngx-decaf-filter", inputs: ["indexes", "conditions", "sortBy", "disableSort"], outputs: ["filterEvent", "searchEvent"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }] }); }
|
|
7937
8338
|
};
|
|
7938
8339
|
ListComponent = __decorate([
|
|
7939
8340
|
Dynamic(),
|
|
@@ -8020,6 +8421,283 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
8020
8421
|
args: ['window:BackButtonNavigationEndEvent', ['$event']]
|
|
8021
8422
|
}] } });
|
|
8022
8423
|
|
|
8424
|
+
let StepedFormComponent = class StepedFormComponent {
|
|
8425
|
+
/**
|
|
8426
|
+
* @description Creates an instance of StepedFormComponent.
|
|
8427
|
+
* @summary Initializes a new StepedFormComponent instance and registers the required
|
|
8428
|
+
* Ionic icons for navigation buttons (forward and back arrows).
|
|
8429
|
+
*
|
|
8430
|
+
* @memberOf StepedFormComponent
|
|
8431
|
+
*/
|
|
8432
|
+
constructor() {
|
|
8433
|
+
/**
|
|
8434
|
+
* @description Number of pages in the stepped form.
|
|
8435
|
+
* @summary Represents the total number of steps/pages in the multi-step form.
|
|
8436
|
+
* This value is automatically calculated based on the page properties of the children
|
|
8437
|
+
* or can be explicitly set. Each page represents a logical group of form fields.
|
|
8438
|
+
*
|
|
8439
|
+
* @type {number}
|
|
8440
|
+
* @default 1
|
|
8441
|
+
* @memberOf StepedFormComponent
|
|
8442
|
+
*/
|
|
8443
|
+
this.pages = 1;
|
|
8444
|
+
/**
|
|
8445
|
+
* @description The CRUD operation type for this form.
|
|
8446
|
+
* @summary Defines the type of operation being performed (CREATE, READ, UPDATE, DELETE).
|
|
8447
|
+
* This affects form behavior, validation rules, and field accessibility. For example,
|
|
8448
|
+
* READ operations might disable form fields, while CREATE operations enable all fields.
|
|
8449
|
+
*
|
|
8450
|
+
* @type {CrudOperations}
|
|
8451
|
+
* @default OperationKeys.CREATE
|
|
8452
|
+
* @memberOf StepedFormComponent
|
|
8453
|
+
*/
|
|
8454
|
+
this.operation = OperationKeys.CREATE;
|
|
8455
|
+
/**
|
|
8456
|
+
* @description The initial page to display when the form loads.
|
|
8457
|
+
* @summary Specifies which page of the multi-step form should be shown first.
|
|
8458
|
+
* This allows starting the form at any step, useful for scenarios like editing
|
|
8459
|
+
* existing data where you might want to jump to a specific section.
|
|
8460
|
+
*
|
|
8461
|
+
* @type {number}
|
|
8462
|
+
* @default 1
|
|
8463
|
+
* @memberOf StepedFormComponent
|
|
8464
|
+
*/
|
|
8465
|
+
this.startPage = 1;
|
|
8466
|
+
/**
|
|
8467
|
+
* @description Array of UI model metadata for the currently active page.
|
|
8468
|
+
* @summary Contains only the UI model metadata for fields that should be displayed
|
|
8469
|
+
* on the currently active page. This is a filtered subset of the children array,
|
|
8470
|
+
* updated whenever the user navigates between pages.
|
|
8471
|
+
*
|
|
8472
|
+
* @type {UIModelMetadata[] | undefined}
|
|
8473
|
+
* @memberOf StepedFormComponent
|
|
8474
|
+
*/
|
|
8475
|
+
this.activeChildren = undefined;
|
|
8476
|
+
/**
|
|
8477
|
+
* @description FormGroup for the currently active page.
|
|
8478
|
+
* @summary The FormGroup instance that manages form controls and validation
|
|
8479
|
+
* for the current page only. This is extracted from the main formGroup
|
|
8480
|
+
* when using FormArray structure.
|
|
8481
|
+
*
|
|
8482
|
+
* @type {FormGroup | undefined}
|
|
8483
|
+
* @memberOf StepedFormComponent
|
|
8484
|
+
*/
|
|
8485
|
+
this.activeFormGroup = undefined;
|
|
8486
|
+
/**
|
|
8487
|
+
* @description The currently active page number.
|
|
8488
|
+
* @summary Tracks which page of the multi-step form is currently being displayed.
|
|
8489
|
+
* This property is updated as users navigate through the form steps using
|
|
8490
|
+
* the next/back buttons or programmatic navigation.
|
|
8491
|
+
*
|
|
8492
|
+
* @type {number}
|
|
8493
|
+
* @memberOf StepedFormComponent
|
|
8494
|
+
*/
|
|
8495
|
+
this.activePage = 1;
|
|
8496
|
+
/**
|
|
8497
|
+
* @description Array representing the structure of pages.
|
|
8498
|
+
* @summary Contains metadata about each page, including page numbers and indices.
|
|
8499
|
+
* This array is built during initialization to organize the form fields into
|
|
8500
|
+
* logical pages and provide navigation structure.
|
|
8501
|
+
*
|
|
8502
|
+
* @type {UIModelMetadata[]}
|
|
8503
|
+
* @memberOf StepedFormComponent
|
|
8504
|
+
*/
|
|
8505
|
+
this.pagesArray = [];
|
|
8506
|
+
/**
|
|
8507
|
+
* @description Event emitter for form submission.
|
|
8508
|
+
* @summary Emits events when the form is submitted, typically on the last page
|
|
8509
|
+
* when all validation passes. The emitted event contains the form data and
|
|
8510
|
+
* event type information for parent components to handle.
|
|
8511
|
+
*
|
|
8512
|
+
* @type {EventEmitter<BaseCustomEvent>}
|
|
8513
|
+
* @memberOf StepedFormComponent
|
|
8514
|
+
*/
|
|
8515
|
+
this.submitEvent = new EventEmitter();
|
|
8516
|
+
addIcons({ arrowForwardOutline, arrowBackOutline });
|
|
8517
|
+
}
|
|
8518
|
+
/**
|
|
8519
|
+
* @description Initializes the component after Angular first displays the data-bound properties.
|
|
8520
|
+
* @summary Sets up the stepped form by organizing children into pages, calculating the total
|
|
8521
|
+
* number of pages, and initializing the active page. This method processes the UI model metadata
|
|
8522
|
+
* to create a logical page structure and ensures proper page assignments for all form fields.
|
|
8523
|
+
*
|
|
8524
|
+
* @mermaid
|
|
8525
|
+
* sequenceDiagram
|
|
8526
|
+
* participant A as Angular Lifecycle
|
|
8527
|
+
* participant S as StepedFormComponent
|
|
8528
|
+
* participant F as Form Service
|
|
8529
|
+
*
|
|
8530
|
+
* A->>S: ngOnInit()
|
|
8531
|
+
* S->>S: Set activePage = startPage
|
|
8532
|
+
* S->>S: Process children into pagesArray
|
|
8533
|
+
* S->>S: Calculate total pages
|
|
8534
|
+
* S->>S: Assign page props to children
|
|
8535
|
+
* S->>S: getCurrentFormGroup(activePage)
|
|
8536
|
+
* S->>F: Extract FormGroup for active page
|
|
8537
|
+
* F-->>S: Return activeFormGroup
|
|
8538
|
+
*
|
|
8539
|
+
* @memberOf StepedFormComponent
|
|
8540
|
+
*/
|
|
8541
|
+
ngOnInit() {
|
|
8542
|
+
this.activePage = this.startPage;
|
|
8543
|
+
this.pagesArray = this.children.reduce((acc, curr, index) => {
|
|
8544
|
+
const page = curr.props?.['page'] || index + 1;
|
|
8545
|
+
if (!acc[page])
|
|
8546
|
+
acc[page] = [];
|
|
8547
|
+
acc[page].push({ index: page });
|
|
8548
|
+
return acc;
|
|
8549
|
+
}, []).filter(Boolean);
|
|
8550
|
+
this.pages = this.pagesArray.length;
|
|
8551
|
+
this.children = [...this.children.map((c) => {
|
|
8552
|
+
if (!c.props)
|
|
8553
|
+
c.props = {};
|
|
8554
|
+
const page = c.props['page'] || 1;
|
|
8555
|
+
// prevent page overflow
|
|
8556
|
+
c.props['page'] = page > this.pages ? this.pages : page;
|
|
8557
|
+
return c;
|
|
8558
|
+
})];
|
|
8559
|
+
this.getCurrentFormGroup(this.activePage);
|
|
8560
|
+
}
|
|
8561
|
+
/**
|
|
8562
|
+
* @description Cleanup method called when the component is destroyed.
|
|
8563
|
+
* @summary Unsubscribes from any active timer subscriptions to prevent memory leaks.
|
|
8564
|
+
* This is part of Angular's component lifecycle and ensures proper resource cleanup.
|
|
8565
|
+
*
|
|
8566
|
+
* @memberOf StepedFormComponent
|
|
8567
|
+
*/
|
|
8568
|
+
ngOnDestroy() {
|
|
8569
|
+
if (this.timerSubscription)
|
|
8570
|
+
this.timerSubscription.unsubscribe();
|
|
8571
|
+
}
|
|
8572
|
+
/**
|
|
8573
|
+
* @description Handles navigation to the next page or form submission.
|
|
8574
|
+
* @summary Validates the current page's form fields and either navigates to the next page
|
|
8575
|
+
* or submits the entire form if on the last page. Form validation must pass before
|
|
8576
|
+
* proceeding. On successful submission, emits a submit event with form data.
|
|
8577
|
+
*
|
|
8578
|
+
* @param {boolean} lastPage - Whether this is the last page of the form
|
|
8579
|
+
* @return {void}
|
|
8580
|
+
*
|
|
8581
|
+
* @mermaid
|
|
8582
|
+
* sequenceDiagram
|
|
8583
|
+
* participant U as User
|
|
8584
|
+
* participant S as StepedFormComponent
|
|
8585
|
+
* participant F as Form Service
|
|
8586
|
+
* participant P as Parent Component
|
|
8587
|
+
*
|
|
8588
|
+
* U->>S: Click Next/Submit
|
|
8589
|
+
* S->>F: validateFields(activeFormGroup)
|
|
8590
|
+
* F-->>S: Return validation result
|
|
8591
|
+
* alt Not last page and valid
|
|
8592
|
+
* S->>S: activePage++
|
|
8593
|
+
* S->>S: getCurrentFormGroup(activePage)
|
|
8594
|
+
* else Last page and valid
|
|
8595
|
+
* S->>F: getFormData(formGroup)
|
|
8596
|
+
* F-->>S: Return form data
|
|
8597
|
+
* S->>P: submitEvent.emit({data, name: SUBMIT})
|
|
8598
|
+
* end
|
|
8599
|
+
*
|
|
8600
|
+
* @memberOf StepedFormComponent
|
|
8601
|
+
*/
|
|
8602
|
+
handleNext(lastPage = false) {
|
|
8603
|
+
const isValid = NgxFormService.validateFields(this.activeFormGroup);
|
|
8604
|
+
if (!lastPage) {
|
|
8605
|
+
if (isValid) {
|
|
8606
|
+
this.activePage = this.activePage + 1;
|
|
8607
|
+
this.getCurrentFormGroup(this.activePage);
|
|
8608
|
+
}
|
|
8609
|
+
}
|
|
8610
|
+
else {
|
|
8611
|
+
if (isValid) {
|
|
8612
|
+
const data = Object.assign({}, ...Object.values(NgxFormService.getFormData(this.formGroup)));
|
|
8613
|
+
this.submitEvent.emit({
|
|
8614
|
+
data,
|
|
8615
|
+
name: EventConstants.SUBMIT,
|
|
8616
|
+
});
|
|
8617
|
+
}
|
|
8618
|
+
}
|
|
8619
|
+
}
|
|
8620
|
+
/**
|
|
8621
|
+
* @description Handles navigation to the previous page.
|
|
8622
|
+
* @summary Moves the user back to the previous page in the stepped form.
|
|
8623
|
+
* This method decrements the active page number and updates the form
|
|
8624
|
+
* group and children to display the previous page's content.
|
|
8625
|
+
*
|
|
8626
|
+
* @return {void}
|
|
8627
|
+
*
|
|
8628
|
+
* @mermaid
|
|
8629
|
+
* sequenceDiagram
|
|
8630
|
+
* participant U as User
|
|
8631
|
+
* participant S as StepedFormComponent
|
|
8632
|
+
*
|
|
8633
|
+
* U->>S: Click Back
|
|
8634
|
+
* S->>S: activePage--
|
|
8635
|
+
* S->>S: getCurrentFormGroup(activePage)
|
|
8636
|
+
* Note over S: Update active form and children
|
|
8637
|
+
*
|
|
8638
|
+
* @memberOf StepedFormComponent
|
|
8639
|
+
*/
|
|
8640
|
+
handleBack() {
|
|
8641
|
+
this.activePage = this.activePage - 1;
|
|
8642
|
+
this.getCurrentFormGroup(this.activePage);
|
|
8643
|
+
}
|
|
8644
|
+
/**
|
|
8645
|
+
* @description Updates the active form group and children for the specified page.
|
|
8646
|
+
* @summary Extracts the FormGroup for the given page from the FormArray and filters
|
|
8647
|
+
* the children to show only fields belonging to that page. Uses a timer to ensure
|
|
8648
|
+
* proper Angular change detection when updating the activeChildren.
|
|
8649
|
+
*
|
|
8650
|
+
* @param {number} page - The page number to activate
|
|
8651
|
+
* @return {void}
|
|
8652
|
+
*
|
|
8653
|
+
* @private
|
|
8654
|
+
* @mermaid
|
|
8655
|
+
* sequenceDiagram
|
|
8656
|
+
* participant S as StepedFormComponent
|
|
8657
|
+
* participant F as FormArray
|
|
8658
|
+
* participant T as Timer
|
|
8659
|
+
*
|
|
8660
|
+
* S->>F: Extract FormGroup at index (page - 1)
|
|
8661
|
+
* F-->>S: Return page FormGroup
|
|
8662
|
+
* S->>S: Set activeChildren = undefined
|
|
8663
|
+
* S->>T: timer(10).subscribe()
|
|
8664
|
+
* T-->>S: Filter children for active page
|
|
8665
|
+
* S->>S: Set activeChildren
|
|
8666
|
+
*
|
|
8667
|
+
* @memberOf StepedFormComponent
|
|
8668
|
+
*/
|
|
8669
|
+
getCurrentFormGroup(page) {
|
|
8670
|
+
this.activeFormGroup = this.formGroup.at(page - 1);
|
|
8671
|
+
this.activeChildren = undefined;
|
|
8672
|
+
this.timerSubscription = timer(10).subscribe(() => {
|
|
8673
|
+
this.activeChildren = this.children.filter(c => c.props?.['page'] === page);
|
|
8674
|
+
console.log(this.activeChildren);
|
|
8675
|
+
});
|
|
8676
|
+
}
|
|
8677
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StepedFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8678
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: StepedFormComponent, isStandalone: true, selector: "ngx-decaf-steped-form", inputs: { pages: "pages", operation: "operation", startPage: "startPage", children: "children", formGroup: "formGroup" }, outputs: { submitEvent: "submitEvent" }, ngImport: i0, template: " <!-- @for(child of children; track trackItemFn($index, child)) {\n {{child.tag }}\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{props: child.props}'>\n </ngx-decaf-component-renderer>\n } -->\n <form class=\"dcf-steped-form\" novalidate>\n <div class=\"dcf-page-steps\">\n <div>\n @for(page of pagesArray; track $index;) {\n <div [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n }\n </div>\n </div>\n @if(formGroup) {\n @for(child of activeChildren; track $index) {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n }\n\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"clear\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon>\n Previous\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button [fill]=\"activePage === pages ? 'solid' : 'outline'\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n Submit\n } @else {\n Next\n <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon>\n }\n </ion-button>\n </div>\n </div>\n </form>\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 639px){.dcf-buttons-container.dcf-flex div:nth-child(2){display:flex;justify-content:flex-end}}@media (max-width: 638px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}.dcf-steped-form{padding:2rem 1rem}.dcf-page-steps{display:flex;justify-content:center;margin-bottom:2rem}.dcf-page-steps>div{justify-content:center;min-width:200px;max-width:200px;column-gap:.25em;display:flex}.dcf-page-steps>div>div{width:30px;text-align:center;border-bottom:solid var(--dcf-color-gray-3);box-sizing:border-box;border-width:3px;font-size:0px;font-weight:600}.dcf-page-steps>div>div.dcf-active{border-width:5px;font-size:1rem;color:var(--ion-color-gray-7);border-color:var(--ion-color-primary);line-height:1rem}.dcf-page-steps>div>div.dcf-passed{border-width:4px;font-size:.5rem;line-height:1.2rem;border-color:var(--dcf-color-gray-5);color:var(--ion-color-primary)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "model", "parent"], outputs: ["listenEvent"] }] }); }
|
|
8679
|
+
};
|
|
8680
|
+
StepedFormComponent = __decorate([
|
|
8681
|
+
Dynamic(),
|
|
8682
|
+
__metadata("design:paramtypes", [])
|
|
8683
|
+
], StepedFormComponent);
|
|
8684
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: StepedFormComponent, decorators: [{
|
|
8685
|
+
type: Component,
|
|
8686
|
+
args: [{ selector: 'ngx-decaf-steped-form', imports: [ReactiveFormsModule, IonSkeletonText, IonText, IonButton, IonIcon, ModelRendererComponent, ComponentRendererComponent], standalone: true, template: " <!-- @for(child of children; track trackItemFn($index, child)) {\n {{child.tag }}\n <ngx-decaf-component-renderer\n [tag]=\"child.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [globals]='{props: child.props}'>\n </ngx-decaf-component-renderer>\n } -->\n <form class=\"dcf-steped-form\" novalidate>\n <div class=\"dcf-page-steps\">\n <div>\n @for(page of pagesArray; track $index;) {\n <div [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n }\n </div>\n </div>\n @if(formGroup) {\n @for(child of activeChildren; track $index) {\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\n } @else {\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n <br />\n <ion-skeleton-text [animated]=\"true\"></ion-skeleton-text>\n <ion-text class=\"date\" style=\"width: 20%;\"><ion-skeleton-text [animated]=\"true\"></ion-skeleton-text></ion-text>\n }\n\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-collapse dcf-flex dcf-flex-left\">\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"clear\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon>\n Previous\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button [fill]=\"activePage === pages ? 'solid' : 'outline'\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n Submit\n } @else {\n Next\n <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon>\n }\n </ion-button>\n </div>\n </div>\n </form>\n", styles: [".dcf-buttons-container{margin-top:1.8rem;margin-bottom:0}@media (min-width: 639px){.dcf-buttons-container.dcf-flex div:nth-child(2){display:flex;justify-content:flex-end}}@media (max-width: 638px){.dcf-buttons-container.dcf-flex div{width:100%}.dcf-buttons-container.dcf-flex ion-button{width:100%;margin-bottom:1rem}}.dcf-steped-form{padding:2rem 1rem}.dcf-page-steps{display:flex;justify-content:center;margin-bottom:2rem}.dcf-page-steps>div{justify-content:center;min-width:200px;max-width:200px;column-gap:.25em;display:flex}.dcf-page-steps>div>div{width:30px;text-align:center;border-bottom:solid var(--dcf-color-gray-3);box-sizing:border-box;border-width:3px;font-size:0px;font-weight:600}.dcf-page-steps>div>div.dcf-active{border-width:5px;font-size:1rem;color:var(--ion-color-gray-7);border-color:var(--ion-color-primary);line-height:1rem}.dcf-page-steps>div>div.dcf-passed{border-width:4px;font-size:.5rem;line-height:1.2rem;border-color:var(--dcf-color-gray-5);color:var(--ion-color-primary)}\n"] }]
|
|
8687
|
+
}], ctorParameters: () => [], propDecorators: { pages: [{
|
|
8688
|
+
type: Input
|
|
8689
|
+
}], operation: [{
|
|
8690
|
+
type: Input
|
|
8691
|
+
}], startPage: [{
|
|
8692
|
+
type: Input
|
|
8693
|
+
}], children: [{
|
|
8694
|
+
type: Input
|
|
8695
|
+
}], formGroup: [{
|
|
8696
|
+
type: Input
|
|
8697
|
+
}], submitEvent: [{
|
|
8698
|
+
type: Output
|
|
8699
|
+
}] } });
|
|
8700
|
+
|
|
8023
8701
|
class CollapsableDirective {
|
|
8024
8702
|
constructor() {
|
|
8025
8703
|
this.element = inject(ElementRef);
|
|
@@ -8061,7 +8739,8 @@ const Components = [
|
|
|
8061
8739
|
CrudFormComponent,
|
|
8062
8740
|
FieldsetComponent,
|
|
8063
8741
|
LayoutComponent,
|
|
8064
|
-
FilterComponent
|
|
8742
|
+
FilterComponent,
|
|
8743
|
+
StepedFormComponent
|
|
8065
8744
|
];
|
|
8066
8745
|
class ForAngularComponentsModule {
|
|
8067
8746
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularComponentsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
@@ -8077,7 +8756,8 @@ class ForAngularComponentsModule {
|
|
|
8077
8756
|
CrudFormComponent,
|
|
8078
8757
|
FieldsetComponent,
|
|
8079
8758
|
LayoutComponent,
|
|
8080
|
-
FilterComponent,
|
|
8759
|
+
FilterComponent,
|
|
8760
|
+
StepedFormComponent, CollapsableDirective], exports: [ModelRendererComponent,
|
|
8081
8761
|
ComponentRendererComponent,
|
|
8082
8762
|
CrudFieldComponent,
|
|
8083
8763
|
CrudFormComponent,
|
|
@@ -8089,7 +8769,8 @@ class ForAngularComponentsModule {
|
|
|
8089
8769
|
CrudFormComponent,
|
|
8090
8770
|
FieldsetComponent,
|
|
8091
8771
|
LayoutComponent,
|
|
8092
|
-
FilterComponent,
|
|
8772
|
+
FilterComponent,
|
|
8773
|
+
StepedFormComponent, CollapsableDirective] }); }
|
|
8093
8774
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularComponentsModule, imports: [CrudFieldComponent,
|
|
8094
8775
|
CrudFormComponent,
|
|
8095
8776
|
EmptyStateComponent,
|
|
@@ -8099,7 +8780,8 @@ class ForAngularComponentsModule {
|
|
|
8099
8780
|
PaginationComponent,
|
|
8100
8781
|
CrudFormComponent,
|
|
8101
8782
|
FieldsetComponent,
|
|
8102
|
-
FilterComponent
|
|
8783
|
+
FilterComponent,
|
|
8784
|
+
StepedFormComponent] }); }
|
|
8103
8785
|
}
|
|
8104
8786
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ForAngularComponentsModule, decorators: [{
|
|
8105
8787
|
type: NgModule,
|
|
@@ -8125,5 +8807,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
8125
8807
|
* Generated bundle index. Do not edit.
|
|
8126
8808
|
*/
|
|
8127
8809
|
|
|
8128
|
-
export { AngularEngineKeys, BaseComponentProps, CollapsableDirective, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_PROVIDER_TOKEN, DefaultFormReactiveOptions, Dynamic, DynamicModule, EmptyStateComponent, EventConstants, FieldsetComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, FormConstants, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, LayoutComponent, ListComponent, ListComponentsTypes, ListItemComponent, LoggerLevels, ModelRendererComponent, MultiI18nLoader, NgxBaseComponent, NgxCrudFormField, NgxFormService, NgxRenderingEngine, PaginationComponent, RouteDirections, SearchbarComponent, cleanSpaces, dataMapper, formatDate, generateRandomValue, getI18nLoaderFactoryProviderConfig, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidDate, itemMapper, parseToValidDate, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
|
|
8810
|
+
export { AngularEngineKeys, BaseComponentProps, CollapsableDirective, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_PROVIDER_TOKEN, DefaultFormReactiveOptions, Dynamic, DynamicModule, EmptyStateComponent, EventConstants, FieldsetComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, FormConstants, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, LayoutComponent, ListComponent, ListComponentsTypes, ListItemComponent, LoggerLevels, ModelRendererComponent, MultiI18nLoader, NgxBaseComponent, NgxCrudFormField, NgxFormService, NgxRenderingEngine, PaginationComponent, RouteDirections, SearchbarComponent, StepedFormComponent, cleanSpaces, dataMapper, formatDate, generateRandomValue, getI18nLoaderFactoryProviderConfig, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidDate, itemMapper, parseToValidDate, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
|
|
8129
8811
|
//# sourceMappingURL=decaf-ts-for-angular.mjs.map
|