@decaf-ts/for-angular 0.0.35 → 0.0.37
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/fesm2022/decaf-ts-for-angular.mjs +998 -719
- package/fesm2022/decaf-ts-for-angular.mjs.map +1 -1
- package/index.d.ts +1174 -593
- package/package.json +5 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { UIKeys, HTML5InputTypes, parseValueByType, HTML5CheckTypes, escapeHtml, parseToNumber, RenderingEngine, RenderingError, UIMediaBreakPoints } from '@decaf-ts/ui-decorators';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
3
|
import { InjectionToken, NgModule, isDevMode, reflectComponentType, inject, ChangeDetectorRef, Renderer2, EventEmitter, ElementRef, Input, Output, ViewChild, Inject, Directive, EnvironmentInjector, ViewContainerRef, TemplateRef, ViewEncapsulation, Component, HostListener, CUSTOM_ELEMENTS_SCHEMA, Injector } from '@angular/core';
|
|
4
|
-
import { CommonModule,
|
|
4
|
+
import { CommonModule, Location, NgComponentOutlet } from '@angular/common';
|
|
5
5
|
import { VALIDATION_PARENT_KEY, ValidationKeys, DEFAULT_PATTERNS, Validation, Primitives, ComparisonValidationKeys, PathProxyEngine, Model, ModelKeys, isValidDate as isValidDate$1, parseDate, sf, ReservedModels } from '@decaf-ts/decorator-validation';
|
|
6
6
|
import { InternalError, OperationKeys } from '@decaf-ts/db-decorators';
|
|
7
7
|
import * as i1 from '@angular/forms';
|
|
@@ -11,9 +11,9 @@ import { TranslateModule, TranslatePipe, TranslateParser, provideTranslateServic
|
|
|
11
11
|
import { Logging, LoggedClass } from '@decaf-ts/logging';
|
|
12
12
|
import { uses, Repository, OrderDirection, Condition } from '@decaf-ts/core';
|
|
13
13
|
import { apply, metadata } from '@decaf-ts/reflection';
|
|
14
|
-
import { Router } from '@angular/router';
|
|
15
|
-
import { provideHttpClient, HttpClient } from '@angular/common/http';
|
|
14
|
+
import { Router, NavigationEnd, NavigationStart } from '@angular/router';
|
|
16
15
|
import { forkJoin, firstValueFrom, fromEvent, debounceTime, Subject, timer } from 'rxjs';
|
|
16
|
+
import { provideHttpClient, HttpClient } from '@angular/common/http';
|
|
17
17
|
import { map } from 'rxjs/operators';
|
|
18
18
|
import { MenuController, NavController } from '@ionic/angular';
|
|
19
19
|
import { Title, DomSanitizer } from '@angular/platform-browser';
|
|
@@ -22,12 +22,13 @@ import { IonInput, IonItem, IonCheckbox, IonRadioGroup, IonRadio, IonSelect, Ion
|
|
|
22
22
|
import { addIcons } from 'ionicons';
|
|
23
23
|
import * as allIcons from 'ionicons/icons';
|
|
24
24
|
import { chevronUpOutline, chevronDownOutline, createOutline, alertCircleOutline, chevronForwardOutline, chevronBackOutline, arrowBackOutline, arrowForwardOutline } from 'ionicons/icons';
|
|
25
|
-
import { NgxParentComponentDirective as NgxParentComponentDirective$1 } from 'src/lib/engine/NgxParentComponentDirective';
|
|
26
25
|
|
|
27
26
|
/**
|
|
28
|
-
* @description Angular engine key constants
|
|
27
|
+
* @description Angular engine key constants.
|
|
29
28
|
* @summary Contains key strings used by the Angular rendering engine for reflection,
|
|
30
|
-
* dynamic component creation, and other engine operations.
|
|
29
|
+
* dynamic component creation, and other engine operations. These constants provide
|
|
30
|
+
* consistent naming for metadata keys, DOM attributes, and component identification
|
|
31
|
+
* throughout the rendering system.
|
|
31
32
|
* @typedef {Object} AngularEngineKeys
|
|
32
33
|
* @property {string} REFLECT - Prefix for reflection metadata keys
|
|
33
34
|
* @property {string} DYNAMIC - Key for dynamic component identification
|
|
@@ -41,8 +42,10 @@ import { NgxParentComponentDirective as NgxParentComponentDirective$1 } from 'sr
|
|
|
41
42
|
* @property {string} RENDER - Key for renderable components
|
|
42
43
|
* @property {string} RENDERED_ID - Template for rendered component IDs
|
|
43
44
|
* @property {string} PARENT - Key for comparison decorators and validators
|
|
45
|
+
* @property {string} VALIDATION_PARENT_KEY - Key for validation parent reference
|
|
46
|
+
* @property {string} FLAVOUR - Identifier for the Angular engine flavor
|
|
44
47
|
* @const AngularEngineKeys
|
|
45
|
-
* @memberOf module:engine
|
|
48
|
+
* @memberOf module:lib/engine/constants
|
|
46
49
|
*/
|
|
47
50
|
const AngularEngineKeys = {
|
|
48
51
|
REFLECT: `${UIKeys.REFLECT}.angular.`,
|
|
@@ -58,32 +61,40 @@ const AngularEngineKeys = {
|
|
|
58
61
|
RENDERED_ID: 'rendered-as-{0}',
|
|
59
62
|
PARENT: '_parent',
|
|
60
63
|
VALIDATION_PARENT_KEY: VALIDATION_PARENT_KEY,
|
|
64
|
+
FLAVOUR: "angular",
|
|
61
65
|
};
|
|
62
66
|
/**
|
|
63
|
-
* @description Form validation state constants
|
|
67
|
+
* @description Form validation state constants.
|
|
64
68
|
* @summary Contains constants representing the possible validation states of a form.
|
|
65
69
|
* These are used to check and handle form validation throughout the application.
|
|
70
|
+
* The VALID state indicates all form controls pass validation, while INVALID
|
|
71
|
+
* indicates one or more validation errors exist.
|
|
66
72
|
* @typedef {Object} FormConstants
|
|
67
73
|
* @property {string} VALID - Constant representing a valid form state
|
|
68
74
|
* @property {string} INVALID - Constant representing an invalid form state
|
|
69
75
|
* @const FormConstants
|
|
70
|
-
* @memberOf module:engine
|
|
76
|
+
* @memberOf module:lib/engine/constants
|
|
71
77
|
*/
|
|
72
78
|
const FormConstants = {
|
|
73
79
|
VALID: 'VALID',
|
|
74
80
|
INVALID: 'INVALID',
|
|
75
81
|
};
|
|
76
82
|
/**
|
|
77
|
-
* @description Event name constants
|
|
78
|
-
* @summary
|
|
79
|
-
* These
|
|
80
|
-
*
|
|
81
|
-
* @
|
|
83
|
+
* @description Event name constants.
|
|
84
|
+
* @summary Contains constants for standardized event names used throughout the application.
|
|
85
|
+
* These constants ensure consistent event naming across components and make it easier to
|
|
86
|
+
* track and handle events. Each constant represents a specific application event type.
|
|
87
|
+
* @typedef {Object} EventConstants
|
|
82
88
|
* @property {string} BACK_BUTTON_NAVIGATION - Event fired when back button navigation ends
|
|
83
|
-
* @property {string}
|
|
84
|
-
* @property {string}
|
|
85
|
-
* @property {string}
|
|
86
|
-
* @
|
|
89
|
+
* @property {string} REFRESH - Event fired when a refresh action occurs
|
|
90
|
+
* @property {string} CLICK - Event fired when a click action occurs
|
|
91
|
+
* @property {string} SUBMIT - Event fired when a form submission occurs
|
|
92
|
+
* @property {string} VALIDATION_ERROR - Event fired when a validation error occurs
|
|
93
|
+
* @property {string} FIELDSET_ADD_GROUP - Event fired when adding a group to a fieldset
|
|
94
|
+
* @property {string} FIELDSET_UPDATE_GROUP - Event fired when updating a fieldset group
|
|
95
|
+
* @property {string} FIELDSET_REMOVE_GROUP - Event fired when removing a fieldset group
|
|
96
|
+
* @const EventConstants
|
|
97
|
+
* @memberOf module:lib/engine/constants
|
|
87
98
|
*/
|
|
88
99
|
const EventConstants = {
|
|
89
100
|
BACK_BUTTON_NAVIGATION: 'backButtonNavigationEndEvent',
|
|
@@ -97,9 +108,11 @@ const EventConstants = {
|
|
|
97
108
|
// FIELDSET_GROUP_VALIDATION: 'fieldsetGroupValidationEvent'
|
|
98
109
|
};
|
|
99
110
|
/**
|
|
100
|
-
* @description Logger level constants
|
|
101
|
-
* @summary
|
|
102
|
-
* Lower values represent more verbose logging, while higher values represent
|
|
111
|
+
* @description Logger level constants.
|
|
112
|
+
* @summary Defines the logging levels used in the application's logging system.
|
|
113
|
+
* Lower numeric values represent more verbose logging, while higher values represent
|
|
114
|
+
* more critical logs. These levels control which log messages are output based on
|
|
115
|
+
* the configured logging threshold.
|
|
103
116
|
* @enum {number}
|
|
104
117
|
* @readonly
|
|
105
118
|
* @property {number} ALL - Log everything (most verbose)
|
|
@@ -108,7 +121,7 @@ const EventConstants = {
|
|
|
108
121
|
* @property {number} WARN - Log warnings
|
|
109
122
|
* @property {number} ERROR - Log errors
|
|
110
123
|
* @property {number} CRITICAL - Log critical errors (least verbose)
|
|
111
|
-
* @memberOf module:engine
|
|
124
|
+
* @memberOf module:lib/engine/constants
|
|
112
125
|
*/
|
|
113
126
|
var LoggerLevels;
|
|
114
127
|
(function (LoggerLevels) {
|
|
@@ -121,15 +134,16 @@ var LoggerLevels;
|
|
|
121
134
|
})(LoggerLevels || (LoggerLevels = {}));
|
|
122
135
|
;
|
|
123
136
|
/**
|
|
124
|
-
* @description Route direction constants
|
|
125
|
-
* @summary
|
|
126
|
-
* Used for controlling navigation flow and animation directions.
|
|
137
|
+
* @description Route direction constants.
|
|
138
|
+
* @summary Defines the possible navigation directions in the application.
|
|
139
|
+
* Used for controlling navigation flow and animation directions during route transitions.
|
|
140
|
+
* These constants help maintain consistent navigation behavior throughout the app.
|
|
127
141
|
* @enum {string}
|
|
128
142
|
* @readonly
|
|
129
143
|
* @property {string} BACK - Navigate back to the previous page
|
|
130
144
|
* @property {string} FORWARD - Navigate forward to the next page
|
|
131
145
|
* @property {string} ROOT - Navigate to the root/home page
|
|
132
|
-
* @memberOf module:engine
|
|
146
|
+
* @memberOf module:lib/engine/constants
|
|
133
147
|
*/
|
|
134
148
|
var RouteDirections;
|
|
135
149
|
(function (RouteDirections) {
|
|
@@ -138,15 +152,18 @@ var RouteDirections;
|
|
|
138
152
|
RouteDirections["ROOT"] = "root";
|
|
139
153
|
})(RouteDirections || (RouteDirections = {}));
|
|
140
154
|
/**
|
|
141
|
-
* @description Component tag name constants
|
|
142
|
-
* @summary
|
|
143
|
-
* These tag names are used for component
|
|
155
|
+
* @description Component tag name constants.
|
|
156
|
+
* @summary Defines the custom HTML tag names for specialized components used in the application.
|
|
157
|
+
* These tag names are registered with Angular and used for component rendering and identification.
|
|
158
|
+
* Each constant represents the selector for a specific custom component type.
|
|
144
159
|
* @enum {string}
|
|
145
160
|
* @readonly
|
|
146
161
|
* @property {string} LIST_ITEM - Tag name for list item component
|
|
147
162
|
* @property {string} LIST_INFINITE - Tag name for infinite scrolling list component
|
|
148
163
|
* @property {string} LIST_PAGINATED - Tag name for paginated list component
|
|
149
|
-
* @
|
|
164
|
+
* @property {string} CRUD_FIELD - Tag name for CRUD form field component
|
|
165
|
+
* @property {string} LAYOUT_COMPONENT - Tag name for layout container component
|
|
166
|
+
* @memberOf module:lib/engine/constants
|
|
150
167
|
*/
|
|
151
168
|
var ComponentsTagNames;
|
|
152
169
|
(function (ComponentsTagNames) {
|
|
@@ -157,13 +174,16 @@ var ComponentsTagNames;
|
|
|
157
174
|
ComponentsTagNames["LAYOUT_COMPONENT"] = "ngx-decaf-layout";
|
|
158
175
|
})(ComponentsTagNames || (ComponentsTagNames = {}));
|
|
159
176
|
/**
|
|
160
|
-
* @description Base component property name constants
|
|
161
|
-
* @summary
|
|
162
|
-
* These
|
|
177
|
+
* @description Base component property name constants.
|
|
178
|
+
* @summary Defines the standard property names used by base components throughout the application.
|
|
179
|
+
* These constants ensure consistent property naming across components and facilitate
|
|
180
|
+
* property access, validation, and data binding. Used primarily for component input
|
|
181
|
+
* properties and change detection.
|
|
163
182
|
* @enum {string}
|
|
164
183
|
* @readonly
|
|
165
184
|
* @property {string} MODEL - Property name for the component's data model
|
|
166
185
|
* @property {string} LOCALE - Property name for localization settings
|
|
186
|
+
* @property {string} LOCALE_ROOT - Property name for the locale root identifier
|
|
167
187
|
* @property {string} PK - Property name for primary key
|
|
168
188
|
* @property {string} ITEMS - Property name for collection items
|
|
169
189
|
* @property {string} ROUTE - Property name for routing information
|
|
@@ -172,7 +192,10 @@ var ComponentsTagNames;
|
|
|
172
192
|
* @property {string} TRANSLATABLE - Property name for translation flag
|
|
173
193
|
* @property {string} MAPPER - Property name for property mapper
|
|
174
194
|
* @property {string} INITIALIZED - Property name for initialization state
|
|
175
|
-
* @
|
|
195
|
+
* @property {string} COMPONENT_NAME - Property name for component identifier
|
|
196
|
+
* @property {string} PARENT_COMPONENT - Property name for parent component reference
|
|
197
|
+
* @property {string} FORM_GROUP_COMPONENT_PROPS - Property name for form group component properties
|
|
198
|
+
* @memberOf module:lib/engine/constants
|
|
176
199
|
*/
|
|
177
200
|
var BaseComponentProps;
|
|
178
201
|
(function (BaseComponentProps) {
|
|
@@ -191,14 +214,48 @@ var BaseComponentProps;
|
|
|
191
214
|
BaseComponentProps["PARENT_COMPONENT"] = "parentComponent";
|
|
192
215
|
BaseComponentProps["FORM_GROUP_COMPONENT_PROPS"] = "componentProps";
|
|
193
216
|
})(BaseComponentProps || (BaseComponentProps = {}));
|
|
217
|
+
/**
|
|
218
|
+
* @description List component type constants.
|
|
219
|
+
* @summary Defines the available types for list components, determining their
|
|
220
|
+
* pagination and scrolling behavior. Used to configure list rendering strategies.
|
|
221
|
+
* @enum {string}
|
|
222
|
+
* @readonly
|
|
223
|
+
* @property {string} INFINITE - Infinite scroll list type
|
|
224
|
+
* @property {string} PAGINATED - Paginated list type with page navigation
|
|
225
|
+
* @memberOf module:lib/engine/constants
|
|
226
|
+
*/
|
|
194
227
|
var ListComponentsTypes;
|
|
195
228
|
(function (ListComponentsTypes) {
|
|
196
229
|
ListComponentsTypes["INFINITE"] = "infinite";
|
|
197
230
|
ListComponentsTypes["PAGINATED"] = "paginated";
|
|
198
231
|
})(ListComponentsTypes || (ListComponentsTypes = {}));
|
|
232
|
+
/**
|
|
233
|
+
* @description CSS class name constants.
|
|
234
|
+
* @summary Contains predefined CSS class names used for consistent styling
|
|
235
|
+
* across components. These constants help maintain a unified visual language
|
|
236
|
+
* and make it easier to apply standard styles.
|
|
237
|
+
* @typedef {Object} CssClasses
|
|
238
|
+
* @property {string} BUTTONS_CONTAINER - CSS class for button container elements
|
|
239
|
+
* @const CssClasses
|
|
240
|
+
* @memberOf module:lib/engine/constants
|
|
241
|
+
*/
|
|
199
242
|
const CssClasses = {
|
|
200
243
|
BUTTONS_CONTAINER: 'buttons-container',
|
|
201
244
|
};
|
|
245
|
+
/**
|
|
246
|
+
* @description Default options for reactive CRUD forms.
|
|
247
|
+
* @summary Provides default configuration for form buttons in CRUD operations.
|
|
248
|
+
* Includes default text labels for submit and clear buttons, which can be
|
|
249
|
+
* overridden by individual form implementations.
|
|
250
|
+
* @type {ICrudFormOptions}
|
|
251
|
+
* @property {Object} buttons - Configuration for form action buttons
|
|
252
|
+
* @property {Object} buttons.submit - Submit button configuration
|
|
253
|
+
* @property {string} buttons.submit.text - Default text for submit button
|
|
254
|
+
* @property {Object} buttons.clear - Clear button configuration
|
|
255
|
+
* @property {string} buttons.clear.text - Default text for clear button
|
|
256
|
+
* @const DefaultFormReactiveOptions
|
|
257
|
+
* @memberOf module:lib/engine/constants
|
|
258
|
+
*/
|
|
202
259
|
const DefaultFormReactiveOptions = {
|
|
203
260
|
buttons: {
|
|
204
261
|
submit: {
|
|
@@ -209,6 +266,30 @@ const DefaultFormReactiveOptions = {
|
|
|
209
266
|
},
|
|
210
267
|
},
|
|
211
268
|
};
|
|
269
|
+
/**
|
|
270
|
+
* @description Default options for empty list state display.
|
|
271
|
+
* @summary Provides default configuration for displaying empty state in list components
|
|
272
|
+
* when no data is available. Includes default text for title and subtitle, icon name,
|
|
273
|
+
* button text and visibility settings. These defaults can be overridden by individual
|
|
274
|
+
* list component implementations to customize the empty state presentation.
|
|
275
|
+
* @type {IListEmptyOptions}
|
|
276
|
+
* @property {string} title - Default translation key for empty list title
|
|
277
|
+
* @property {string} subtitle - Default translation key for empty list subtitle
|
|
278
|
+
* @property {boolean} showButton - Whether to show action button in empty state
|
|
279
|
+
* @property {string} icon - Default Ionic icon name for empty state
|
|
280
|
+
* @property {string} buttonText - Default translation key for button text
|
|
281
|
+
* @property {string} link - Default navigation link (empty string)
|
|
282
|
+
* @const DefaultListEmptyOptions
|
|
283
|
+
* @memberOf module:lib/engine/constants
|
|
284
|
+
*/
|
|
285
|
+
const DefaultListEmptyOptions = {
|
|
286
|
+
title: 'empty.title',
|
|
287
|
+
subtitle: 'empty.subtitle',
|
|
288
|
+
showButton: false,
|
|
289
|
+
icon: 'folder-open-outline',
|
|
290
|
+
buttonText: 'locale.empty.button',
|
|
291
|
+
link: ''
|
|
292
|
+
};
|
|
212
293
|
|
|
213
294
|
/**
|
|
214
295
|
* @module module:lib/engine/ValidatorFactory
|
|
@@ -707,11 +788,17 @@ function generateRandomValue(length = 8, onlyNumbers = false) {
|
|
|
707
788
|
return result;
|
|
708
789
|
}
|
|
709
790
|
/**
|
|
710
|
-
* Converts a string representation of a boolean or a boolean value to a boolean type.
|
|
791
|
+
* @description Converts a string representation of a boolean or a boolean value to a boolean type.
|
|
792
|
+
* @summary This utility function handles conversion of string-based boolean values ('true', 'false')
|
|
793
|
+
* to actual boolean types. It performs case-insensitive string comparison and returns the
|
|
794
|
+
* corresponding boolean value. This is particularly useful when parsing configuration values,
|
|
795
|
+
* URL parameters, or form inputs that may come as strings but need to be used as booleans.
|
|
711
796
|
*
|
|
712
|
-
* @
|
|
713
|
-
* @
|
|
714
|
-
*
|
|
797
|
+
* @param {'true' | 'false' | boolean} prop - The value to convert. Can be the string 'true', 'false', or a boolean
|
|
798
|
+
* @returns {boolean} The boolean representation of the input value. Returns true if the input is the string 'true' or boolean true, false otherwise
|
|
799
|
+
*
|
|
800
|
+
* @function stringToBoolean
|
|
801
|
+
* @memberOf module:lib/helpers/utils
|
|
715
802
|
*/
|
|
716
803
|
function stringToBoolean(prop) {
|
|
717
804
|
if (typeof prop === 'string')
|
|
@@ -719,10 +806,18 @@ function stringToBoolean(prop) {
|
|
|
719
806
|
return prop;
|
|
720
807
|
}
|
|
721
808
|
/**
|
|
722
|
-
* Checks if a value is a valid Date object
|
|
809
|
+
* @description Checks if a value is a valid Date object.
|
|
810
|
+
* @summary This validation function determines whether a given value represents a valid date.
|
|
811
|
+
* It handles multiple input types including Date objects, timestamp numbers, and date strings.
|
|
812
|
+
* For string inputs, it supports ISO 8601 format (YYYY-MM-DD) with or without time components.
|
|
813
|
+
* The function performs comprehensive validation including regex pattern matching and Date
|
|
814
|
+
* object creation to ensure the date is not only parseable but also represents a real date.
|
|
815
|
+
*
|
|
816
|
+
* @param {string | Date | number} date - The value to check. Can be a Date object, a timestamp number, or a date string
|
|
817
|
+
* @returns {boolean} Returns true if the value is a valid Date object (not NaN), otherwise false
|
|
723
818
|
*
|
|
724
|
-
* @
|
|
725
|
-
* @
|
|
819
|
+
* @function isValidDate
|
|
820
|
+
* @memberOf module:lib/helpers/utils
|
|
726
821
|
*/
|
|
727
822
|
function isValidDate(date) {
|
|
728
823
|
try {
|
|
@@ -742,12 +837,21 @@ function isValidDate(date) {
|
|
|
742
837
|
}
|
|
743
838
|
}
|
|
744
839
|
/**
|
|
745
|
-
* Formats a date into a localized string representation
|
|
840
|
+
* @description Formats a date into a localized string representation.
|
|
841
|
+
* @summary This function converts a date value into a formatted string according to a specified
|
|
842
|
+
* or system locale. It accepts multiple input formats (Date objects, timestamps, or date strings)
|
|
843
|
+
* and returns a consistently formatted date string in DD/MM/YYYY format. If the input date is
|
|
844
|
+
* invalid, the function returns the original input as a string. The function automatically
|
|
845
|
+
* uses the system locale if none is provided and handles string format conversions by replacing
|
|
846
|
+
* forward slashes with hyphens for proper Date parsing.
|
|
746
847
|
*
|
|
747
|
-
* @param {
|
|
848
|
+
* @param {string | Date | number} date - The date to format. Can be a Date object, a timestamp number, or a date string
|
|
748
849
|
* @param {string} [locale] - The locale to use for formatting. If not provided, the system's locale will be used
|
|
749
|
-
* @
|
|
750
|
-
*
|
|
850
|
+
* @returns {Date | string} A formatted date string in the format DD/MM/YYYY according to the specified locale,
|
|
851
|
+
* or the original input as a string if the date is invalid
|
|
852
|
+
*
|
|
853
|
+
* @function formatDate
|
|
854
|
+
* @memberOf module:lib/helpers/utils
|
|
751
855
|
*/
|
|
752
856
|
function formatDate(date, locale) {
|
|
753
857
|
if (!locale)
|
|
@@ -764,12 +868,21 @@ function formatDate(date, locale) {
|
|
|
764
868
|
return r;
|
|
765
869
|
}
|
|
766
870
|
/**
|
|
767
|
-
* Attempts to parse a date string, Date object, or number into a valid Date object
|
|
871
|
+
* @description Attempts to parse a date string, Date object, or number into a valid Date object.
|
|
872
|
+
* @summary This function provides robust date parsing functionality that handles the specific
|
|
873
|
+
* format "DD/MM/YYYY HH:MM:SS:MS". It first validates the input date, and if already valid,
|
|
874
|
+
* returns it as-is. For string inputs, it parses the date and time components separately,
|
|
875
|
+
* extracts numeric values, and constructs a new Date object. The function includes validation
|
|
876
|
+
* to ensure the resulting Date object is valid and logs a warning if parsing fails.
|
|
877
|
+
* Returns null for invalid or unsupported date formats.
|
|
878
|
+
*
|
|
879
|
+
* @param {string | Date | number} date - The date to parse. Can be a Date object, a timestamp number,
|
|
880
|
+
* or a date string in the format "DD/MM/YYYY HH:MM:SS:MS"
|
|
881
|
+
* @returns {Date | null} A valid Date object if parsing is successful, or null if the date is invalid
|
|
882
|
+
* or doesn't match the expected format
|
|
768
883
|
*
|
|
769
|
-
* @
|
|
770
|
-
*
|
|
771
|
-
* @return {(Date | null)} A valid Date object if parsing is successful, or null if the date is invalid
|
|
772
|
-
* or doesn't match the expected format
|
|
884
|
+
* @function parseToValidDate
|
|
885
|
+
* @memberOf module:lib/helpers/utils
|
|
773
886
|
*/
|
|
774
887
|
function parseToValidDate(date) {
|
|
775
888
|
if (isValidDate(date))
|
|
@@ -787,13 +900,22 @@ function parseToValidDate(date) {
|
|
|
787
900
|
return date;
|
|
788
901
|
}
|
|
789
902
|
/**
|
|
790
|
-
* Maps an item object using a provided mapper object and optional additional properties.
|
|
903
|
+
* @description Maps an item object using a provided mapper object and optional additional properties.
|
|
904
|
+
* @summary This function transforms a source object into a new object based on mapping rules defined
|
|
905
|
+
* in the mapper parameter. It supports dot notation for nested property access (e.g., 'user.name.first')
|
|
906
|
+
* and handles various data types including strings and complex objects. For date values, it automatically
|
|
907
|
+
* formats them using the formatDate function. The function also allows merging additional properties
|
|
908
|
+
* into the result. When a mapped value is null or undefined, it uses the original mapper value as
|
|
909
|
+
* a fallback.
|
|
791
910
|
*
|
|
792
|
-
* @param {KeyValue} item - The source object to be mapped
|
|
911
|
+
* @param {KeyValue} item - The source object to be mapped
|
|
793
912
|
* @param {KeyValue} mapper - An object that defines the mapping rules. Keys represent the new property names,
|
|
794
|
-
* and values represent the path to the corresponding values in the source object
|
|
795
|
-
* @param {KeyValue} [props] - Optional additional properties to be included in the mapped object
|
|
796
|
-
* @returns {KeyValue} A new object with properties mapped according to the mapper object and including any additional properties
|
|
913
|
+
* and values represent the path to the corresponding values in the source object
|
|
914
|
+
* @param {KeyValue} [props] - Optional additional properties to be included in the mapped object
|
|
915
|
+
* @returns {KeyValue} A new object with properties mapped according to the mapper object and including any additional properties
|
|
916
|
+
*
|
|
917
|
+
* @function itemMapper
|
|
918
|
+
* @memberOf module:lib/helpers/utils
|
|
797
919
|
*/
|
|
798
920
|
function itemMapper(item, mapper, props) {
|
|
799
921
|
return Object.entries(mapper).reduce((accum, [key, value]) => {
|
|
@@ -820,15 +942,23 @@ function itemMapper(item, mapper, props) {
|
|
|
820
942
|
}, {});
|
|
821
943
|
}
|
|
822
944
|
/**
|
|
823
|
-
* Maps an array of data objects using a provided mapper object.
|
|
945
|
+
* @description Maps an array of data objects using a provided mapper object.
|
|
946
|
+
* @summary This function transforms an array of objects by applying mapping rules to each item
|
|
947
|
+
* using the itemMapper function. It processes each element in the data array and creates
|
|
948
|
+
* new mapped objects based on the mapper configuration. The function includes validation
|
|
949
|
+
* to ensure meaningful data: if a mapped item contains only null/undefined values, it
|
|
950
|
+
* preserves the original item instead. This prevents data loss during transformation.
|
|
951
|
+
* Returns an empty array if the input data is null, undefined, or empty.
|
|
824
952
|
*
|
|
825
|
-
* @template T - The type of the resulting mapped items
|
|
826
|
-
* @param {
|
|
827
|
-
* @param {KeyValue} mapper - An object that defines the mapping rules
|
|
828
|
-
* @param {KeyValue} [props] - Additional properties to be included in the mapped items
|
|
953
|
+
* @template T - The type of the resulting mapped items
|
|
954
|
+
* @param {T[]} data - The array of data objects to be mapped
|
|
955
|
+
* @param {KeyValue} mapper - An object that defines the mapping rules
|
|
956
|
+
* @param {KeyValue} [props] - Additional properties to be included in the mapped items
|
|
957
|
+
* @returns {T[]} The array of mapped items. If an item in the original array does not have any non-null values after mapping,
|
|
958
|
+
* the original item is returned instead
|
|
829
959
|
*
|
|
830
|
-
* @
|
|
831
|
-
*
|
|
960
|
+
* @function dataMapper
|
|
961
|
+
* @memberOf module:lib/helpers/utils
|
|
832
962
|
*/
|
|
833
963
|
function dataMapper(data, mapper, props) {
|
|
834
964
|
if (!data || !data.length)
|
|
@@ -907,13 +1037,11 @@ async function isDarkMode() {
|
|
|
907
1037
|
*/
|
|
908
1038
|
|
|
909
1039
|
/**
|
|
910
|
-
* @module
|
|
1040
|
+
* @module lib/engine/NgxDecafFormService
|
|
911
1041
|
* @description Utilities to create and manage Angular forms in Decaf components.
|
|
912
1042
|
* @summary The NgxDecafFormService exposes helpers to build FormGroup/FormArray instances
|
|
913
1043
|
* from component metadata or UI model definitions, register forms in a registry,
|
|
914
1044
|
* validate and extract form data, and create controls with appropriate validators.
|
|
915
|
-
*
|
|
916
|
-
* @link {@link NgxDecafFormService}
|
|
917
1045
|
*/
|
|
918
1046
|
/**
|
|
919
1047
|
* @description Service for managing Angular forms and form controls.
|
|
@@ -936,7 +1064,6 @@ async function isDarkMode() {
|
|
|
936
1064
|
*
|
|
937
1065
|
* // Getting form data
|
|
938
1066
|
* const formData = NgxDecafFormService.getFormData(form);
|
|
939
|
-
*
|
|
940
1067
|
* @mermaid
|
|
941
1068
|
* sequenceDiagram
|
|
942
1069
|
* participant C as Component
|
|
@@ -958,46 +1085,42 @@ class NgxDecafFormService {
|
|
|
958
1085
|
* @description WeakMap that stores control properties for form controls.
|
|
959
1086
|
* @summary A WeakMap that associates AbstractControl instances with their corresponding FieldProperties.
|
|
960
1087
|
* This allows the service to track metadata for form controls without creating memory leaks.
|
|
961
|
-
*
|
|
962
1088
|
* @type {WeakMap<AbstractControl, FieldProperties>}
|
|
963
1089
|
* @private
|
|
964
1090
|
* @static
|
|
965
|
-
* @memberOf NgxDecafFormService
|
|
966
1091
|
*/
|
|
967
1092
|
static { this.controls = new WeakMap(); }
|
|
968
1093
|
/**
|
|
969
1094
|
* @description Registry of form groups indexed by their unique identifiers.
|
|
970
1095
|
* @summary A Map that stores FormGroup instances with their unique string identifiers.
|
|
971
1096
|
* This allows global access to registered forms throughout the application.
|
|
972
|
-
*
|
|
973
1097
|
* @type {Map<string, FormGroup>}
|
|
974
1098
|
* @private
|
|
975
1099
|
* @static
|
|
976
|
-
* @memberOf NgxDecafFormService
|
|
977
1100
|
*/
|
|
978
1101
|
static { this.formRegistry = new Map(); }
|
|
979
1102
|
/**
|
|
980
1103
|
* @description Creates a new form group or form array with the specified identifier.
|
|
981
|
-
* @summary Generates a FormGroup or FormArray based on the provided
|
|
982
|
-
*
|
|
983
|
-
*
|
|
984
|
-
*
|
|
1104
|
+
* @summary Generates a FormGroup or FormArray based on the provided parameters. If formArray is true,
|
|
1105
|
+
* creates a FormArray; otherwise creates a FormGroup. The form can optionally be registered in the
|
|
1106
|
+
* global form registry for later access throughout the application. If a form with the given id
|
|
1107
|
+
* already exists in the registry, it returns the existing form.
|
|
985
1108
|
* @param {string} id - Unique identifier for the form
|
|
986
|
-
* @param {
|
|
1109
|
+
* @param {boolean} [formArray=false] - Whether to create a FormArray instead of a FormGroup
|
|
987
1110
|
* @param {boolean} [registry=true] - Whether to register the form in the global registry
|
|
988
|
-
* @return {FormGroup | FormArray} The created form instance
|
|
989
|
-
*
|
|
1111
|
+
* @return {FormGroup | FormArray} The created or existing form instance
|
|
990
1112
|
* @mermaid
|
|
991
1113
|
* sequenceDiagram
|
|
992
1114
|
* participant C as Component
|
|
993
1115
|
* participant NFS as NgxDecafFormService
|
|
994
1116
|
* participant FR as Form Registry
|
|
995
1117
|
* participant AF as Angular Forms
|
|
996
|
-
*
|
|
997
|
-
* C->>NFS: createForm(id, props, registry)
|
|
1118
|
+
* C->>NFS: createForm(id, formArray, registry)
|
|
998
1119
|
* NFS->>FR: Check if form exists
|
|
999
|
-
* alt Form
|
|
1000
|
-
*
|
|
1120
|
+
* alt Form exists
|
|
1121
|
+
* FR-->>NFS: Return existing form
|
|
1122
|
+
* else Form doesn't exist
|
|
1123
|
+
* alt formArray is true
|
|
1001
1124
|
* NFS->>AF: new FormArray([])
|
|
1002
1125
|
* else
|
|
1003
1126
|
* NFS->>AF: new FormGroup({})
|
|
@@ -1007,9 +1130,7 @@ class NgxDecafFormService {
|
|
|
1007
1130
|
* end
|
|
1008
1131
|
* end
|
|
1009
1132
|
* NFS-->>C: Return FormGroup | FormArray
|
|
1010
|
-
*
|
|
1011
1133
|
* @static
|
|
1012
|
-
* @memberOf NgxDecafFormService
|
|
1013
1134
|
*/
|
|
1014
1135
|
static createForm(id, formArray = false, registry = true) {
|
|
1015
1136
|
const form = this.formRegistry.get(id) ?? (formArray ? new FormArray([]) : new FormGroup({}));
|
|
@@ -1022,20 +1143,26 @@ class NgxDecafFormService {
|
|
|
1022
1143
|
* @summary Registers a FormGroup or FormArray with a unique identifier for global access throughout
|
|
1023
1144
|
* the application. This allows forms to be retrieved and managed centrally. Throws an error if
|
|
1024
1145
|
* the identifier is already in use to prevent conflicts.
|
|
1025
|
-
*
|
|
1026
1146
|
* @param {string} formId - The unique identifier for the form
|
|
1027
1147
|
* @param {FormParent} formGroup - The FormGroup or FormArray to be registered
|
|
1028
1148
|
* @return {void}
|
|
1029
1149
|
* @throws {Error} If a FormGroup with the given id is already registered
|
|
1030
|
-
*
|
|
1031
1150
|
* @static
|
|
1032
|
-
* @memberOf NgxDecafFormService
|
|
1033
1151
|
*/
|
|
1034
1152
|
static addRegistry(formId, formGroup) {
|
|
1035
1153
|
if (this.formRegistry.has(formId))
|
|
1036
1154
|
throw new Error(`A FormGroup with id '${formId}' is already registered.`);
|
|
1037
1155
|
this.formRegistry.set(formId, formGroup);
|
|
1038
1156
|
}
|
|
1157
|
+
/**
|
|
1158
|
+
* @description Retrieves a form from the registry by its identifier.
|
|
1159
|
+
* @summary Gets a FormGroup or FormArray from the registry using its unique identifier.
|
|
1160
|
+
* Returns undefined if the form is not found in the registry. This method provides
|
|
1161
|
+
* safe access to registered forms without throwing errors.
|
|
1162
|
+
* @param {string} [id] - The unique identifier of the form to retrieve
|
|
1163
|
+
* @return {FormParent | undefined} The FormGroup or FormArray if found, undefined otherwise
|
|
1164
|
+
* @static
|
|
1165
|
+
*/
|
|
1039
1166
|
static getOnRegistry(id) {
|
|
1040
1167
|
return this.formRegistry.get(id);
|
|
1041
1168
|
}
|
|
@@ -1044,12 +1171,9 @@ class NgxDecafFormService {
|
|
|
1044
1171
|
* @summary Deletes a FormGroup or FormArray from the registry using its unique identifier.
|
|
1045
1172
|
* This cleans up the registry and allows the identifier to be reused. The form itself
|
|
1046
1173
|
* is not destroyed, only removed from the central registry.
|
|
1047
|
-
*
|
|
1048
1174
|
* @param {string} formId - The unique identifier of the form to be removed
|
|
1049
1175
|
* @return {void}
|
|
1050
|
-
*
|
|
1051
1176
|
* @static
|
|
1052
|
-
* @memberOf NgxDecafFormService
|
|
1053
1177
|
*/
|
|
1054
1178
|
static removeRegistry(formId) {
|
|
1055
1179
|
this.formRegistry.delete(formId);
|
|
@@ -1059,20 +1183,17 @@ class NgxDecafFormService {
|
|
|
1059
1183
|
* @summary Traverses the form group structure to find the parent group and control name for a given path.
|
|
1060
1184
|
* Handles complex nested structures including arrays and sub-groups. Creates missing intermediate
|
|
1061
1185
|
* groups as needed and properly configures FormArray controls for multiple value scenarios.
|
|
1062
|
-
*
|
|
1063
1186
|
* @param {FormGroup} formGroup - The root FormGroup to traverse
|
|
1064
1187
|
* @param {string} path - The dot-separated path to the control (e.g., 'user.address.street')
|
|
1065
1188
|
* @param {IComponentInput} componentProps - Properties defining the component configuration
|
|
1066
1189
|
* @param {KeyValue} parentProps - Properties from the parent component for context
|
|
1067
1190
|
* @return {FormParentGroup} A tuple containing the parent FormGroup and the control name
|
|
1068
|
-
*
|
|
1069
1191
|
* @private
|
|
1070
1192
|
* @mermaid
|
|
1071
1193
|
* sequenceDiagram
|
|
1072
1194
|
* participant NFS as NgxDecafFormService
|
|
1073
1195
|
* participant FG as FormGroup
|
|
1074
1196
|
* participant FA as FormArray
|
|
1075
|
-
*
|
|
1076
1197
|
* NFS->>NFS: Split path into parts
|
|
1077
1198
|
* loop For each path part
|
|
1078
1199
|
* alt Control doesn't exist
|
|
@@ -1086,9 +1207,7 @@ class NgxDecafFormService {
|
|
|
1086
1207
|
* NFS->>NFS: Navigate to next level
|
|
1087
1208
|
* end
|
|
1088
1209
|
* NFS-->>NFS: Return [parentGroup, controlName]
|
|
1089
|
-
*
|
|
1090
1210
|
* @static
|
|
1091
|
-
* @memberOf NgxDecafFormService
|
|
1092
1211
|
*/
|
|
1093
1212
|
static resolveParentGroup(formGroup, path, componentProps, parentProps) {
|
|
1094
1213
|
const isMultiple = parentProps?.multiple || parentProps?.type === Array.name || false;
|
|
@@ -1135,14 +1254,11 @@ class NgxDecafFormService {
|
|
|
1135
1254
|
* @description Retrieves component properties from a FormGroup or FormArray.
|
|
1136
1255
|
* @summary Extracts component properties stored in the form group metadata. If a FormGroup is provided
|
|
1137
1256
|
* and groupArrayName is specified, it will look for the FormArray within the form structure.
|
|
1138
|
-
*
|
|
1139
1257
|
* @param {FormGroup | FormArray} formGroup - The form group or form array to extract properties from
|
|
1140
1258
|
* @param {string} [key] - Optional key to retrieve a specific property
|
|
1141
1259
|
* @param {string} [groupArrayName] - Optional name of the group array if formGroup is not a FormArray
|
|
1142
1260
|
* @return {Partial<FieldProperties>} The component properties or a specific property if key is provided
|
|
1143
|
-
*
|
|
1144
1261
|
* @static
|
|
1145
|
-
* @memberOf NgxDecafFormService
|
|
1146
1262
|
*/
|
|
1147
1263
|
static getComponentPropsFromGroupArray(formGroup, key, groupArrayName) {
|
|
1148
1264
|
if (!(formGroup instanceof FormArray) && typeof groupArrayName === Primitives.STRING)
|
|
@@ -1154,14 +1270,12 @@ class NgxDecafFormService {
|
|
|
1154
1270
|
* @description Adds a new group to a parent FormArray.
|
|
1155
1271
|
* @summary Creates and adds a new FormGroup to the specified parent FormArray based on the
|
|
1156
1272
|
* component properties stored in the parent's metadata. This is used for dynamic form arrays
|
|
1157
|
-
* where new groups need to be added at runtime.
|
|
1158
|
-
*
|
|
1159
|
-
* @param {FormParent} parentForm - The
|
|
1160
|
-
* @param {number} index - The index position
|
|
1161
|
-
* @return {
|
|
1162
|
-
*
|
|
1273
|
+
* where new groups need to be added at runtime. Clones the control at the specified index
|
|
1274
|
+
* to maintain the same structure and validators.
|
|
1275
|
+
* @param {FormParent} parentForm - The FormArray or FormGroup containing the parent FormArray
|
|
1276
|
+
* @param {number} [index] - The index position to clone from; defaults to last index if length > 0, otherwise 0
|
|
1277
|
+
* @return {FormArray} The parent FormArray after adding the new group
|
|
1163
1278
|
* @static
|
|
1164
|
-
* @memberOf NgxDecafFormService
|
|
1165
1279
|
*/
|
|
1166
1280
|
static addGroupToParent(parentForm, index) {
|
|
1167
1281
|
if (parentForm instanceof FormGroup)
|
|
@@ -1174,14 +1288,11 @@ class NgxDecafFormService {
|
|
|
1174
1288
|
* @description Retrieves a FormGroup from a parent FormArray at the specified index.
|
|
1175
1289
|
* @summary Gets a FormGroup from the specified parent FormArray. If the group doesn't exist
|
|
1176
1290
|
* at the given index, it will create a new one using addGroupToParent.
|
|
1177
|
-
*
|
|
1178
|
-
* @param {FormGroup} formGroup - The root form group containing the parent FormArray
|
|
1291
|
+
* @param {FormParent} formGroup - The root form group containing the parent FormArray
|
|
1179
1292
|
* @param {string} parentName - The name of the parent FormArray to retrieve the group from
|
|
1180
1293
|
* @param {number} [index=1] - The index of the group to retrieve
|
|
1181
1294
|
* @return {FormGroup} The FormGroup at the specified index
|
|
1182
|
-
*
|
|
1183
1295
|
* @static
|
|
1184
|
-
* @memberOf NgxDecafFormService
|
|
1185
1296
|
*/
|
|
1186
1297
|
static getGroupFromParent(formGroup, parentName, index = 1) {
|
|
1187
1298
|
const childGroup = (formGroup.get(parentName) || formGroup).at(index);
|
|
@@ -1189,6 +1300,17 @@ class NgxDecafFormService {
|
|
|
1189
1300
|
return childGroup;
|
|
1190
1301
|
return this.addGroupToParent(formGroup, index).at(index);
|
|
1191
1302
|
}
|
|
1303
|
+
/**
|
|
1304
|
+
* @description Clones a form control with its validators.
|
|
1305
|
+
* @summary Creates a deep copy of a FormControl, FormGroup, or FormArray, preserving
|
|
1306
|
+
* validators but resetting values and state. This is useful for creating new instances
|
|
1307
|
+
* of form controls with the same validation rules, particularly in dynamic FormArrays
|
|
1308
|
+
* where new groups need to be added with identical structure.
|
|
1309
|
+
* @param {AbstractControl} control - The control to clone (FormControl, FormGroup, or FormArray)
|
|
1310
|
+
* @return {AbstractControl} A new instance of the control with the same validators
|
|
1311
|
+
* @throws {Error} If the control type is not supported
|
|
1312
|
+
* @static
|
|
1313
|
+
*/
|
|
1192
1314
|
static cloneFormControl(control) {
|
|
1193
1315
|
const syncValidators = (control.validator ? [control.validator] : []).filter(fn => {
|
|
1194
1316
|
// if(lastIndex > 0)
|
|
@@ -1226,14 +1348,13 @@ class NgxDecafFormService {
|
|
|
1226
1348
|
* @description Checks if a value is unique within a FormArray group.
|
|
1227
1349
|
* @summary Validates that the primary key value in a FormGroup is unique among all groups
|
|
1228
1350
|
* in the parent FormArray. The uniqueness check behavior differs based on the operation type.
|
|
1229
|
-
*
|
|
1351
|
+
* For both CREATE and UPDATE operations, it checks that no other group in the array has the same
|
|
1352
|
+
* primary key value.
|
|
1230
1353
|
* @param {FormGroup} formGroup - The FormGroup to check for uniqueness
|
|
1231
|
-
* @param {number} index - The index of the current group within the FormArray
|
|
1232
1354
|
* @param {OperationKeys} [operation=OperationKeys.CREATE] - The type of operation being performed
|
|
1355
|
+
* @param {number} [index] - The index of the current group within the FormArray
|
|
1233
1356
|
* @return {boolean} True if the value is unique, false otherwise
|
|
1234
|
-
*
|
|
1235
1357
|
* @static
|
|
1236
|
-
* @memberOf NgxDecafFormService
|
|
1237
1358
|
*/
|
|
1238
1359
|
static isUniqueOnGroup(formGroup, operation = OperationKeys.CREATE, index) {
|
|
1239
1360
|
const formArray = formGroup.parent;
|
|
@@ -1259,12 +1380,9 @@ class NgxDecafFormService {
|
|
|
1259
1380
|
* @description Enables all controls within a FormGroup or FormArray.
|
|
1260
1381
|
* @summary Recursively enables all form controls within the provided FormGroup or FormArray.
|
|
1261
1382
|
* This is useful for making all controls interactive after they have been disabled.
|
|
1262
|
-
*
|
|
1263
1383
|
* @param {FormArray | FormGroup} formGroup - The FormGroup or FormArray to enable all controls for
|
|
1264
1384
|
* @return {void}
|
|
1265
|
-
*
|
|
1266
1385
|
* @static
|
|
1267
|
-
* @memberOf NgxDecafFormService
|
|
1268
1386
|
*/
|
|
1269
1387
|
static enableAllGroupControls(formGroup) {
|
|
1270
1388
|
Object.keys(formGroup.controls).forEach(key => {
|
|
@@ -1283,17 +1401,15 @@ class NgxDecafFormService {
|
|
|
1283
1401
|
* @description Adds a form control to a form group based on component properties.
|
|
1284
1402
|
* @summary Creates and configures a FormControl within the specified FormGroup using the provided
|
|
1285
1403
|
* component properties. Handles nested paths, multiple controls (FormArrays), and control registration.
|
|
1286
|
-
* This method supports complex form structures with nested groups and arrays.
|
|
1287
|
-
*
|
|
1288
|
-
* @param {
|
|
1404
|
+
* This method supports complex form structures with nested groups and arrays. It also manages
|
|
1405
|
+
* page-based forms and FormArray indexing.
|
|
1406
|
+
* @param {FormParent} formGroup - The form group or form array to add the control to
|
|
1289
1407
|
* @param {IComponentInput} componentProps - The component properties defining the control configuration
|
|
1290
|
-
* @param {
|
|
1408
|
+
* @param {Partial<IComponentInput>} [parentProps={}] - Properties from the parent component for context
|
|
1291
1409
|
* @param {number} [index=0] - The index for multiple controls in FormArrays
|
|
1292
|
-
* @return {
|
|
1293
|
-
*
|
|
1410
|
+
* @return {FormParent} The updated form parent (FormGroup or FormArray)
|
|
1294
1411
|
* @private
|
|
1295
1412
|
* @static
|
|
1296
|
-
* @memberOf NgxDecafFormService
|
|
1297
1413
|
*/
|
|
1298
1414
|
static addFormControl(formGroup, componentProps, parentProps = {}, index = 0) {
|
|
1299
1415
|
const isMultiple = parentProps?.['multiple'] || parentProps?.['type'] === 'Array' || false;
|
|
@@ -1329,18 +1445,15 @@ class NgxDecafFormService {
|
|
|
1329
1445
|
* @summary Finds and returns an AbstractControl from a registered form using the form id and optional path.
|
|
1330
1446
|
* This method provides centralized access to form controls across the application by leveraging
|
|
1331
1447
|
* the form registry system.
|
|
1332
|
-
*
|
|
1333
1448
|
* @param {string} formId - The unique identifier of the form in the registry
|
|
1334
1449
|
* @param {string} [path] - The optional dot-separated path to a specific control within the form
|
|
1335
1450
|
* @return {AbstractControl} The requested AbstractControl (FormGroup, FormArray, or FormControl)
|
|
1336
1451
|
* @throws {Error} If the form is not found in the registry or the control is not found in the form
|
|
1337
|
-
*
|
|
1338
1452
|
* @mermaid
|
|
1339
1453
|
* sequenceDiagram
|
|
1340
1454
|
* participant C as Component
|
|
1341
1455
|
* participant NFS as NgxDecafFormService
|
|
1342
1456
|
* participant FR as Form Registry
|
|
1343
|
-
*
|
|
1344
1457
|
* C->>NFS: getControlFromForm(formId, path?)
|
|
1345
1458
|
* NFS->>FR: Get form by formId
|
|
1346
1459
|
* alt Form not found
|
|
@@ -1359,9 +1472,7 @@ class NgxDecafFormService {
|
|
|
1359
1472
|
* NFS-->>C: Return form
|
|
1360
1473
|
* end
|
|
1361
1474
|
* end
|
|
1362
|
-
*
|
|
1363
1475
|
* @static
|
|
1364
|
-
* @memberOf NgxDecafFormService
|
|
1365
1476
|
*/
|
|
1366
1477
|
static getControlFromForm(formId, path) {
|
|
1367
1478
|
const form = this.formRegistry.get(formId);
|
|
@@ -1379,18 +1490,15 @@ class NgxDecafFormService {
|
|
|
1379
1490
|
* @summary Generates a FormGroup from an array of UIModelMetadata objects, extracting component
|
|
1380
1491
|
* properties and creating appropriate form controls. This method is specifically designed to work
|
|
1381
1492
|
* with the UI decorator system and provides automatic form generation from metadata.
|
|
1382
|
-
*
|
|
1383
1493
|
* @param {string} id - Unique identifier for the form
|
|
1384
1494
|
* @param {boolean} [registry=false] - Whether to register the created form in the global registry
|
|
1385
1495
|
* @param {UIModelMetadata[]} [children] - Array of UI model metadata objects to create controls from
|
|
1386
1496
|
* @return {FormGroup} The created FormGroup with controls for each child metadata
|
|
1387
|
-
*
|
|
1388
1497
|
* @mermaid
|
|
1389
1498
|
* sequenceDiagram
|
|
1390
1499
|
* participant C as Component
|
|
1391
1500
|
* participant NFS as NgxDecafFormService
|
|
1392
1501
|
* participant AF as Angular Forms
|
|
1393
|
-
*
|
|
1394
1502
|
* C->>NFS: createFormFromChildren(id, registry, children)
|
|
1395
1503
|
* NFS->>AF: new FormGroup({})
|
|
1396
1504
|
* loop For each child metadata
|
|
@@ -1401,9 +1509,7 @@ class NgxDecafFormService {
|
|
|
1401
1509
|
* NFS->>NFS: addRegistry(id, form)
|
|
1402
1510
|
* end
|
|
1403
1511
|
* NFS-->>C: Return FormGroup
|
|
1404
|
-
*
|
|
1405
1512
|
* @static
|
|
1406
|
-
* @memberOf NgxDecafFormService
|
|
1407
1513
|
*/
|
|
1408
1514
|
static createFormFromChildren(id, registry = false, children) {
|
|
1409
1515
|
const form = new FormGroup({});
|
|
@@ -1420,18 +1526,15 @@ class NgxDecafFormService {
|
|
|
1420
1526
|
* @summary Generates a FormGroup based on an array of component configurations and optionally registers it.
|
|
1421
1527
|
* This method processes component input configurations to create appropriate form controls with
|
|
1422
1528
|
* validation and initial values.
|
|
1423
|
-
*
|
|
1424
1529
|
* @param {string} id - The unique identifier for the form
|
|
1425
1530
|
* @param {IComponentConfig[]} components - An array of component configurations defining the form structure
|
|
1426
1531
|
* @param {boolean} [registry=false] - Whether to register the created form in the global registry
|
|
1427
1532
|
* @return {FormGroup} The created FormGroup with controls for each component configuration
|
|
1428
|
-
*
|
|
1429
1533
|
* @mermaid
|
|
1430
1534
|
* sequenceDiagram
|
|
1431
1535
|
* participant C as Component
|
|
1432
1536
|
* participant NFS as NgxDecafFormService
|
|
1433
1537
|
* participant AF as Angular Forms
|
|
1434
|
-
*
|
|
1435
1538
|
* C->>NFS: createFormFromComponents(id, components, registry)
|
|
1436
1539
|
* NFS->>AF: new FormGroup({})
|
|
1437
1540
|
* loop For each component config
|
|
@@ -1442,9 +1545,7 @@ class NgxDecafFormService {
|
|
|
1442
1545
|
* NFS->>NFS: addRegistry(id, form)
|
|
1443
1546
|
* end
|
|
1444
1547
|
* NFS-->>C: Return FormGroup
|
|
1445
|
-
*
|
|
1446
1548
|
* @static
|
|
1447
|
-
* @memberOf NgxDecafFormService
|
|
1448
1549
|
*/
|
|
1449
1550
|
static createFormFromComponents(id, components, registry = false) {
|
|
1450
1551
|
const form = new FormGroup({});
|
|
@@ -1459,54 +1560,51 @@ class NgxDecafFormService {
|
|
|
1459
1560
|
* @description Adds a control to a form based on component properties.
|
|
1460
1561
|
* @summary Creates and adds a form control to a form (existing or new) based on the provided component properties.
|
|
1461
1562
|
* Handles multi-page forms by managing FormArray structures and proper indexing. This method supports
|
|
1462
|
-
* complex form scenarios including nested controls and page-based form organization.
|
|
1463
|
-
*
|
|
1563
|
+
* complex form scenarios including nested controls and page-based form organization. It automatically
|
|
1564
|
+
* creates FormArrays for forms with multiple pages and manages page indexing.
|
|
1464
1565
|
* @param {string} id - The unique identifier of the form
|
|
1465
1566
|
* @param {FieldProperties} componentProperties - The properties of the component to create the control from
|
|
1466
1567
|
* @param {FieldProperties} [parentProps] - Optional parent properties for context and configuration
|
|
1467
|
-
* @return {
|
|
1468
|
-
*
|
|
1568
|
+
* @return {FormParent} The form or created control (FormGroup or FormArray)
|
|
1569
|
+
* @throws {Error} If page property is required but not provided or is invalid
|
|
1469
1570
|
* @mermaid
|
|
1470
1571
|
* sequenceDiagram
|
|
1471
1572
|
* participant C as Component
|
|
1472
1573
|
* participant NFS as NgxDecafFormService
|
|
1473
1574
|
* participant F as Form
|
|
1474
|
-
*
|
|
1475
1575
|
* C->>NFS: addControlFromProps(id, componentProps, parentProps?)
|
|
1476
|
-
* NFS->>NFS: createForm(id,
|
|
1477
|
-
* alt Multi-page form (parentProps.pages >
|
|
1576
|
+
* NFS->>NFS: createForm(id, formArray, true)
|
|
1577
|
+
* alt Multi-page form (parentProps.pages > 0)
|
|
1478
1578
|
* NFS->>NFS: Calculate page index
|
|
1479
|
-
*
|
|
1579
|
+
* alt Group doesn't exist at index
|
|
1580
|
+
* NFS->>F: Create new FormGroup at index
|
|
1581
|
+
* end
|
|
1480
1582
|
* NFS->>NFS: Set form to page FormGroup
|
|
1481
1583
|
* end
|
|
1482
1584
|
* alt componentProperties has path
|
|
1483
1585
|
* NFS->>NFS: addFormControl(form, componentProperties, parentProps)
|
|
1484
1586
|
* end
|
|
1485
1587
|
* NFS-->>C: Return form/control
|
|
1486
|
-
*
|
|
1487
1588
|
* @static
|
|
1488
|
-
* @memberOf NgxDecafFormService
|
|
1489
1589
|
*/
|
|
1490
1590
|
static addControlFromProps(id, componentProperties, parentProps) {
|
|
1491
1591
|
const formArray = (componentProperties?.pages && componentProperties?.pages >= 1 || componentProperties.multiple === true);
|
|
1492
1592
|
let form = this.createForm(id, formArray, true);
|
|
1493
|
-
const formLength = form.length;
|
|
1494
1593
|
if (parentProps?.pages && parentProps?.pages > 0) {
|
|
1495
|
-
|
|
1594
|
+
const index = componentProperties.page || parentProps.page;
|
|
1496
1595
|
if (!(typeof index === 'number') || index === 0)
|
|
1497
1596
|
throw Error(`Property 'page' is required and greather than 0 on ${componentProperties.name}`);
|
|
1498
|
-
if
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
}
|
|
1597
|
+
// if(index > formLength) {
|
|
1598
|
+
// if((form as KeyValue)?.['lastIndex'] && index === (form as KeyValue)['lastIndex']['page']) {
|
|
1599
|
+
// index = (form as KeyValue)['lastIndex']['index'];
|
|
1600
|
+
// } else {
|
|
1601
|
+
// (form as KeyValue)['lastIndex'] = {
|
|
1602
|
+
// page: index,
|
|
1603
|
+
// index: formLength + 1
|
|
1604
|
+
// };
|
|
1605
|
+
// index = formLength + 1;
|
|
1606
|
+
// }
|
|
1607
|
+
// }
|
|
1510
1608
|
let group = form.controls[index - 1];
|
|
1511
1609
|
if (!group) {
|
|
1512
1610
|
group = new FormGroup({});
|
|
@@ -1523,17 +1621,14 @@ class NgxDecafFormService {
|
|
|
1523
1621
|
* @summary Extracts and processes the data from a FormGroup, handling different input types and nested form groups.
|
|
1524
1622
|
* Performs type conversion for various HTML5 input types, validates nested controls, and manages
|
|
1525
1623
|
* multiple control scenarios. Automatically enables all group controls after data extraction.
|
|
1526
|
-
*
|
|
1527
1624
|
* @param {FormGroup} formGroup - The FormGroup to extract data from
|
|
1528
1625
|
* @return {Record<string, unknown>} An object containing the processed form data with proper type conversions
|
|
1529
|
-
*
|
|
1530
1626
|
* @mermaid
|
|
1531
1627
|
* sequenceDiagram
|
|
1532
1628
|
* participant C as Component
|
|
1533
1629
|
* participant NFS as NgxDecafFormService
|
|
1534
1630
|
* participant FG as FormGroup
|
|
1535
1631
|
* participant FC as FormControl
|
|
1536
|
-
*
|
|
1537
1632
|
* C->>NFS: getFormData(formGroup)
|
|
1538
1633
|
* loop For each control in formGroup
|
|
1539
1634
|
* alt Control is not FormControl
|
|
@@ -1557,9 +1652,7 @@ class NgxDecafFormService {
|
|
|
1557
1652
|
* end
|
|
1558
1653
|
* NFS->>NFS: enableAllGroupControls(formGroup)
|
|
1559
1654
|
* NFS-->>C: Return processed data object
|
|
1560
|
-
*
|
|
1561
1655
|
* @static
|
|
1562
|
-
* @memberOf NgxDecafFormService
|
|
1563
1656
|
*/
|
|
1564
1657
|
static getFormData(formGroup) {
|
|
1565
1658
|
const data = {};
|
|
@@ -1610,13 +1703,11 @@ class NgxDecafFormService {
|
|
|
1610
1703
|
* @summary Recursively validates all fields in a form control or form group, marking them as touched and dirty.
|
|
1611
1704
|
* Performs comprehensive validation including uniqueness checks for primary keys in FormArray scenarios.
|
|
1612
1705
|
* This method ensures all validation rules are applied and form state is properly updated.
|
|
1613
|
-
*
|
|
1614
1706
|
* @param {AbstractControl} control - The control or form group to validate
|
|
1615
1707
|
* @param {string} [pk] - Optional primary key field name for uniqueness validation
|
|
1616
1708
|
* @param {string} [path] - The path to the control within the form for error reporting
|
|
1617
1709
|
* @return {boolean} True if all fields are valid, false otherwise
|
|
1618
1710
|
* @throws {Error} If no control is found at the specified path or if the control type is unknown
|
|
1619
|
-
*
|
|
1620
1711
|
* @mermaid
|
|
1621
1712
|
* sequenceDiagram
|
|
1622
1713
|
* participant C as Component
|
|
@@ -1624,7 +1715,6 @@ class NgxDecafFormService {
|
|
|
1624
1715
|
* participant FC as FormControl
|
|
1625
1716
|
* participant FG as FormGroup
|
|
1626
1717
|
* participant FA as FormArray
|
|
1627
|
-
*
|
|
1628
1718
|
* C->>NFS: validateFields(control, pk?, path?)
|
|
1629
1719
|
* alt Control is FormControl
|
|
1630
1720
|
* NFS->>FC: markAsTouched()
|
|
@@ -1650,9 +1740,7 @@ class NgxDecafFormService {
|
|
|
1650
1740
|
* else Unknown control type
|
|
1651
1741
|
* NFS-->>C: Throw Error
|
|
1652
1742
|
* end
|
|
1653
|
-
*
|
|
1654
1743
|
* @static
|
|
1655
|
-
* @memberOf NgxDecafFormService
|
|
1656
1744
|
*/
|
|
1657
1745
|
static validateFields(control, pk, path) {
|
|
1658
1746
|
control = path ? control.get(path) : control;
|
|
@@ -1703,8 +1791,12 @@ class NgxDecafFormService {
|
|
|
1703
1791
|
/**
|
|
1704
1792
|
* @description Generates validators from component properties.
|
|
1705
1793
|
* @summary Creates an array of ValidatorFn based on the supported validation keys in the component properties.
|
|
1706
|
-
*
|
|
1707
|
-
*
|
|
1794
|
+
* Maps each validation property to its corresponding Angular validator function using the ValidatorFactory.
|
|
1795
|
+
* Only processes properties that are recognized as validation keys by the Validation utility.
|
|
1796
|
+
* @param {KeyValue} props - The component properties containing validation rules
|
|
1797
|
+
* @return {ValidatorFn[]} An array of validator functions
|
|
1798
|
+
* @private
|
|
1799
|
+
* @static
|
|
1708
1800
|
*/
|
|
1709
1801
|
static validatorsFromProps(props) {
|
|
1710
1802
|
const supportedValidationKeys = Validation.keys();
|
|
@@ -1719,18 +1811,15 @@ class NgxDecafFormService {
|
|
|
1719
1811
|
* @summary Generates a FormControl with validators and initial configuration based on the provided
|
|
1720
1812
|
* component properties. Handles different input types, sets initial values, and configures
|
|
1721
1813
|
* validation rules and update modes.
|
|
1722
|
-
*
|
|
1723
1814
|
* @param {FieldProperties} props - The component properties defining the control configuration
|
|
1724
1815
|
* @param {FieldUpdateMode} [updateMode='change'] - The update mode for the control ('change', 'blur', 'submit')
|
|
1725
1816
|
* @return {FormControl} The created FormControl with proper configuration and validators
|
|
1726
|
-
*
|
|
1727
1817
|
* @mermaid
|
|
1728
1818
|
* sequenceDiagram
|
|
1729
1819
|
* participant C as Component
|
|
1730
1820
|
* participant NFS as NgxDecafFormService
|
|
1731
1821
|
* participant VF as ValidatorFactory
|
|
1732
1822
|
* participant AF as Angular Forms
|
|
1733
|
-
*
|
|
1734
1823
|
* C->>NFS: fromProps(props, updateMode?)
|
|
1735
1824
|
* NFS->>NFS: validatorsFromProps(props)
|
|
1736
1825
|
* NFS->>VF: Create validators from props
|
|
@@ -1745,9 +1834,7 @@ class NgxDecafFormService {
|
|
|
1745
1834
|
* NFS->>AF: new FormControl(config)
|
|
1746
1835
|
* AF-->>NFS: Return FormControl
|
|
1747
1836
|
* NFS-->>C: Return configured FormControl
|
|
1748
|
-
*
|
|
1749
1837
|
* @static
|
|
1750
|
-
* @memberOf NgxDecafFormService
|
|
1751
1838
|
*/
|
|
1752
1839
|
static fromProps(props, updateMode = 'change') {
|
|
1753
1840
|
const validators = this.validatorsFromProps(props);
|
|
@@ -1771,12 +1858,9 @@ class NgxDecafFormService {
|
|
|
1771
1858
|
* @summary Gets the FieldProperties associated with a form control from the internal WeakMap.
|
|
1772
1859
|
* This method provides access to the original component properties that were used to create
|
|
1773
1860
|
* the control, enabling validation, rendering, and behavior configuration.
|
|
1774
|
-
*
|
|
1775
1861
|
* @param {FormControl | FormArray | FormGroup} control - The form control to get properties for
|
|
1776
1862
|
* @return {FieldProperties} The properties associated with the control, or empty object if not found
|
|
1777
|
-
*
|
|
1778
1863
|
* @static
|
|
1779
|
-
* @memberOf NgxDecafFormService
|
|
1780
1864
|
*/
|
|
1781
1865
|
static getPropsFromControl(control) {
|
|
1782
1866
|
return this.controls.get(control) || {};
|
|
@@ -1786,18 +1870,15 @@ class NgxDecafFormService {
|
|
|
1786
1870
|
* @summary Traverses up the DOM tree to find the nearest parent element with the specified tag name.
|
|
1787
1871
|
* This is useful for finding container elements or specific parent components in the DOM hierarchy.
|
|
1788
1872
|
* The search is case-insensitive for tag name matching.
|
|
1789
|
-
*
|
|
1790
1873
|
* @param {HTMLElement} el - The starting element to traverse from
|
|
1791
1874
|
* @param {string} tag - The tag name to search for (case-insensitive)
|
|
1792
1875
|
* @return {HTMLElement} The found parent element with the specified tag
|
|
1793
1876
|
* @throws {Error} If no parent with the specified tag is found in the DOM tree
|
|
1794
|
-
*
|
|
1795
1877
|
* @mermaid
|
|
1796
1878
|
* sequenceDiagram
|
|
1797
1879
|
* participant C as Component
|
|
1798
1880
|
* participant NFS as NgxDecafFormService
|
|
1799
1881
|
* participant DOM as DOM Tree
|
|
1800
|
-
*
|
|
1801
1882
|
* C->>NFS: getParentEl(element, tagName)
|
|
1802
1883
|
* loop Traverse up DOM tree
|
|
1803
1884
|
* NFS->>DOM: Get parentElement
|
|
@@ -1808,9 +1889,7 @@ class NgxDecafFormService {
|
|
|
1808
1889
|
* NFS-->>C: Throw Error
|
|
1809
1890
|
* end
|
|
1810
1891
|
* end
|
|
1811
|
-
*
|
|
1812
1892
|
* @static
|
|
1813
|
-
* @memberOf NgxDecafFormService
|
|
1814
1893
|
*/
|
|
1815
1894
|
static getParentEl(el, tag) {
|
|
1816
1895
|
let parent;
|
|
@@ -1827,30 +1906,35 @@ class NgxDecafFormService {
|
|
|
1827
1906
|
* @summary Associates a form control with its component properties for later retrieval.
|
|
1828
1907
|
* This enables the service to maintain metadata about controls without creating memory leaks,
|
|
1829
1908
|
* as WeakMap automatically cleans up references when controls are garbage collected.
|
|
1830
|
-
*
|
|
1831
1909
|
* @param {AbstractControl} control - The control to register (FormControl, FormGroup, or FormArray)
|
|
1832
1910
|
* @param {FieldProperties} props - The properties to associate with the control
|
|
1833
1911
|
* @return {void}
|
|
1834
|
-
*
|
|
1835
1912
|
* @static
|
|
1836
|
-
* @memberOf NgxDecafFormService
|
|
1837
1913
|
*/
|
|
1838
1914
|
static register(control, props) {
|
|
1839
1915
|
this.controls.set(control, props);
|
|
1840
1916
|
}
|
|
1841
1917
|
/**
|
|
1842
|
-
* @description Unregisters a control.
|
|
1918
|
+
* @description Unregisters a control from the internal WeakMap.
|
|
1843
1919
|
* @summary Removes a control and its associated properties from the internal WeakMap.
|
|
1844
|
-
*
|
|
1845
|
-
*
|
|
1920
|
+
* This cleans up the metadata tracking for the control and frees up memory. Returns
|
|
1921
|
+
* true if the control was found and removed, false if it was not in the registry.
|
|
1922
|
+
* @param {AbstractControl} control - The control to unregister (FormControl, FormGroup, or FormArray)
|
|
1923
|
+
* @return {boolean} True if the control was successfully unregistered, false otherwise
|
|
1924
|
+
* @static
|
|
1846
1925
|
*/
|
|
1847
1926
|
static unregister(control) {
|
|
1848
1927
|
return this.controls.delete(control);
|
|
1849
1928
|
}
|
|
1850
1929
|
/**
|
|
1851
|
-
* @description Resets a form group.
|
|
1852
|
-
* @summary Recursively resets all controls in a form group
|
|
1853
|
-
*
|
|
1930
|
+
* @description Resets a form group or form control.
|
|
1931
|
+
* @summary Recursively resets all controls in a form group or a single form control, clearing values,
|
|
1932
|
+
* errors, and marking them as pristine and untouched. For FormControls, it sets the value to empty
|
|
1933
|
+
* string (except for checkbox types) and clears validation errors. For FormGroups, it recursively
|
|
1934
|
+
* resets all child controls.
|
|
1935
|
+
* @param {FormGroup | FormControl} formGroup - The form group or form control to reset
|
|
1936
|
+
* @return {void}
|
|
1937
|
+
* @static
|
|
1854
1938
|
*/
|
|
1855
1939
|
static reset(formGroup) {
|
|
1856
1940
|
if (formGroup instanceof FormControl) {
|
|
@@ -1874,32 +1958,29 @@ class NgxDecafFormService {
|
|
|
1874
1958
|
}
|
|
1875
1959
|
|
|
1876
1960
|
/**
|
|
1877
|
-
* @module
|
|
1961
|
+
* @module lib/engine/NgxRenderingEngine
|
|
1878
1962
|
* @description Angular rendering engine for Decaf model-driven UIs.
|
|
1879
1963
|
* @summary Implements NgxRenderingEngine which converts model decorator metadata
|
|
1880
1964
|
* into Angular components, manages component registration, and orchestrates
|
|
1881
1965
|
* dynamic component creation and input mapping.
|
|
1882
|
-
*
|
|
1883
1966
|
* @link {@link NgxRenderingEngine}
|
|
1884
1967
|
*/
|
|
1885
1968
|
/**
|
|
1886
|
-
* @description Angular implementation of the RenderingEngine
|
|
1887
|
-
* @summary This class extends the base RenderingEngine to provide Angular-specific rendering capabilities
|
|
1888
|
-
*
|
|
1889
|
-
*
|
|
1890
|
-
*
|
|
1891
|
-
*
|
|
1969
|
+
* @description Angular implementation of the RenderingEngine for Decaf components.
|
|
1970
|
+
* @summary This class extends the base RenderingEngine to provide Angular-specific rendering capabilities.
|
|
1971
|
+
* It handles the conversion of field definitions to Angular components, manages component registration,
|
|
1972
|
+
* and provides utilities for component creation and input handling. The engine converts model decorator
|
|
1973
|
+
* metadata into dynamically created Angular components with proper input binding and lifecycle management.
|
|
1892
1974
|
* @template AngularFieldDefinition - Type for Angular-specific field definitions
|
|
1893
1975
|
* @template AngularDynamicOutput - Type for Angular-specific component output
|
|
1894
|
-
*
|
|
1895
1976
|
* @class NgxRenderingEngine
|
|
1977
|
+
* @extends {RenderingEngine<AngularFieldDefinition, AngularDynamicOutput>}
|
|
1896
1978
|
* @example
|
|
1897
1979
|
* ```typescript
|
|
1898
1980
|
* const engine = NgxRenderingEngine.get();
|
|
1899
1981
|
* engine.initialize();
|
|
1900
1982
|
* const output = engine.render(myModel, {}, viewContainerRef, injector, templateRef);
|
|
1901
1983
|
* ```
|
|
1902
|
-
*
|
|
1903
1984
|
* @mermaid
|
|
1904
1985
|
* sequenceDiagram
|
|
1905
1986
|
* participant Client
|
|
@@ -1915,49 +1996,61 @@ class NgxDecafFormService {
|
|
|
1915
1996
|
* Components-->>Engine: component constructor
|
|
1916
1997
|
* Engine->>Engine: createComponent(component, inputs, metadata, vcr, injector, template)
|
|
1917
1998
|
* Engine-->>Client: return AngularDynamicOutput
|
|
1999
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
1918
2000
|
*/
|
|
1919
2001
|
class NgxRenderingEngine extends RenderingEngine {
|
|
1920
2002
|
/**
|
|
1921
|
-
* @description Current operation context for component visibility control
|
|
2003
|
+
* @description Current operation context for component visibility control.
|
|
1922
2004
|
* @summary Static property that stores the current operation being performed,
|
|
1923
2005
|
* which is used to determine component visibility through the 'hidden' property.
|
|
1924
2006
|
* Components can specify operations where they should be hidden, and this property
|
|
1925
2007
|
* provides the context for those visibility checks. The value is typically extracted
|
|
1926
2008
|
* from the global properties during the rendering process.
|
|
1927
|
-
*
|
|
1928
2009
|
* @private
|
|
1929
2010
|
* @static
|
|
1930
2011
|
* @type {string | undefined}
|
|
2012
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
1931
2013
|
*/
|
|
1932
2014
|
static { this._operation = undefined; }
|
|
1933
2015
|
// private static _projectable: boolean = true
|
|
2016
|
+
/**
|
|
2017
|
+
* @description Parent component properties for child component inheritance.
|
|
2018
|
+
* @summary Static property that stores parent component properties that should be
|
|
2019
|
+
* inherited by child components. This is particularly used for passing page configuration
|
|
2020
|
+
* down to child components in multi-page forms. The property is cleared after rendering
|
|
2021
|
+
* to prevent property leakage between unrelated component trees.
|
|
2022
|
+
* @private
|
|
2023
|
+
* @static
|
|
2024
|
+
* @type {KeyValue | undefined}
|
|
2025
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2026
|
+
*/
|
|
1934
2027
|
static { this._parentProps = undefined; }
|
|
1935
2028
|
/**
|
|
1936
|
-
* @description Constructs a new NgxRenderingEngine instance
|
|
2029
|
+
* @description Constructs a new NgxRenderingEngine instance.
|
|
1937
2030
|
* @summary Initializes a new instance of the Angular rendering engine by calling the parent
|
|
1938
2031
|
* constructor with the 'angular' engine type identifier. This constructor sets up the base
|
|
1939
2032
|
* rendering engine functionality with Angular-specific configurations and prepares the
|
|
1940
2033
|
* instance for component registration and rendering operations.
|
|
1941
|
-
*
|
|
1942
2034
|
* @constructor
|
|
2035
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
1943
2036
|
*/
|
|
1944
2037
|
constructor() {
|
|
1945
|
-
super(
|
|
2038
|
+
super(AngularEngineKeys.FLAVOUR);
|
|
1946
2039
|
}
|
|
1947
2040
|
/**
|
|
1948
|
-
* @description Converts a field definition to an Angular component output
|
|
2041
|
+
* @description Converts a field definition to an Angular component output.
|
|
1949
2042
|
* @summary This private method takes a field definition and creates the corresponding Angular component.
|
|
1950
|
-
* It handles component instantiation, input property mapping,
|
|
1951
|
-
* The method validates input properties against the component's metadata and processes
|
|
2043
|
+
* It handles component instantiation, input property mapping, child component rendering, and visibility
|
|
2044
|
+
* control. The method validates input properties against the component's metadata and processes
|
|
1952
2045
|
* child components recursively.
|
|
1953
|
-
*
|
|
1954
2046
|
* @param {FieldDefinition<AngularFieldDefinition>} fieldDef - The field definition to convert
|
|
1955
2047
|
* @param {ViewContainerRef} vcr - The view container reference for component creation
|
|
1956
2048
|
* @param {Injector} injector - The Angular injector for dependency injection
|
|
1957
2049
|
* @param {TemplateRef<any>} tpl - The template reference for content projection
|
|
1958
2050
|
* @param {string} registryFormId - Form identifier for the component renderer
|
|
2051
|
+
* @param {boolean} createComponent - Whether to create the component instance
|
|
2052
|
+
* @param {FormParent} [formGroup] - Optional form group for form components
|
|
1959
2053
|
* @return {AngularDynamicOutput} The Angular component output with component reference and inputs
|
|
1960
|
-
*
|
|
1961
2054
|
* @mermaid
|
|
1962
2055
|
* sequenceDiagram
|
|
1963
2056
|
* participant Method as fromFieldDefinition
|
|
@@ -1978,6 +2071,8 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
1978
2071
|
* Method->>Method: Create component instance
|
|
1979
2072
|
* end
|
|
1980
2073
|
* Method-->>Caller: return AngularDynamicOutput
|
|
2074
|
+
* @private
|
|
2075
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
1981
2076
|
*/
|
|
1982
2077
|
fromFieldDefinition(fieldDef, vcr, injector, tpl, registryFormId = Date.now().toString(36).toUpperCase(), createComponent = true, formGroup) {
|
|
1983
2078
|
const cmp = fieldDef?.['component'] || NgxRenderingEngine.components(fieldDef.tag);
|
|
@@ -2047,11 +2142,10 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2047
2142
|
return result;
|
|
2048
2143
|
}
|
|
2049
2144
|
/**
|
|
2050
|
-
* @description Creates an Angular component instance
|
|
2145
|
+
* @description Creates an Angular component instance with inputs and template projection.
|
|
2051
2146
|
* @summary This static utility method creates an Angular component instance with the specified
|
|
2052
2147
|
* inputs and template. It uses Angular's component creation API to instantiate the component
|
|
2053
2148
|
* and then sets the input properties using the provided metadata.
|
|
2054
|
-
*
|
|
2055
2149
|
* @param {Type<unknown>} component - The component type to create
|
|
2056
2150
|
* @param {KeyValue} [inputs={}] - The input properties to set on the component
|
|
2057
2151
|
* @param {ComponentMirror<unknown>} metadata - The component metadata for input validation
|
|
@@ -2059,6 +2153,8 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2059
2153
|
* @param {Injector} injector - The Angular injector for dependency injection
|
|
2060
2154
|
* @param {Node[]} [template=[]] - The template nodes to project into the component
|
|
2061
2155
|
* @return {ComponentRef<unknown>} The created component reference
|
|
2156
|
+
* @static
|
|
2157
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2062
2158
|
*/
|
|
2063
2159
|
static createComponent(component, inputs = {}, metadata, vcr, injector, template = []) {
|
|
2064
2160
|
const componentInstance = vcr.createComponent(component, {
|
|
@@ -2069,26 +2165,29 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2069
2165
|
return componentInstance;
|
|
2070
2166
|
}
|
|
2071
2167
|
/**
|
|
2072
|
-
* @description Extracts decorator metadata from a model
|
|
2168
|
+
* @description Extracts decorator metadata from a model.
|
|
2073
2169
|
* @summary This method provides access to the field definition generated from a model's
|
|
2074
2170
|
* decorators. It's a convenience wrapper around the toFieldDefinition method that
|
|
2075
2171
|
* converts a model to a field definition based on its decorators and the provided
|
|
2076
2172
|
* global properties.
|
|
2077
|
-
*
|
|
2078
2173
|
* @param {Model} model - The model to extract decorators from
|
|
2079
2174
|
* @param {Record<string, unknown>} globalProps - Global properties to include in the field definition
|
|
2080
2175
|
* @return {FieldDefinition<AngularFieldDefinition>} The field definition generated from the model
|
|
2176
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2081
2177
|
*/
|
|
2082
2178
|
getDecorators(model, globalProps) {
|
|
2083
2179
|
return this.toFieldDefinition(model, globalProps);
|
|
2084
2180
|
}
|
|
2085
2181
|
/**
|
|
2086
|
-
* @description Destroys the current engine instance
|
|
2087
|
-
* @summary This static method clears the current instance reference,
|
|
2088
|
-
* destroying the singleton instance of the rendering engine.
|
|
2089
|
-
*
|
|
2090
|
-
*
|
|
2182
|
+
* @description Destroys the current engine instance and cleans up resources.
|
|
2183
|
+
* @summary This static method clears the current instance reference and parent props,
|
|
2184
|
+
* effectively destroying the singleton instance of the rendering engine. Optionally
|
|
2185
|
+
* removes the form registry for the specified form ID. This can be used to reset the
|
|
2186
|
+
* engine state or to prepare for a new instance creation.
|
|
2187
|
+
* @param {string} [formId] - Optional form ID to remove from registry
|
|
2091
2188
|
* @return {Promise<void>} A promise that resolves when the instance is destroyed
|
|
2189
|
+
* @static
|
|
2190
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2092
2191
|
*/
|
|
2093
2192
|
static async destroy(formId) {
|
|
2094
2193
|
if (formId)
|
|
@@ -2097,12 +2196,11 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2097
2196
|
NgxRenderingEngine._parentProps = undefined;
|
|
2098
2197
|
}
|
|
2099
2198
|
/**
|
|
2100
|
-
* @description Renders a model into an Angular component output
|
|
2199
|
+
* @description Renders a model into an Angular component output.
|
|
2101
2200
|
* @summary This method takes a model and converts it to an Angular component output.
|
|
2102
2201
|
* It first stores a reference to the model, then converts it to a field definition
|
|
2103
2202
|
* using the base RenderingEngine's toFieldDefinition method, and finally converts
|
|
2104
2203
|
* that field definition to an Angular component output using fromFieldDefinition.
|
|
2105
|
-
*
|
|
2106
2204
|
* @template M - Type extending Model
|
|
2107
2205
|
* @param {M} model - The model to render
|
|
2108
2206
|
* @param {Record<string, unknown>} globalProps - Global properties to pass to the component
|
|
@@ -2110,7 +2208,6 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2110
2208
|
* @param {Injector} injector - The Angular injector for dependency injection
|
|
2111
2209
|
* @param {TemplateRef<any>} tpl - The template reference for content projection
|
|
2112
2210
|
* @return {AngularDynamicOutput} The Angular component output with component reference and inputs
|
|
2113
|
-
*
|
|
2114
2211
|
* @mermaid
|
|
2115
2212
|
* sequenceDiagram
|
|
2116
2213
|
* participant Client as Client Code
|
|
@@ -2125,6 +2222,8 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2125
2222
|
* Render->>FromField: fromFieldDefinition(fieldDef, vcr, injector, tpl)
|
|
2126
2223
|
* FromField-->>Render: AngularDynamicOutput
|
|
2127
2224
|
* Render-->>Client: return AngularDynamicOutput
|
|
2225
|
+
* @override
|
|
2226
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2128
2227
|
*/
|
|
2129
2228
|
render(model, globalProps, vcr, injector, tpl) {
|
|
2130
2229
|
let result;
|
|
@@ -2148,12 +2247,13 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2148
2247
|
return result;
|
|
2149
2248
|
}
|
|
2150
2249
|
/**
|
|
2151
|
-
* @description Initializes the rendering engine
|
|
2250
|
+
* @description Initializes the rendering engine.
|
|
2152
2251
|
* @summary This method initializes the rendering engine. It checks if the engine is already initialized
|
|
2153
2252
|
* and sets the initialized flag to true. This method is called before the engine is used
|
|
2154
2253
|
* to ensure it's properly set up for rendering operations.
|
|
2155
|
-
*
|
|
2156
2254
|
* @return {Promise<void>} A promise that resolves when initialization is complete
|
|
2255
|
+
* @override
|
|
2256
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2157
2257
|
*/
|
|
2158
2258
|
async initialize() {
|
|
2159
2259
|
if (this.initialized)
|
|
@@ -2162,15 +2262,16 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2162
2262
|
this.initialized = true;
|
|
2163
2263
|
}
|
|
2164
2264
|
/**
|
|
2165
|
-
* @description Registers a component with the rendering engine
|
|
2265
|
+
* @description Registers a component with the rendering engine.
|
|
2166
2266
|
* @summary This static method registers a component constructor with the rendering engine
|
|
2167
2267
|
* under a specific name. It initializes the components registry if needed and throws
|
|
2168
2268
|
* an error if a component is already registered under the same name to prevent
|
|
2169
2269
|
* accidental overrides.
|
|
2170
|
-
*
|
|
2171
2270
|
* @param {string} name - The name to register the component under
|
|
2172
2271
|
* @param {Constructor<unknown>} constructor - The component constructor
|
|
2173
2272
|
* @return {void}
|
|
2273
|
+
* @static
|
|
2274
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2174
2275
|
*/
|
|
2175
2276
|
static registerComponent(name, constructor) {
|
|
2176
2277
|
if (!this._components)
|
|
@@ -2182,14 +2283,15 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2182
2283
|
};
|
|
2183
2284
|
}
|
|
2184
2285
|
/**
|
|
2185
|
-
* @description Retrieves registered components from the rendering engine
|
|
2286
|
+
* @description Retrieves registered components from the rendering engine.
|
|
2186
2287
|
* @summary This static method retrieves either all registered components or a specific component
|
|
2187
2288
|
* by its selector. When called without a selector, it returns an array of all registered
|
|
2188
2289
|
* components. When called with a selector, it returns the specific component if found,
|
|
2189
2290
|
* or throws an error if the component is not registered.
|
|
2190
|
-
*
|
|
2191
2291
|
* @param {string} [selector] - Optional selector to retrieve a specific component
|
|
2192
2292
|
* @return {Object|Array} Either a specific component or an array of all components
|
|
2293
|
+
* @static
|
|
2294
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2193
2295
|
*/
|
|
2194
2296
|
static components(selector) {
|
|
2195
2297
|
if (!selector)
|
|
@@ -2199,30 +2301,30 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2199
2301
|
return this._components[selector];
|
|
2200
2302
|
}
|
|
2201
2303
|
/**
|
|
2202
|
-
* @description Generates a key for reflection metadata
|
|
2304
|
+
* @description Generates a key for reflection metadata storage.
|
|
2203
2305
|
* @summary This static method generates a key for reflection metadata by prefixing the input key
|
|
2204
2306
|
* with the Angular engine's reflection prefix. This is used for storing and retrieving
|
|
2205
2307
|
* metadata in a namespaced way to avoid conflicts with other metadata.
|
|
2206
|
-
*
|
|
2207
2308
|
* @param {string} key - The base key to prefix
|
|
2208
2309
|
* @return {string} The prefixed key for reflection metadata
|
|
2310
|
+
* @static
|
|
2311
|
+
* @override
|
|
2312
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2209
2313
|
*/
|
|
2210
2314
|
static key(key) {
|
|
2211
2315
|
return `${AngularEngineKeys.REFLECT}${key}`;
|
|
2212
2316
|
}
|
|
2213
2317
|
/**
|
|
2214
|
-
* @description Sets input properties on a component instance
|
|
2318
|
+
* @description Sets input properties on a component instance.
|
|
2215
2319
|
* @summary This static utility method sets input properties on a component instance
|
|
2216
2320
|
* based on the provided inputs object and component metadata. It handles both simple
|
|
2217
2321
|
* values and nested objects, recursively processing object properties. The method
|
|
2218
2322
|
* validates each input against the component's metadata to ensure only valid inputs
|
|
2219
2323
|
* are set.
|
|
2220
|
-
*
|
|
2221
2324
|
* @param {ComponentRef<unknown>} component - The component reference to set inputs on
|
|
2222
2325
|
* @param {KeyValue} inputs - The input properties to set
|
|
2223
2326
|
* @param {ComponentMirror<unknown>} metadata - The component metadata for input validation
|
|
2224
2327
|
* @return {void}
|
|
2225
|
-
*
|
|
2226
2328
|
* @mermaid
|
|
2227
2329
|
* sequenceDiagram
|
|
2228
2330
|
* participant Caller
|
|
@@ -2242,6 +2344,8 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2242
2344
|
* SetInputs->>Component: setInput(key, value)
|
|
2243
2345
|
* end
|
|
2244
2346
|
* end
|
|
2347
|
+
* @static
|
|
2348
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2245
2349
|
*/
|
|
2246
2350
|
static setInputs(component, inputs, metadata) {
|
|
2247
2351
|
function parseInputValue(component, input) {
|
|
@@ -2344,7 +2448,8 @@ var errors = {
|
|
|
2344
2448
|
lessThanOrEqual: "This field must be less than or equal to field {0}",
|
|
2345
2449
|
greaterThan: "This field must be greater than field {0}",
|
|
2346
2450
|
greaterThanOrEqual: "This field must be greater than or equal to field {0}",
|
|
2347
|
-
form_control: "Controlador do formulário não encontrado para {0}."
|
|
2451
|
+
form_control: "Controlador do formulário não encontrado para {0}.",
|
|
2452
|
+
not_found: "No records found with <span class=\"text-bold\">{0}: {1} in {2}</span>."
|
|
2348
2453
|
};
|
|
2349
2454
|
var component = {
|
|
2350
2455
|
fieldset: {
|
|
@@ -2378,7 +2483,7 @@ var component = {
|
|
|
2378
2483
|
},
|
|
2379
2484
|
empty_state: {
|
|
2380
2485
|
title: "No data found",
|
|
2381
|
-
|
|
2486
|
+
button_create: "Create",
|
|
2382
2487
|
search: {
|
|
2383
2488
|
title: "Not data found for search",
|
|
2384
2489
|
subtitle: "You searched for: <ion-text color=\"primary\" class=\"display-block ion-text-center text-bold\">{0}</ion-text>",
|
|
@@ -2507,12 +2612,11 @@ function provideI18n(config = { fallbackLang: 'en', lang: 'en' }, resources = []
|
|
|
2507
2612
|
}
|
|
2508
2613
|
|
|
2509
2614
|
/**
|
|
2510
|
-
* @module
|
|
2615
|
+
* @module lib/engine/NgxDecafComponentDirective
|
|
2511
2616
|
* @description Base decaf component abstraction providing shared inputs and utilities.
|
|
2512
2617
|
* @summary NgxDecafComponentDirective is the abstract foundation for Decaf components and provides common
|
|
2513
2618
|
* inputs (model, mapper, pk, props), logging, repository resolution, and event dispatch helpers.
|
|
2514
2619
|
* It centralizes shared behavior for child components and simplifies integration with the rendering engine.
|
|
2515
|
-
*
|
|
2516
2620
|
* @link {@link NgxDecafComponentDirective}
|
|
2517
2621
|
*/
|
|
2518
2622
|
try {
|
|
@@ -2521,194 +2625,250 @@ try {
|
|
|
2521
2625
|
catch (e) {
|
|
2522
2626
|
throw new Error(`Failed to load rendering engine: ${e}`);
|
|
2523
2627
|
}
|
|
2628
|
+
/**
|
|
2629
|
+
* @description Base directive for Decaf components in Angular applications.
|
|
2630
|
+
* @summary Abstract base class that provides common functionality for all Decaf components.
|
|
2631
|
+
* This directive establishes a foundation for component development by offering shared inputs
|
|
2632
|
+
* (model, mapper, pk, props), logging infrastructure, repository access, event handling, and
|
|
2633
|
+
* internationalization support. It implements OnChanges to respond to input property changes
|
|
2634
|
+
* and includes utilities for navigation, localization, and dynamic property binding. All Decaf
|
|
2635
|
+
* components should extend this directive to inherit its foundational capabilities.
|
|
2636
|
+
* @class NgxDecafComponentDirective
|
|
2637
|
+
* @extends {LoggedClass}
|
|
2638
|
+
* @implements {OnChanges}
|
|
2639
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2640
|
+
*/
|
|
2524
2641
|
class NgxDecafComponentDirective extends LoggedClass {
|
|
2642
|
+
/**
|
|
2643
|
+
* @description Constructor for NgxDecafComponentDirective.
|
|
2644
|
+
* @summary Initializes the directive by setting up the component name, locale root,
|
|
2645
|
+
* and logger. Calls the parent LoggedClass constructor and configures localization
|
|
2646
|
+
* context. The component name and locale root can be optionally injected via the
|
|
2647
|
+
* CPTKN token, otherwise defaults are used.
|
|
2648
|
+
* @param {string} [componentName] - Optional component name for identification and logging
|
|
2649
|
+
* @param {string} [localeRoot] - Optional locale root key for internationalization
|
|
2650
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2651
|
+
*/
|
|
2525
2652
|
// eslint-disable-next-line @angular-eslint/prefer-inject
|
|
2526
2653
|
constructor(componentName, localeRoot) {
|
|
2527
2654
|
super();
|
|
2528
|
-
this.componentName = componentName;
|
|
2529
|
-
this.localeRoot = localeRoot;
|
|
2530
2655
|
/**
|
|
2531
|
-
* @description Unique identifier for the
|
|
2532
|
-
* @summary A unique identifier
|
|
2533
|
-
* This is
|
|
2534
|
-
*
|
|
2656
|
+
* @description Unique identifier for the component instance.
|
|
2657
|
+
* @summary A unique identifier automatically generated for each component instance.
|
|
2658
|
+
* This UID is used for DOM element identification, component tracking, and debugging purposes.
|
|
2659
|
+
* By default, it generates a random 16-character value, but it can be explicitly set via input.
|
|
2535
2660
|
* @type {string | number}
|
|
2536
|
-
* @
|
|
2661
|
+
* @default generateRandomValue(16)
|
|
2662
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2537
2663
|
*/
|
|
2538
2664
|
this.uid = generateRandomValue(16);
|
|
2539
2665
|
/**
|
|
2540
|
-
* @description Field mapping configuration.
|
|
2666
|
+
* @description Field mapping configuration object or function.
|
|
2541
2667
|
* @summary Defines how fields from the data model should be mapped to properties used by the component.
|
|
2542
|
-
* This allows for flexible data binding between the model and the component's display logic.
|
|
2543
|
-
*
|
|
2544
|
-
* @type {Record<string, string>}
|
|
2545
|
-
* @
|
|
2668
|
+
* This allows for flexible data binding between the model and the component's display logic. Can be
|
|
2669
|
+
* provided as a static object mapping or as a function for dynamic mapping transformations.
|
|
2670
|
+
* @type {Record<string, string> | FunctionLike}
|
|
2671
|
+
* @default {}
|
|
2672
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2546
2673
|
*/
|
|
2547
2674
|
this.mapper = {};
|
|
2548
2675
|
/**
|
|
2549
|
-
* @description Available CRUD operations for this component.
|
|
2676
|
+
* @description Available CRUD operations for this component instance.
|
|
2550
2677
|
* @summary Defines which CRUD operations (Create, Read, Update, Delete) are available
|
|
2551
|
-
* for this component. This affects which operations can be performed on the data
|
|
2552
|
-
*
|
|
2678
|
+
* for this component. This affects which operations can be performed on the data and
|
|
2679
|
+
* which operation buttons are displayed in the UI. By default, only READ operations are enabled.
|
|
2680
|
+
* @type {CrudOperations[]}
|
|
2553
2681
|
* @default [OperationKeys.READ]
|
|
2554
|
-
* @memberOf NgxDecafComponentDirective
|
|
2682
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2555
2683
|
*/
|
|
2556
2684
|
this.operations = [OperationKeys.READ];
|
|
2557
2685
|
/**
|
|
2558
|
-
* @description
|
|
2559
|
-
* @summary Specifies which
|
|
2560
|
-
*
|
|
2686
|
+
* @description The CRUD operation type to be performed on the model.
|
|
2687
|
+
* @summary Specifies which operation (Create, Read, Update, Delete) this component instance
|
|
2688
|
+
* should perform. This determines the UI behavior, form configuration, and available actions.
|
|
2689
|
+
* The operation affects form validation, field availability, and the specific repository
|
|
2690
|
+
* method called during data submission.
|
|
2561
2691
|
*
|
|
2692
|
+
* @type {OperationKeys.CREATE | OperationKeys.READ | OperationKeys.UPDATE | OperationKeys.DELETE}
|
|
2693
|
+
* @default OperationKeys.READ
|
|
2694
|
+
* @memberOf ModelPage
|
|
2695
|
+
*/
|
|
2696
|
+
this.operation = OperationKeys.READ;
|
|
2697
|
+
/**
|
|
2698
|
+
* @description Row position in a grid-based layout system.
|
|
2699
|
+
* @summary Specifies the row position of this component when rendered within a grid-based layout.
|
|
2700
|
+
* This property is used for positioning components in multi-row, multi-column layouts and helps
|
|
2701
|
+
* establish the component's vertical placement within the grid structure.
|
|
2562
2702
|
* @type {number}
|
|
2563
2703
|
* @default 1
|
|
2564
|
-
* @memberOf NgxDecafComponentDirective
|
|
2704
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2565
2705
|
*/
|
|
2566
2706
|
this.row = 1;
|
|
2567
2707
|
/**
|
|
2568
|
-
* @description
|
|
2569
|
-
* @summary Specifies
|
|
2570
|
-
* This is
|
|
2571
|
-
*
|
|
2708
|
+
* @description Column position in a grid-based layout system.
|
|
2709
|
+
* @summary Specifies the column position of this component when rendered within a grid-based layout.
|
|
2710
|
+
* This property is used for positioning components in multi-row, multi-column layouts and helps
|
|
2711
|
+
* establish the component's horizontal placement within the grid structure.
|
|
2572
2712
|
* @type {number}
|
|
2573
2713
|
* @default 1
|
|
2574
|
-
* @memberOf NgxDecafComponentDirective
|
|
2714
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2575
2715
|
*/
|
|
2576
2716
|
this.col = 1;
|
|
2577
2717
|
/**
|
|
2578
|
-
* @description Additional CSS class names
|
|
2718
|
+
* @description Additional CSS class names for component styling.
|
|
2579
2719
|
* @summary Allows custom CSS classes to be added to the component's root element.
|
|
2580
2720
|
* These classes are appended to any automatically generated classes based on other
|
|
2581
2721
|
* component properties. Multiple classes can be provided as a space-separated string.
|
|
2582
2722
|
* This provides a way to customize the component's appearance beyond the built-in styling options.
|
|
2583
|
-
*
|
|
2584
2723
|
* @type {string}
|
|
2585
2724
|
* @default ""
|
|
2586
|
-
* @memberOf NgxDecafComponentDirective
|
|
2725
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2587
2726
|
*/
|
|
2588
2727
|
this.className = '';
|
|
2589
2728
|
/**
|
|
2590
|
-
* @description
|
|
2591
|
-
* @summary
|
|
2592
|
-
*
|
|
2593
|
-
* the application
|
|
2594
|
-
*
|
|
2595
|
-
* @
|
|
2729
|
+
* @description Ionic menu controller service for menu management.
|
|
2730
|
+
* @summary Injected service that provides programmatic control over Ionic menu components.
|
|
2731
|
+
* This service allows the component to open, close, toggle, and manage menu states within
|
|
2732
|
+
* the application. It provides access to menu functionality for implementing navigation
|
|
2733
|
+
* and layout features that require menu interaction.
|
|
2734
|
+
* @protected
|
|
2596
2735
|
* @type {MenuController}
|
|
2597
|
-
* @memberOf NgxDecafComponentDirective
|
|
2736
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2598
2737
|
*/
|
|
2599
2738
|
this.menuController = inject(MenuController);
|
|
2600
2739
|
/**
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
*/
|
|
2740
|
+
* @description Angular change detection service for manual change detection control.
|
|
2741
|
+
* @summary Injected service that provides manual control over change detection cycles.
|
|
2742
|
+
* This is essential for ensuring that programmatic DOM changes (like setting accordion
|
|
2743
|
+
* attributes) are properly reflected in the component's state and trigger appropriate
|
|
2744
|
+
* view updates when modifications occur outside the normal Angular change detection flow.
|
|
2745
|
+
* @protected
|
|
2746
|
+
* @type {ChangeDetectorRef}
|
|
2747
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2748
|
+
*/
|
|
2611
2749
|
this.changeDetectorRef = inject(ChangeDetectorRef);
|
|
2612
2750
|
/**
|
|
2613
|
-
* @description Angular Renderer2 service for
|
|
2751
|
+
* @description Angular Renderer2 service for platform-agnostic DOM manipulation.
|
|
2614
2752
|
* @summary Injected service that provides a safe, platform-agnostic way to manipulate DOM elements.
|
|
2615
2753
|
* This service ensures proper handling of DOM operations across different platforms and environments,
|
|
2616
|
-
* including server-side rendering and web workers.
|
|
2617
|
-
*
|
|
2754
|
+
* including server-side rendering and web workers, without direct DOM access.
|
|
2618
2755
|
* @protected
|
|
2619
2756
|
* @type {Renderer2}
|
|
2620
|
-
* @memberOf
|
|
2757
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2621
2758
|
*/
|
|
2622
2759
|
this.renderer = inject(Renderer2);
|
|
2623
2760
|
/**
|
|
2624
|
-
* @description Translation service for internationalization.
|
|
2761
|
+
* @description Translation service for application internationalization.
|
|
2625
2762
|
* @summary Injected service that provides translation capabilities for UI text.
|
|
2626
|
-
* Used to translate button labels
|
|
2627
|
-
*
|
|
2763
|
+
* Used to translate button labels, validation messages, and other text content based
|
|
2764
|
+
* on the current locale setting, enabling multilingual support throughout the application.
|
|
2628
2765
|
* @protected
|
|
2629
2766
|
* @type {TranslateService}
|
|
2630
|
-
* @memberOf
|
|
2767
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2631
2768
|
*/
|
|
2632
2769
|
this.translateService = inject(TranslateService);
|
|
2633
2770
|
/**
|
|
2634
|
-
* @description Event emitter for custom
|
|
2635
|
-
* @summary Emits custom events that occur within child components or the
|
|
2771
|
+
* @description Event emitter for custom component events.
|
|
2772
|
+
* @summary Emits custom events that occur within child components or the component itself.
|
|
2636
2773
|
* This allows parent components to listen for and respond to user interactions or
|
|
2637
|
-
* state changes
|
|
2638
|
-
*
|
|
2639
|
-
*
|
|
2774
|
+
* state changes. Events are passed up the component hierarchy to enable coordinated
|
|
2775
|
+
* behavior across the application.
|
|
2640
2776
|
* @type {EventEmitter<IBaseCustomEvent>}
|
|
2641
|
-
* @memberOf NgxDecafComponentDirective
|
|
2777
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2642
2778
|
*/
|
|
2643
2779
|
this.listenEvent = new EventEmitter();
|
|
2644
2780
|
/**
|
|
2645
|
-
* @description Angular Router instance for navigation
|
|
2646
|
-
* @summary Injected Router service used for programmatic navigation
|
|
2647
|
-
*
|
|
2648
|
-
*
|
|
2649
|
-
* @
|
|
2781
|
+
* @description Angular Router instance for programmatic navigation.
|
|
2782
|
+
* @summary Injected Router service used for programmatic navigation between routes
|
|
2783
|
+
* in the application. This service enables navigation to different views and operations,
|
|
2784
|
+
* handles route parameters, and manages the browser's navigation history.
|
|
2785
|
+
* @protected
|
|
2650
2786
|
* @type {Router}
|
|
2651
|
-
* @memberOf NgxDecafComponentDirective
|
|
2787
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2652
2788
|
*/
|
|
2653
2789
|
this.router = inject(Router);
|
|
2654
2790
|
/**
|
|
2655
|
-
* @description Configuration for list item rendering
|
|
2791
|
+
* @description Configuration for list item rendering behavior.
|
|
2656
2792
|
* @summary Defines how list items should be rendered in the component.
|
|
2657
2793
|
* This property holds a configuration object that specifies the tag name
|
|
2658
2794
|
* and other properties needed to render list items correctly. The tag property
|
|
2659
2795
|
* identifies which component should be used to render each item in a list.
|
|
2660
2796
|
* Additional properties can be included to customize the rendering behavior.
|
|
2661
|
-
*
|
|
2662
2797
|
* @type {Record<string, unknown>}
|
|
2663
2798
|
* @default {tag: ""}
|
|
2664
|
-
* @memberOf NgxDecafComponentDirective
|
|
2799
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2665
2800
|
*/
|
|
2666
2801
|
this.item = { tag: '' };
|
|
2667
2802
|
/**
|
|
2668
|
-
* @description Dynamic properties configuration
|
|
2803
|
+
* @description Dynamic properties configuration for runtime customization.
|
|
2669
2804
|
* @summary Contains key-value pairs of dynamic properties that can be applied to the component
|
|
2670
2805
|
* at runtime. This flexible configuration object allows for dynamic property assignment without
|
|
2671
2806
|
* requiring explicit input bindings for every possible configuration option. Properties from
|
|
2672
2807
|
* this object are parsed and applied to the component instance through the parseProps method,
|
|
2673
2808
|
* enabling customizable component behavior based on external configuration.
|
|
2674
|
-
*
|
|
2675
2809
|
* @type {Record<string, unknown>}
|
|
2676
2810
|
* @default {}
|
|
2677
|
-
* @memberOf NgxDecafComponentDirective
|
|
2811
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2678
2812
|
*/
|
|
2679
2813
|
this.props = {};
|
|
2680
2814
|
/**
|
|
2681
|
-
* @description
|
|
2815
|
+
* @description Initialization status flag for the component.
|
|
2682
2816
|
* @summary Tracks whether the component has completed its initialization process.
|
|
2683
2817
|
* This flag is used to prevent duplicate initialization and to determine if
|
|
2684
2818
|
* certain operations that require initialization can be performed.
|
|
2685
|
-
*
|
|
2686
2819
|
* @type {boolean}
|
|
2687
2820
|
* @default false
|
|
2688
|
-
* @memberOf NgxDecafComponentDirective
|
|
2821
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2689
2822
|
*/
|
|
2690
2823
|
this.initialized = false;
|
|
2691
|
-
|
|
2692
|
-
|
|
2824
|
+
/**
|
|
2825
|
+
* @description Reference to CRUD operation constants for template usage.
|
|
2826
|
+
* @summary Exposes the OperationKeys enum to the component template, enabling
|
|
2827
|
+
* conditional rendering and behavior based on operation types. This protected
|
|
2828
|
+
* readonly property ensures that template logic can access operation constants
|
|
2829
|
+
* while maintaining encapsulation and preventing accidental modification.
|
|
2830
|
+
* @protected
|
|
2831
|
+
* @readonly
|
|
2832
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2833
|
+
*/
|
|
2834
|
+
this.OperationKeys = OperationKeys;
|
|
2835
|
+
/**
|
|
2836
|
+
* @description Angular Location service.
|
|
2837
|
+
* @summary Injected service that provides access to the browser's URL and history.
|
|
2838
|
+
* This service is used for interacting with the browser's history API, allowing
|
|
2839
|
+
* for back navigation and URL manipulation outside of Angular's router.
|
|
2840
|
+
*
|
|
2841
|
+
* @private
|
|
2842
|
+
* @type {Location}
|
|
2843
|
+
*/
|
|
2844
|
+
this.location = inject(Location);
|
|
2845
|
+
this.componentName = componentName || "NgxDecafComponentDirective";
|
|
2846
|
+
this.localeRoot = localeRoot;
|
|
2847
|
+
if (!this.localeRoot && this.componentName)
|
|
2693
2848
|
this.localeRoot = this.componentName;
|
|
2849
|
+
if (this.localeRoot)
|
|
2850
|
+
this.getLocale(this.localeRoot);
|
|
2694
2851
|
this.logger = this.log;
|
|
2695
2852
|
}
|
|
2853
|
+
/**
|
|
2854
|
+
* @description Getter for the current locale context identifier.
|
|
2855
|
+
* @summary Returns the current locale identifier by calling the getLocale method.
|
|
2856
|
+
* This property provides convenient access to the component's active locale setting.
|
|
2857
|
+
* @returns {string} The current locale identifier
|
|
2858
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2859
|
+
*/
|
|
2696
2860
|
get localeContext() {
|
|
2697
2861
|
return this.getLocale();
|
|
2698
2862
|
}
|
|
2699
2863
|
/**
|
|
2700
|
-
* @description Getter for the repository instance.
|
|
2701
|
-
* @summary
|
|
2702
|
-
* This
|
|
2703
|
-
*
|
|
2704
|
-
*
|
|
2705
|
-
* The repository
|
|
2706
|
-
*
|
|
2707
|
-
*
|
|
2708
|
-
*
|
|
2709
|
-
* @returns {DecafRepository<Model>} The initialized repository instance.
|
|
2710
|
-
* @private
|
|
2711
|
-
* @memberOf NgxDecafComponentDirective
|
|
2864
|
+
* @description Getter for the data repository instance.
|
|
2865
|
+
* @summary Lazily initializes and returns the DecafRepository instance for the current model.
|
|
2866
|
+
* This getter ensures the repository is created only when needed and reused for subsequent
|
|
2867
|
+
* access. It also automatically sets the primary key field if not explicitly configured.
|
|
2868
|
+
* @protected
|
|
2869
|
+
* @returns {DecafRepository<Model>} The repository instance for the current model
|
|
2870
|
+
* @throws {InternalError} If repository initialization fails
|
|
2871
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2712
2872
|
*/
|
|
2713
2873
|
get repository() {
|
|
2714
2874
|
try {
|
|
@@ -2725,16 +2885,14 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2725
2885
|
return this._repository;
|
|
2726
2886
|
}
|
|
2727
2887
|
/**
|
|
2728
|
-
* @description
|
|
2729
|
-
* @summary
|
|
2730
|
-
*
|
|
2731
|
-
*
|
|
2732
|
-
* it
|
|
2733
|
-
*
|
|
2734
|
-
* the translation settings.
|
|
2735
|
-
*
|
|
2736
|
-
* @param {SimpleChanges} changes - Object containing changed properties
|
|
2888
|
+
* @description Angular lifecycle hook for handling input property changes.
|
|
2889
|
+
* @summary Responds to changes in component input properties, specifically monitoring changes
|
|
2890
|
+
* to the model, locale root, and component name properties. When the model changes, it triggers
|
|
2891
|
+
* model initialization and locale context updates. When locale-related properties change,
|
|
2892
|
+
* it updates the component's locale setting accordingly.
|
|
2893
|
+
* @param {SimpleChanges} changes - Object containing the changed properties with their previous and current values
|
|
2737
2894
|
* @return {void}
|
|
2895
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2738
2896
|
*/
|
|
2739
2897
|
ngOnChanges(changes) {
|
|
2740
2898
|
if (changes[BaseComponentProps.MODEL]) {
|
|
@@ -2746,6 +2904,18 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2746
2904
|
if (changes[BaseComponentProps.LOCALE_ROOT] || changes[BaseComponentProps.COMPONENT_NAME])
|
|
2747
2905
|
this.locale = this.localeContext;
|
|
2748
2906
|
}
|
|
2907
|
+
/**
|
|
2908
|
+
* @description Translates text phrases using the translation service.
|
|
2909
|
+
* @summary Provides a promise-based wrapper around the translation service to translate
|
|
2910
|
+
* UI text based on the current locale. Supports both single phrases and arrays of phrases,
|
|
2911
|
+
* and accepts optional parameters for template interpolation. When a string parameter is
|
|
2912
|
+
* provided, it's automatically converted to an object format for the translation service.
|
|
2913
|
+
* @protected
|
|
2914
|
+
* @param {string | string[]} phrase - The translation key or array of keys to translate
|
|
2915
|
+
* @param {object | string} [params] - Optional parameters for interpolation in translated text
|
|
2916
|
+
* @return {Promise<string>} A promise that resolves to the translated text
|
|
2917
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2918
|
+
*/
|
|
2749
2919
|
translate(phrase, params) {
|
|
2750
2920
|
return new Promise((resolve) => {
|
|
2751
2921
|
if (typeof params === Primitives.STRING)
|
|
@@ -2753,10 +2923,31 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2753
2923
|
return resolve(firstValueFrom(this.translateService.get(phrase, (params || {}))));
|
|
2754
2924
|
});
|
|
2755
2925
|
}
|
|
2926
|
+
/**
|
|
2927
|
+
* @description Initializes the component asynchronously with custom logic.
|
|
2928
|
+
* @summary Abstract initialization method that can be overridden by child components to perform
|
|
2929
|
+
* custom initialization logic. By default, it simply sets the initialized flag to true.
|
|
2930
|
+
* Child components can extend this method to load data, configure settings, or perform
|
|
2931
|
+
* other setup operations required before the component is fully functional.
|
|
2932
|
+
* @protected
|
|
2933
|
+
* @param {...unknown[]} args - Variable number of arguments that can be used by child implementations
|
|
2934
|
+
* @return {Promise<void>} A promise that resolves when initialization is complete
|
|
2935
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2936
|
+
*/
|
|
2756
2937
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2757
2938
|
async initialize(...args) {
|
|
2758
2939
|
this.initialized = true;
|
|
2759
2940
|
}
|
|
2941
|
+
/**
|
|
2942
|
+
* @description Retrieves or sets the locale context for the component.
|
|
2943
|
+
* @summary Gets the locale identifier from the locale context system. If a locale parameter
|
|
2944
|
+
* is provided, it updates the localeRoot property and resolves the new locale context.
|
|
2945
|
+
* If no locale is currently set, it initializes it from the localeRoot.
|
|
2946
|
+
* @protected
|
|
2947
|
+
* @param {string} [locale] - Optional locale identifier to set
|
|
2948
|
+
* @return {string} The current locale identifier
|
|
2949
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2950
|
+
*/
|
|
2760
2951
|
getLocale(locale) {
|
|
2761
2952
|
if (locale || !this.locale) {
|
|
2762
2953
|
if (locale)
|
|
@@ -2766,13 +2957,13 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2766
2957
|
return this.locale;
|
|
2767
2958
|
}
|
|
2768
2959
|
/**
|
|
2769
|
-
* @description
|
|
2770
|
-
* @summary
|
|
2771
|
-
*
|
|
2772
|
-
*
|
|
2773
|
-
*
|
|
2774
|
-
*
|
|
2775
|
-
* @
|
|
2960
|
+
* @description Retrieves or generates the route path for the component.
|
|
2961
|
+
* @summary Gets the navigation route associated with this component. If no route is explicitly
|
|
2962
|
+
* set and a model is available, it automatically generates a route based on the model's
|
|
2963
|
+
* class name using the pattern `/model/{ModelName}`. Returns an empty string if neither
|
|
2964
|
+
* a route nor a model is available.
|
|
2965
|
+
* @return {string} The route path for this component
|
|
2966
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2776
2967
|
*/
|
|
2777
2968
|
getRoute() {
|
|
2778
2969
|
if (!this.route && this.model instanceof Model)
|
|
@@ -2780,14 +2971,15 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2780
2971
|
return this.route || '';
|
|
2781
2972
|
}
|
|
2782
2973
|
/**
|
|
2783
|
-
* @description Resolves and
|
|
2784
|
-
* @summary
|
|
2785
|
-
*
|
|
2786
|
-
*
|
|
2787
|
-
* to
|
|
2788
|
-
*
|
|
2789
|
-
* @param {string | Model} model - The model
|
|
2974
|
+
* @description Resolves and initializes a model from various input formats.
|
|
2975
|
+
* @summary Accepts a model in multiple formats (string name, Model instance, or ModelConstructor)
|
|
2976
|
+
* and resolves it to a Model instance. When a string is provided, it looks up the model
|
|
2977
|
+
* by name in the Model registry. After resolution, it delegates to setModelDefinitions
|
|
2978
|
+
* to complete the model initialization and configuration.
|
|
2979
|
+
* @template M - The model type extending from Model
|
|
2980
|
+
* @param {string | Model | ModelConstructor<M>} model - The model to resolve and initialize
|
|
2790
2981
|
* @return {void}
|
|
2982
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2791
2983
|
*/
|
|
2792
2984
|
getModel(model) {
|
|
2793
2985
|
if (!(model instanceof Model) && typeof model === Primitives.STRING)
|
|
@@ -2795,16 +2987,16 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2795
2987
|
this.setModelDefinitions(this.model);
|
|
2796
2988
|
}
|
|
2797
2989
|
/**
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2990
|
+
* @description Configures component properties based on model decorators and metadata.
|
|
2991
|
+
* @summary Extracts rendering configuration from the model's decorators using the rendering
|
|
2992
|
+
* engine. This includes props, item configuration, and child component definitions. It sets
|
|
2993
|
+
* up the mapper for field transformations, configures the item renderer with appropriate
|
|
2994
|
+
* properties, and establishes the route for navigation. This method bridges the model's
|
|
2995
|
+
* decorator metadata with the component's runtime configuration.
|
|
2996
|
+
* @param {Model} model - The model instance to extract definitions from
|
|
2997
|
+
* @return {void}
|
|
2998
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2999
|
+
*/
|
|
2808
3000
|
setModelDefinitions(model) {
|
|
2809
3001
|
if (model instanceof Model) {
|
|
2810
3002
|
this.getRoute();
|
|
@@ -2830,33 +3022,34 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2830
3022
|
* component instance. This allows for dynamic property assignment based on configuration
|
|
2831
3023
|
* stored in the props object, enabling flexible component customization without requiring
|
|
2832
3024
|
* explicit property binding for every possible configuration option.
|
|
2833
|
-
*
|
|
2834
3025
|
* The method performs a safe property assignment by checking if each key from the instance
|
|
2835
3026
|
* exists in the props object before applying it. This prevents accidental property
|
|
2836
3027
|
* overwriting and ensures only intended properties are modified.
|
|
2837
|
-
*
|
|
2838
3028
|
* @param {KeyValue} instance - The component instance object to process
|
|
3029
|
+
* @param {string[]} [skip=[]] - Array of property names to skip during parsing
|
|
2839
3030
|
* @return {void}
|
|
2840
|
-
*
|
|
2841
3031
|
* @mermaid
|
|
2842
3032
|
* sequenceDiagram
|
|
2843
3033
|
* participant C as Component
|
|
2844
|
-
* participant
|
|
3034
|
+
* participant D as NgxDecafComponentDirective
|
|
2845
3035
|
* participant P as Props Object
|
|
2846
3036
|
*
|
|
2847
|
-
* C->>
|
|
2848
|
-
*
|
|
3037
|
+
* C->>D: parseProps(instance, skip)
|
|
3038
|
+
* D->>D: Get Object.keys(instance)
|
|
2849
3039
|
* loop For each key in instance
|
|
2850
|
-
*
|
|
2851
|
-
* alt Key
|
|
2852
|
-
*
|
|
2853
|
-
*
|
|
2854
|
-
*
|
|
3040
|
+
* D->>D: Check if key in skip array
|
|
3041
|
+
* alt Key not in skip
|
|
3042
|
+
* D->>P: Check if key exists in this.props
|
|
3043
|
+
* alt Key exists in props
|
|
3044
|
+
* D->>D: Set this[key] = this.props[key]
|
|
3045
|
+
* D->>P: delete this.props[key]
|
|
3046
|
+
* else Key not in props
|
|
3047
|
+
* Note over D: Skip this key
|
|
3048
|
+
* end
|
|
2855
3049
|
* end
|
|
2856
3050
|
* end
|
|
2857
|
-
*
|
|
2858
3051
|
* @protected
|
|
2859
|
-
* @memberOf
|
|
3052
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2860
3053
|
*/
|
|
2861
3054
|
parseProps(instance, skip = []) {
|
|
2862
3055
|
Object.keys(instance).forEach((key) => {
|
|
@@ -2867,21 +3060,55 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2867
3060
|
});
|
|
2868
3061
|
}
|
|
2869
3062
|
/**
|
|
2870
|
-
* @description Tracks items in ngFor loops for optimal change detection.
|
|
3063
|
+
* @description Tracks items in ngFor loops for optimal change detection performance.
|
|
2871
3064
|
* @summary Provides a tracking function for Angular's *ngFor directive to optimize rendering
|
|
2872
3065
|
* performance. This method generates unique identifiers for list items based on their index
|
|
2873
3066
|
* and content, allowing Angular to efficiently track changes and minimize DOM manipulations
|
|
2874
3067
|
* during list updates. The tracking function is essential for maintaining component state
|
|
2875
3068
|
* and preventing unnecessary re-rendering of unchanged items.
|
|
2876
|
-
*
|
|
3069
|
+
* @protected
|
|
2877
3070
|
* @param {number} index - The index of the item in the list
|
|
2878
3071
|
* @param {KeyValue | string | number} item - The item data to track
|
|
2879
|
-
* @
|
|
2880
|
-
* @memberOf NgxDecafComponentDirective
|
|
3072
|
+
* @return {string | number} A unique identifier for the item
|
|
3073
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2881
3074
|
*/
|
|
2882
3075
|
trackItemFn(index, item) {
|
|
2883
3076
|
return `${index}-${item}`;
|
|
2884
3077
|
}
|
|
3078
|
+
/**
|
|
3079
|
+
* @description Handles custom events from child components or DOM elements.
|
|
3080
|
+
* @summary Processes custom events by extracting event handlers and delegating to appropriate
|
|
3081
|
+
* handler classes. Supports both CustomEvent format with detail property and direct event
|
|
3082
|
+
* objects. If specific handlers are defined in the event, it instantiates the handler class
|
|
3083
|
+
* and invokes its handle method. If no handler is found or defined, the event is emitted
|
|
3084
|
+
* up the component hierarchy via the listenEvent output.
|
|
3085
|
+
* @param {IBaseCustomEvent | ICrudFormEvent | CustomEvent} event - The event to handle
|
|
3086
|
+
* @return {Promise<void>} A promise that resolves when event handling is complete
|
|
3087
|
+
* @mermaid
|
|
3088
|
+
* sequenceDiagram
|
|
3089
|
+
* participant C as Child Component
|
|
3090
|
+
* participant D as NgxDecafComponentDirective
|
|
3091
|
+
* participant H as Event Handler
|
|
3092
|
+
* participant P as Parent Component
|
|
3093
|
+
*
|
|
3094
|
+
* C->>D: handleEvent(event)
|
|
3095
|
+
* alt Event is CustomEvent
|
|
3096
|
+
* D->>D: Extract event.detail
|
|
3097
|
+
* end
|
|
3098
|
+
* D->>D: Get event name and handlers
|
|
3099
|
+
* alt Handlers defined
|
|
3100
|
+
* alt Handler exists for event
|
|
3101
|
+
* D->>H: new Handler(router)
|
|
3102
|
+
* D->>H: handle(event)
|
|
3103
|
+
* H-->>D: return result
|
|
3104
|
+
* else No handler found
|
|
3105
|
+
* D->>D: log.debug("No handler found")
|
|
3106
|
+
* end
|
|
3107
|
+
* else No handlers
|
|
3108
|
+
* D->>P: listenEvent.emit(event)
|
|
3109
|
+
* end
|
|
3110
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
3111
|
+
*/
|
|
2885
3112
|
async handleEvent(event) {
|
|
2886
3113
|
let name = "";
|
|
2887
3114
|
const log = this.log.for(this.handleEvent);
|
|
@@ -2908,8 +3135,70 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2908
3135
|
}
|
|
2909
3136
|
this.listenEvent.emit(event);
|
|
2910
3137
|
}
|
|
3138
|
+
/**
|
|
3139
|
+
* @description Determines if a specific operation is allowed in the current context.
|
|
3140
|
+
* @summary This method checks if an operation is included in the list of available
|
|
3141
|
+
* CRUD operations and if it's not the current operation (unless the current operation
|
|
3142
|
+
* is CREATE). This is used to enable/disable or show/hide operation buttons in the UI.
|
|
3143
|
+
* Returns false if the operations array is undefined or the operation is not in the list.
|
|
3144
|
+
* @param {string} operation - The operation to check
|
|
3145
|
+
* @return {boolean} True if the operation is allowed, false otherwise
|
|
3146
|
+
* @mermaid
|
|
3147
|
+
* sequenceDiagram
|
|
3148
|
+
* participant D as NgxDecafComponentDirective
|
|
3149
|
+
* participant U as UI
|
|
3150
|
+
*
|
|
3151
|
+
* U->>D: isAllowed(operation)
|
|
3152
|
+
* alt operations is undefined
|
|
3153
|
+
* D-->>U: Return false
|
|
3154
|
+
* else
|
|
3155
|
+
* D->>D: Check if operation is in operations
|
|
3156
|
+
* D->>D: Check if operation is not current operation
|
|
3157
|
+
* D-->>U: Return result
|
|
3158
|
+
* end
|
|
3159
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
3160
|
+
*/
|
|
3161
|
+
isAllowed(operation) {
|
|
3162
|
+
if (!this.operations)
|
|
3163
|
+
return false;
|
|
3164
|
+
return this.operations.includes(operation) && (this.operation !== OperationKeys.CREATE && ((this.operation || "").toLowerCase() !== operation || !this.operation));
|
|
3165
|
+
}
|
|
3166
|
+
/**
|
|
3167
|
+
* @description Navigates to a different operation for the current model.
|
|
3168
|
+
* @summary This method constructs a navigation URL based on the component's base route,
|
|
3169
|
+
* the requested operation, and optionally a model ID. It then uses the Angular router
|
|
3170
|
+
* service to navigate to the constructed URL. This is typically used when switching
|
|
3171
|
+
* between different CRUD operations (create, read, update, delete) on a model.
|
|
3172
|
+
* The URL format is: {route}/{operation}/{id?}
|
|
3173
|
+
* @param {string} operation - The operation to navigate to (e.g., 'create', 'read', 'update', 'delete')
|
|
3174
|
+
* @param {string} [id] - Optional model ID to include in the navigation URL
|
|
3175
|
+
* @return {Promise<boolean>} A promise that resolves to true if navigation was successful
|
|
3176
|
+
* @mermaid
|
|
3177
|
+
* sequenceDiagram
|
|
3178
|
+
* participant U as UI
|
|
3179
|
+
* participant D as NgxDecafComponentDirective
|
|
3180
|
+
* participant R as Router
|
|
3181
|
+
*
|
|
3182
|
+
* U->>D: Click operation button
|
|
3183
|
+
* D->>D: changeOperation(operation, id)
|
|
3184
|
+
* D->>D: Construct navigation URL
|
|
3185
|
+
* Note over D: URL: {route}/{operation}/{id?}
|
|
3186
|
+
* D->>R: navigateByUrl(page)
|
|
3187
|
+
* R->>R: Navigate to new route
|
|
3188
|
+
* R-->>D: Return navigation result
|
|
3189
|
+
* D-->>U: Display new operation view
|
|
3190
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
3191
|
+
*/
|
|
3192
|
+
async changeOperation(operation, id) {
|
|
3193
|
+
let page = `${this.route}/${operation}/`.replace('//', '/');
|
|
3194
|
+
if (!id)
|
|
3195
|
+
id = this.modelId;
|
|
3196
|
+
if (this.modelId)
|
|
3197
|
+
page = `${page}${this.modelId || id}`;
|
|
3198
|
+
return this.router.navigateByUrl(page);
|
|
3199
|
+
}
|
|
2911
3200
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NgxDecafComponentDirective, deps: [{ token: CPTKN }, { token: CPTKN }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2912
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.7", type: NgxDecafComponentDirective, isStandalone: true, inputs: { name: "name", childOf: "childOf", uid: "uid", model: "model", modelId: "modelId", pk: "pk", mapper: "mapper", operations: "operations", row: "row", col: "col", className: "className", locale: "locale", item: "item", props: "props", route: "route" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
|
|
3201
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.7", type: NgxDecafComponentDirective, isStandalone: true, inputs: { name: "name", childOf: "childOf", uid: "uid", model: "model", modelId: "modelId", pk: "pk", mapper: "mapper", operations: "operations", operation: "operation", row: "row", col: "col", className: "className", locale: "locale", item: "item", props: "props", route: "route" }, outputs: { listenEvent: "listenEvent" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, read: ElementRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
|
|
2913
3202
|
}
|
|
2914
3203
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NgxDecafComponentDirective, decorators: [{
|
|
2915
3204
|
type: Directive,
|
|
@@ -2939,6 +3228,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2939
3228
|
type: Input
|
|
2940
3229
|
}], operations: [{
|
|
2941
3230
|
type: Input
|
|
3231
|
+
}], operation: [{
|
|
3232
|
+
type: Input
|
|
2942
3233
|
}], row: [{
|
|
2943
3234
|
type: Input
|
|
2944
3235
|
}], col: [{
|
|
@@ -2958,12 +3249,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2958
3249
|
}] } });
|
|
2959
3250
|
|
|
2960
3251
|
/**
|
|
3252
|
+
* @module lib/engine/NgxDecafFormFieldDirective
|
|
3253
|
+
* @description Base directive for CRUD form fields in Decaf Angular applications.
|
|
3254
|
+
* @summary Provides the NgxDecafFormFieldDirective abstract class that implements ControlValueAccessor
|
|
3255
|
+
* and FieldProperties to enable form field integration with Angular's reactive forms system.
|
|
3256
|
+
* This directive handles form control lifecycle, validation, multi-entry forms, and CRUD operations.
|
|
3257
|
+
*/
|
|
3258
|
+
/**
|
|
3259
|
+
* @description Abstract base directive for CRUD form fields in Angular applications.
|
|
3260
|
+
* @summary Provides the foundation for all form field components in Decaf applications by implementing
|
|
3261
|
+
* Angular's ControlValueAccessor interface and FieldProperties for validation. This directive manages
|
|
3262
|
+
* form control integration, validation state, multi-entry forms (FormArrays), and CRUD operation context.
|
|
3263
|
+
* It handles form group lifecycle, error messaging, change detection, and parent-child form relationships.
|
|
3264
|
+
* Extend this class to create custom form field components that seamlessly integrate with Angular's
|
|
3265
|
+
* reactive forms and Decaf's validation system.
|
|
2961
3266
|
* @class NgxDecafFormFieldDirective
|
|
2962
|
-
* @
|
|
3267
|
+
* @extends {NgxDecafComponentDirective}
|
|
2963
3268
|
* @implements {ControlValueAccessor}
|
|
2964
|
-
* @
|
|
2965
|
-
* @
|
|
2966
|
-
*
|
|
3269
|
+
* @implements {FieldProperties}
|
|
3270
|
+
* @example
|
|
3271
|
+
* ```typescript
|
|
3272
|
+
* @Component({
|
|
3273
|
+
* selector: 'app-text-field',
|
|
3274
|
+
* templateUrl: './text-field.component.html',
|
|
3275
|
+
* providers: [{
|
|
3276
|
+
* provide: NG_VALUE_ACCESSOR,
|
|
3277
|
+
* useExisting: forwardRef(() => TextFieldComponent),
|
|
3278
|
+
* multi: true
|
|
3279
|
+
* }]
|
|
3280
|
+
* })
|
|
3281
|
+
* export class TextFieldComponent extends NgxDecafFormFieldDirective {
|
|
3282
|
+
* constructor() {
|
|
3283
|
+
* super();
|
|
3284
|
+
* }
|
|
3285
|
+
* }
|
|
3286
|
+
* ```
|
|
2967
3287
|
*/
|
|
2968
3288
|
class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
|
|
2969
3289
|
constructor() {
|
|
@@ -2973,40 +3293,51 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
|
|
|
2973
3293
|
* @summary When working with multiple form groups (form arrays), this indicates
|
|
2974
3294
|
* which form group is currently active or being edited. This is used to manage
|
|
2975
3295
|
* focus and data binding in multi-entry scenarios.
|
|
2976
|
-
*
|
|
2977
3296
|
* @type {number}
|
|
2978
3297
|
* @default 0
|
|
2979
|
-
* @
|
|
3298
|
+
* @public
|
|
2980
3299
|
*/
|
|
2981
3300
|
this.activeFormGroupIndex = 0;
|
|
3301
|
+
this.operation = OperationKeys.CREATE;
|
|
2982
3302
|
/**
|
|
2983
|
-
* @description Field mapping configuration.
|
|
3303
|
+
* @description Field mapping configuration for options.
|
|
2984
3304
|
* @summary Defines how fields from the data model should be mapped to properties used by the component.
|
|
2985
3305
|
* This allows for flexible data binding between the model and the component's display logic.
|
|
2986
|
-
*
|
|
3306
|
+
* Can be either a key-value mapping object or a function that performs the mapping.
|
|
2987
3307
|
* @type {KeyValue | FunctionLike}
|
|
2988
|
-
* @
|
|
3308
|
+
* @public
|
|
2989
3309
|
*/
|
|
2990
3310
|
this.optionsMapper = {};
|
|
3311
|
+
/**
|
|
3312
|
+
* @description Flag tracking if validation error event has been dispatched.
|
|
3313
|
+
* @summary Prevents duplicate validation error events from being dispatched.
|
|
3314
|
+
* @type {boolean}
|
|
3315
|
+
* @private
|
|
3316
|
+
*/
|
|
2991
3317
|
this.validationErrorEventDispatched = false;
|
|
2992
|
-
// protected constructor() {}
|
|
2993
3318
|
/**
|
|
2994
|
-
* @
|
|
2995
|
-
* @
|
|
2996
|
-
*
|
|
3319
|
+
* @description String formatting utility function.
|
|
3320
|
+
* @summary Provides access to the sf (string format) function for formatting error messages
|
|
3321
|
+
* and other string templates. Used primarily for localizing and parameterizing validation messages.
|
|
3322
|
+
* @type {function(string, ...string): string}
|
|
3323
|
+
* @public
|
|
2997
3324
|
*/
|
|
2998
3325
|
this.sf = sf;
|
|
2999
3326
|
/**
|
|
3000
|
-
* @
|
|
3001
|
-
* @
|
|
3002
|
-
*
|
|
3327
|
+
* @description Callback function invoked when the field value changes.
|
|
3328
|
+
* @summary Function registered by Angular's forms system through registerOnChange.
|
|
3329
|
+
* Called automatically when the field's value is updated to notify the form of the change.
|
|
3330
|
+
* @type {function(): unknown}
|
|
3331
|
+
* @public
|
|
3003
3332
|
*/
|
|
3004
3333
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
3005
3334
|
this.onChange = () => { };
|
|
3006
3335
|
/**
|
|
3007
|
-
* @
|
|
3008
|
-
* @
|
|
3009
|
-
*
|
|
3336
|
+
* @description Callback function invoked when the field is touched.
|
|
3337
|
+
* @summary Function registered by Angular's forms system through registerOnTouched.
|
|
3338
|
+
* Called when the field is blurred or otherwise marked as touched.
|
|
3339
|
+
* @type {function(): unknown}
|
|
3340
|
+
* @public
|
|
3010
3341
|
*/
|
|
3011
3342
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
3012
3343
|
this.onTouch = () => { };
|
|
@@ -3016,9 +3347,9 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
|
|
|
3016
3347
|
* @summary Returns the appropriate FormGroup based on whether this field supports
|
|
3017
3348
|
* multiple values. For single-value fields, returns the main form group.
|
|
3018
3349
|
* For multi-value fields, returns the form group at the active index from the parent FormArray.
|
|
3019
|
-
*
|
|
3020
|
-
* @
|
|
3021
|
-
* @
|
|
3350
|
+
* If no formGroup is set, returns the parent of the formControl.
|
|
3351
|
+
* @return {FormGroup} The currently active FormGroup for this field
|
|
3352
|
+
* @public
|
|
3022
3353
|
*/
|
|
3023
3354
|
get activeFormGroup() {
|
|
3024
3355
|
if (!this.formGroup)
|
|
@@ -3029,53 +3360,61 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
|
|
|
3029
3360
|
return this.formGroup;
|
|
3030
3361
|
}
|
|
3031
3362
|
return this.formGroup;
|
|
3032
|
-
// const formGroup = this.formGroup as FormGroup;
|
|
3033
|
-
// try {
|
|
3034
|
-
// const root = formGroup.root as FormGroup;
|
|
3035
|
-
// return this.multiple
|
|
3036
|
-
// ? ((root?.controls?.[this.name] as FormArray)?.at(this.activeFormGroupIndex) as FormGroup)
|
|
3037
|
-
// : formGroup;
|
|
3038
|
-
// } catch (error: unknown) {
|
|
3039
|
-
// this.log.error("Error getting active form group:", error as Error);
|
|
3040
|
-
// return formGroup;
|
|
3041
|
-
// }
|
|
3042
3363
|
}
|
|
3043
3364
|
/**
|
|
3044
|
-
* @
|
|
3045
|
-
* @
|
|
3365
|
+
* @description Writes a value to the form field.
|
|
3366
|
+
* @summary Part of Angular's ControlValueAccessor interface. Sets the field's value
|
|
3367
|
+
* when the form programmatically updates it. This is called by Angular forms when
|
|
3368
|
+
* the model value changes.
|
|
3046
3369
|
* @param {string} obj - The value to be set
|
|
3370
|
+
* @return {void}
|
|
3371
|
+
* @public
|
|
3047
3372
|
*/
|
|
3048
3373
|
writeValue(obj) {
|
|
3049
3374
|
this.value = obj;
|
|
3050
3375
|
}
|
|
3051
3376
|
/**
|
|
3052
|
-
* @
|
|
3053
|
-
* @
|
|
3377
|
+
* @description Registers the onChange callback function.
|
|
3378
|
+
* @summary Part of Angular's ControlValueAccessor interface. Stores the function
|
|
3379
|
+
* that Angular forms provides to be called when the field value changes.
|
|
3054
3380
|
* @param {function(): unknown} fn - The function to be called on change
|
|
3381
|
+
* @return {void}
|
|
3382
|
+
* @public
|
|
3055
3383
|
*/
|
|
3056
3384
|
registerOnChange(fn) {
|
|
3057
3385
|
this.onChange = fn;
|
|
3058
3386
|
}
|
|
3059
3387
|
/**
|
|
3060
|
-
* @
|
|
3061
|
-
* @
|
|
3388
|
+
* @description Registers the onTouched callback function.
|
|
3389
|
+
* @summary Part of Angular's ControlValueAccessor interface. Stores the function
|
|
3390
|
+
* that Angular forms provides to be called when the field is touched/blurred.
|
|
3062
3391
|
* @param {function(): unknown} fn - The function to be called on touch
|
|
3392
|
+
* @return {void}
|
|
3393
|
+
* @public
|
|
3063
3394
|
*/
|
|
3064
3395
|
registerOnTouched(fn) {
|
|
3065
3396
|
this.onTouch = fn;
|
|
3066
3397
|
}
|
|
3067
3398
|
/**
|
|
3068
|
-
* @
|
|
3069
|
-
* @
|
|
3399
|
+
* @description Sets the disabled state of the field.
|
|
3400
|
+
* @summary Part of Angular's ControlValueAccessor interface. Called by Angular forms
|
|
3401
|
+
* when the disabled state of the control changes.
|
|
3070
3402
|
* @param {boolean} isDisabled - Whether the field should be disabled
|
|
3403
|
+
* @return {void}
|
|
3404
|
+
* @public
|
|
3071
3405
|
*/
|
|
3072
3406
|
setDisabledState(isDisabled) {
|
|
3073
3407
|
this.disabled = isDisabled;
|
|
3074
3408
|
}
|
|
3075
3409
|
/**
|
|
3076
|
-
* @
|
|
3077
|
-
* @
|
|
3078
|
-
*
|
|
3410
|
+
* @description Performs setup after the view has been initialized.
|
|
3411
|
+
* @summary Retrieves and returns the parent HTML element based on the current CRUD operation.
|
|
3412
|
+
* For READ and DELETE operations, returns the immediate parent element. For CREATE and UPDATE
|
|
3413
|
+
* operations, finds the parent div element and registers it with the form service.
|
|
3414
|
+
* @return {HTMLElement} The parent element of the field
|
|
3415
|
+
* @throws {RenderingError} If unable to retrieve parent form element for CREATE/UPDATE operations
|
|
3416
|
+
* @throws {InternalError} If the operation is invalid
|
|
3417
|
+
* @public
|
|
3079
3418
|
*/
|
|
3080
3419
|
afterViewInit() {
|
|
3081
3420
|
let parent;
|
|
@@ -3097,6 +3436,16 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
|
|
|
3097
3436
|
throw new InternalError(`Invalid operation: ${this.operation}`);
|
|
3098
3437
|
}
|
|
3099
3438
|
}
|
|
3439
|
+
/**
|
|
3440
|
+
* @description Angular lifecycle hook for detecting input property changes.
|
|
3441
|
+
* @summary Overrides the parent ngOnChanges to handle changes to activeFormGroupIndex and value.
|
|
3442
|
+
* When activeFormGroupIndex changes in a multiple field scenario, updates the active form group
|
|
3443
|
+
* and form control. When value changes, updates the form control value. Delegates to parent
|
|
3444
|
+
* implementation for initial change detection.
|
|
3445
|
+
* @param {SimpleChanges} changes - Object containing the changed properties
|
|
3446
|
+
* @return {void}
|
|
3447
|
+
* @public
|
|
3448
|
+
*/
|
|
3100
3449
|
ngOnChanges(changes) {
|
|
3101
3450
|
if (!this.initialized)
|
|
3102
3451
|
super.ngOnChanges(changes);
|
|
@@ -3110,14 +3459,38 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
|
|
|
3110
3459
|
&& (changes['value'].currentValue !== undefined && changes['value'].currentValue !== this.value))
|
|
3111
3460
|
this.setValue(changes['value'].currentValue);
|
|
3112
3461
|
}
|
|
3462
|
+
/**
|
|
3463
|
+
* @description Cleanup logic when the component is destroyed.
|
|
3464
|
+
* @summary Unregisters the form group from the form service to prevent memory leaks
|
|
3465
|
+
* and clean up form references.
|
|
3466
|
+
* @return {void}
|
|
3467
|
+
* @public
|
|
3468
|
+
*/
|
|
3113
3469
|
onDestroy() {
|
|
3114
3470
|
if (this.formGroup)
|
|
3115
3471
|
NgxDecafFormService.unregister(this.formGroup);
|
|
3116
3472
|
}
|
|
3473
|
+
/**
|
|
3474
|
+
* @description Sets the value of the form control.
|
|
3475
|
+
* @summary Updates the form control's value and triggers validation. This is used
|
|
3476
|
+
* when the value needs to be programmatically updated from outside the form control.
|
|
3477
|
+
* @param {unknown} value - The value to set
|
|
3478
|
+
* @return {void}
|
|
3479
|
+
* @public
|
|
3480
|
+
*/
|
|
3117
3481
|
setValue(value) {
|
|
3118
3482
|
this.formControl.setValue(value);
|
|
3119
3483
|
this.formControl.updateValueAndValidity();
|
|
3120
3484
|
}
|
|
3485
|
+
/**
|
|
3486
|
+
* @description Retrieves validation error messages for the field.
|
|
3487
|
+
* @summary Checks the form control for validation errors and returns formatted error messages.
|
|
3488
|
+
* If errors exist, dispatches a validation error event to parent accordion components.
|
|
3489
|
+
* Error messages are translated and formatted with relevant field properties.
|
|
3490
|
+
* @param {HTMLElement} parent - The parent HTML element used to find accordion components
|
|
3491
|
+
* @return {string | void} Formatted error message string, or void if no errors
|
|
3492
|
+
* @public
|
|
3493
|
+
*/
|
|
3121
3494
|
getErrors(parent) {
|
|
3122
3495
|
const formControl = this.formControl;
|
|
3123
3496
|
if (formControl) {
|
|
@@ -3143,12 +3516,15 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
|
|
|
3143
3516
|
}
|
|
3144
3517
|
}
|
|
3145
3518
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NgxDecafFormFieldDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3146
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.7", type: NgxDecafFormFieldDirective, isStandalone: true, inputs: { activeFormGroupIndex: "activeFormGroupIndex", parentComponent: "parentComponent", optionsMapper: "optionsMapper" }, usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
|
|
3519
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.7", type: NgxDecafFormFieldDirective, isStandalone: true, inputs: { activeFormGroupIndex: "activeFormGroupIndex", operation: "operation", parentComponent: "parentComponent", optionsMapper: "optionsMapper" }, usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
|
|
3147
3520
|
}
|
|
3148
3521
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NgxDecafFormFieldDirective, decorators: [{
|
|
3149
3522
|
type: Directive
|
|
3150
3523
|
}], ctorParameters: () => [], propDecorators: { activeFormGroupIndex: [{
|
|
3151
3524
|
type: Input
|
|
3525
|
+
}], operation: [{
|
|
3526
|
+
type: Input,
|
|
3527
|
+
args: [{ required: true }]
|
|
3152
3528
|
}], parentComponent: [{
|
|
3153
3529
|
type: Input
|
|
3154
3530
|
}], optionsMapper: [{
|
|
@@ -3167,32 +3543,112 @@ class NgxEventHandler extends LoggedClass {
|
|
|
3167
3543
|
}
|
|
3168
3544
|
|
|
3169
3545
|
/**
|
|
3170
|
-
* @module
|
|
3546
|
+
* @module lib/engine/NgxPageDirective
|
|
3171
3547
|
* @description Base page component for Decaf Angular applications.
|
|
3172
3548
|
* @summary Provides a page-level base class (NgxPageDirective) that extends NgxDecafComponentDirective and
|
|
3173
3549
|
* offers page-focused utilities such as menu management, title handling and router event hooks.
|
|
3174
|
-
*
|
|
3175
3550
|
* @link {@link NgxPageDirective}
|
|
3176
3551
|
*/
|
|
3552
|
+
/**
|
|
3553
|
+
* @description Base directive for page-level components in Decaf Angular applications.
|
|
3554
|
+
* @summary Abstract directive that provides foundational functionality for page components.
|
|
3555
|
+
* Extends NgxDecafComponentDirective to add page-specific features including menu management,
|
|
3556
|
+
* page title handling, and Ionic lifecycle hooks. This directive serves as the base class for
|
|
3557
|
+
* all page-level components, providing consistent behavior for navigation, routing, and UI state.
|
|
3558
|
+
* @class NgxPageDirective
|
|
3559
|
+
* @extends {NgxDecafComponentDirective}
|
|
3560
|
+
* @memberOf module:lib/engine/NgxPageDirective
|
|
3561
|
+
*/
|
|
3177
3562
|
class NgxPageDirective extends NgxDecafComponentDirective {
|
|
3563
|
+
/**
|
|
3564
|
+
* @description Constructor for NgxPageDirective.
|
|
3565
|
+
* @summary Initializes the page directive with optional locale root and menu visibility settings.
|
|
3566
|
+
* Calls the parent NgxDecafComponentDirective constructor to set up base functionality including
|
|
3567
|
+
* logging, localization, and component identification.
|
|
3568
|
+
* @param {string} [localeRoot] - Optional locale root key for internationalization
|
|
3569
|
+
* @param {boolean} [hasMenu=true] - Whether this page should display the menu
|
|
3570
|
+
* @memberOf module:lib/engine/NgxPageDirective
|
|
3571
|
+
*/
|
|
3178
3572
|
// eslint-disable-next-line @angular-eslint/prefer-inject
|
|
3179
3573
|
constructor(localeRoot, hasMenu = true) {
|
|
3180
3574
|
super(localeRoot);
|
|
3181
3575
|
this.localeRoot = localeRoot;
|
|
3182
3576
|
this.hasMenu = hasMenu;
|
|
3577
|
+
/**
|
|
3578
|
+
* @description Page title text for the current view.
|
|
3579
|
+
* @summary Stores the title text to be displayed for this page. This can be set dynamically
|
|
3580
|
+
* based on the current route or menu configuration and is used to update the browser's
|
|
3581
|
+
* title bar or page header.
|
|
3582
|
+
* @type {string}
|
|
3583
|
+
* @default ''
|
|
3584
|
+
* @memberOf module:lib/engine/NgxPageDirective
|
|
3585
|
+
*/
|
|
3183
3586
|
this.title = '';
|
|
3587
|
+
/**
|
|
3588
|
+
* @description Menu items array for page navigation.
|
|
3589
|
+
* @summary Contains the collection of menu items available for this page. Each menu item
|
|
3590
|
+
* defines a navigation option with properties like label, URL, icon, and visibility settings.
|
|
3591
|
+
* This array is used to construct the application's navigation menu and can be filtered or
|
|
3592
|
+
* customized per page.
|
|
3593
|
+
* @protected
|
|
3594
|
+
* @type {IMenuItem[]}
|
|
3595
|
+
* @default []
|
|
3596
|
+
* @memberOf module:lib/engine/NgxPageDirective
|
|
3597
|
+
*/
|
|
3184
3598
|
this.menu = [];
|
|
3599
|
+
/**
|
|
3600
|
+
* @description Angular Title service for browser title management.
|
|
3601
|
+
* @summary Injected service that provides control over the browser's document title.
|
|
3602
|
+
* Used to dynamically set the page title based on the current route or active menu item,
|
|
3603
|
+
* improving SEO and user experience.
|
|
3604
|
+
* @protected
|
|
3605
|
+
* @type {Title}
|
|
3606
|
+
* @memberOf module:lib/engine/NgxPageDirective
|
|
3607
|
+
*/
|
|
3185
3608
|
this.titleService = inject(Title);
|
|
3186
3609
|
}
|
|
3187
|
-
|
|
3610
|
+
/**
|
|
3611
|
+
* @description Ionic lifecycle hook called when the page is about to enter view.
|
|
3612
|
+
* @summary This lifecycle hook is triggered just before the page becomes visible to the user.
|
|
3613
|
+
* It enables or disables the application menu based on the hasMenu property, allowing pages
|
|
3614
|
+
* to control whether the menu should be accessible. This is useful for pages like login screens
|
|
3615
|
+
* where the menu should be hidden.
|
|
3616
|
+
* @return {Promise<void>} A promise that resolves when menu state is updated
|
|
3617
|
+
* @memberOf module:lib/engine/NgxPageDirective
|
|
3618
|
+
*/
|
|
3619
|
+
async ngAfterViewInit() {
|
|
3620
|
+
this.router.events.subscribe(async (event) => {
|
|
3621
|
+
if (event instanceof NavigationEnd) {
|
|
3622
|
+
const url = (event?.url || "").replace('/', '');
|
|
3623
|
+
this.hasMenu = url !== "login" && url !== "";
|
|
3624
|
+
this.setPageTitle(url);
|
|
3625
|
+
}
|
|
3626
|
+
if (event instanceof NavigationStart)
|
|
3627
|
+
removeFocusTrap();
|
|
3628
|
+
});
|
|
3188
3629
|
await this.menuController.enable(this.hasMenu);
|
|
3189
3630
|
}
|
|
3631
|
+
/**
|
|
3632
|
+
* @description Sets the browser page title based on the current route.
|
|
3633
|
+
* @summary Updates the browser's document title by finding the active menu item that matches
|
|
3634
|
+
* the provided route. If a matching menu item is found, it sets the title using the format
|
|
3635
|
+
* "Decaf For Angular - {menu title or label}". This improves SEO and provides clear context
|
|
3636
|
+
* to users about the current page. If a custom menu array is provided, it uses that instead
|
|
3637
|
+
* of the component's default menu.
|
|
3638
|
+
* @protected
|
|
3639
|
+
* @param {string} route - The current route path to match against menu items
|
|
3640
|
+
* @param {IMenuItem[]} [menu] - Optional custom menu array to search (uses this.menu if not provided)
|
|
3641
|
+
* @return {void}
|
|
3642
|
+
* @memberOf module:lib/engine/NgxPageDirective
|
|
3643
|
+
*/
|
|
3190
3644
|
setPageTitle(route, menu) {
|
|
3645
|
+
if (!route)
|
|
3646
|
+
route = this.router.url.replace('/', '');
|
|
3191
3647
|
if (menu)
|
|
3192
3648
|
menu = this.menu;
|
|
3193
3649
|
const activeMenu = this.menu.find(item => item?.url?.includes(route));
|
|
3194
3650
|
if (activeMenu)
|
|
3195
|
-
this.titleService.setTitle(
|
|
3651
|
+
this.titleService.setTitle(`${activeMenu?.title || activeMenu?.label}`);
|
|
3196
3652
|
}
|
|
3197
3653
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NgxPageDirective, deps: [{ token: CPTKN }, { token: CPTKN }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3198
3654
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.7", type: NgxPageDirective, isStandalone: true, usesInheritance: true, ngImport: i0 }); }
|
|
@@ -3779,7 +4235,6 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxDecafFormFieldDirec
|
|
|
3779
4235
|
if (this.optionsMapper) {
|
|
3780
4236
|
if (this.optionsMapper instanceof Function || typeof this.optionsMapper === 'function') {
|
|
3781
4237
|
const mapper = this.optionsMapper;
|
|
3782
|
-
console.log(this.options);
|
|
3783
4238
|
this.options = this.options.map((option) => {
|
|
3784
4239
|
return mapper(option);
|
|
3785
4240
|
});
|
|
@@ -3848,48 +4303,6 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxDecafFormFieldDirec
|
|
|
3848
4303
|
return false;
|
|
3849
4304
|
return this.formControl.value.includes(value);
|
|
3850
4305
|
}
|
|
3851
|
-
/**
|
|
3852
|
-
* @description Handles fieldset group creation events from parent fieldsets.
|
|
3853
|
-
* @summary Processes events triggered when a new group needs to be added to a fieldset.
|
|
3854
|
-
* Validates the current form group, checks for uniqueness if applicable, and either
|
|
3855
|
-
* creates a new group or provides validation feedback. Updates the active form group
|
|
3856
|
-
* and resets the field for new input after successful creation.
|
|
3857
|
-
*
|
|
3858
|
-
* @param {CustomEvent} event - The fieldset create group event containing group details
|
|
3859
|
-
* @returns {void}
|
|
3860
|
-
* @memberOf CrudFieldComponent
|
|
3861
|
-
*/
|
|
3862
|
-
handleFieldsetCreateGroupEvent(event) {
|
|
3863
|
-
event.stopImmediatePropagation();
|
|
3864
|
-
const { formGroup } = event.detail;
|
|
3865
|
-
// const formGroup = this.formGroup as FormGroup;
|
|
3866
|
-
// const parentFormGroup = this.formGroup?.parent as FormArray;
|
|
3867
|
-
// const isValid = NgxDecafFormService.validateFields(formGroup as FormGroup);
|
|
3868
|
-
// const indexToCheck = operation === OperationKeys.CREATE ?
|
|
3869
|
-
// index === 0 ? index : parentFormGroup.length - 1 : index;
|
|
3870
|
-
// const isUnique = NgxDecafFormService.isUniqueOnGroup(formGroup, indexToCheck, operation || OperationKeys.CREATE);
|
|
3871
|
-
// event = new CustomEvent(EventConstants.FIELDSET_ADD_GROUP, {
|
|
3872
|
-
// detail: {isValid: isValid && isUnique, value: formGroup.value, formGroup: parentFormGroup, formService: NgxDecafFormService},
|
|
3873
|
-
// });
|
|
3874
|
-
// component.dispatchEvent(event);
|
|
3875
|
-
// if(isValid && isUnique) {
|
|
3876
|
-
// const newIndex = parentFormGroup?.length;
|
|
3877
|
-
// if(operation === OperationKeys.CREATE) {
|
|
3878
|
-
// NgxDecafFormService.addGroupToParent(parentFormGroup?.parent as FormGroup, parent, newIndex);
|
|
3879
|
-
// this.activeFormGroup = newIndex;
|
|
3880
|
-
// } else {
|
|
3881
|
-
// this.activeFormGroup = newIndex - 1;
|
|
3882
|
-
// }
|
|
3883
|
-
// this.formGroup = this.activeFormGroup;
|
|
3884
|
-
// // NgxDecafFormService.reset(this.formGroup as FormGroup);
|
|
3885
|
-
// this.formControl = (this.formGroup as FormGroup).get(this.name) as FormControl;
|
|
3886
|
-
// // NgxDecafFormService.reset(this.formControl);
|
|
3887
|
-
// // this.component.nativeElement.setFocus();
|
|
3888
|
-
// } else {
|
|
3889
|
-
// if(isUnique)
|
|
3890
|
-
// this.component.nativeElement.setFocus();
|
|
3891
|
-
// }
|
|
3892
|
-
}
|
|
3893
4306
|
/**
|
|
3894
4307
|
* @description Handles fieldset group update events from parent fieldsets.
|
|
3895
4308
|
* @summary Processes events triggered when an existing group needs to be updated.
|
|
@@ -3907,31 +4320,8 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxDecafFormFieldDirec
|
|
|
3907
4320
|
this.formControl = this.formGroup.get(this.name);
|
|
3908
4321
|
this.value = this.formControl.value;
|
|
3909
4322
|
}
|
|
3910
|
-
/**
|
|
3911
|
-
* @description Handles fieldset group removal events from parent fieldsets.
|
|
3912
|
-
* @summary Processes events triggered when a group needs to be removed from a fieldset.
|
|
3913
|
-
* Removes the specified group from the form array, updates the active form group index,
|
|
3914
|
-
* and refreshes the form references. Dispatches a confirmation event back to the component.
|
|
3915
|
-
*
|
|
3916
|
-
* @param {CustomEvent} event - The fieldset remove group event containing removal details
|
|
3917
|
-
* @returns {void}
|
|
3918
|
-
* @memberOf CrudFieldComponent
|
|
3919
|
-
*/
|
|
3920
|
-
handleFieldsetRemoveGroupEvent(event) {
|
|
3921
|
-
const { component, index } = event.detail;
|
|
3922
|
-
const formArray = this.formGroup?.parent;
|
|
3923
|
-
formArray.removeAt(index);
|
|
3924
|
-
this.activeFormGroupIndex = formArray.length === 1 ? 0 : formArray.length - 1;
|
|
3925
|
-
this.formGroup = this.activeFormGroup;
|
|
3926
|
-
this.formControl = this.formGroup.get(this.name);
|
|
3927
|
-
this.parentComponent = formArray;
|
|
3928
|
-
event = new CustomEvent(EventConstants.FIELDSET_REMOVE_GROUP, {
|
|
3929
|
-
detail: { value: true },
|
|
3930
|
-
});
|
|
3931
|
-
component.dispatchEvent(event);
|
|
3932
|
-
}
|
|
3933
4323
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CrudFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
3934
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: CrudFieldComponent, isStandalone: true, selector: "ngx-decaf-crud-field", inputs: { operation: "operation", name: "name", className: "className", 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", 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" }, host: { listeners: { "window:fieldsetAddGroupEvent": "handleFieldsetCreateGroupEvent($event)", "window:fieldsetUpdateGroupEvent": "handleFieldsetUpdateGroupEvent($event)", "window:fieldsetRemoveGroupEvent": "handleFieldsetRemoveGroupEvent($event)" }, properties: { "attr.id": "uid", "attr.class": "className" } }, 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 @if(['checkbox', 'radio'].includes(type)) {\n <ion-icon class=\"dcf-margin-small-top\" color=\"primary\" size=\"large\" name=\"checkmark-circle-outline\"></ion-icon>\n } @else {\n <br />\n }\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n @if(formControl) {\n <ng-container [formGroup]=\"multiple ? activeFormGroup : formControl.parent\">\n <div\n [id]=\"uid\" #container\n [class]=\"'dcf-input-item ' + (operation || 'create')\"\n (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\"\n [class.dcf-field-required]=\"required\"\n >\n @if(type === 'textarea') {\n <ion-textarea\n [id]=\"name\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\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 @if(!options?.length) {\n <ion-item class=\"dcf-width-1-1\" [hidden]=\"hidden\">\n <ion-checkbox\n [id]=\"name\"\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"left\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span>{{label | translate}}</span>\n </ion-checkbox>\n\n </ion-item>\n } @else {\n <div class=\"dcf-checkbox-group\">\n <label class=\"dcf-label\" [for]=\"path\">{{ label | translate }}</label>\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-item class=\"dcf-width-1-1\" [button]=\"true\">\n <ion-checkbox\n [id]=\"option.text\"\n [mode]=\"mode\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"option.value\"\n [readonly]=\"readonly\"\n [checked]=\"isOptionChecked(option.value)\"\n (ionChange)=\"toggleOptionSelection(option.value, $event)\"\n #component>\n <span>{{ $index + 1 }}. {{ option?.text | translate }}</span>\n </ion-checkbox>\n </ion-item>\n }\n <span class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></span>\n </div>\n }\n\n }\n @else if(type === 'radio' && options?.length) {\n <ion-radio-group class=\"dcf-width-1-1\" [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track $index) {\n <ion-item>\n <ion-radio\n [id]=\"name\"\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 >{{ option?.text | translate }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @if(options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n aa\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n\n </ion-select>\n }\n @else {\n <ion-input\n [class.required]=\"required\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\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 } @else {\n <div>\n <p class=\"dcf-error\">\n {{ 'errors.form.control' | translate:{'0': name} }}\n </p>\n </div>\n }\n\n}\n\n", styles: ["@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)!important}.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}.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,.dcf-input-item.delete{padding:0;margin:0!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item.read ion-item,.dcf-input-item.delete ion-item{--min-height: 30px;margin-bottom:0}.dcf-input-item.read ion-item ion-label,.dcf-input-item.delete ion-item ion-label{margin-top:0!important;margin-bottom:.25rem!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}.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}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-checkbox-group .dcf-label{font-weight:600}.dcf-checkbox-group .dcf-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}.dcf-checkbox-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.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: "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"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
4324
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: CrudFieldComponent, isStandalone: true, selector: "ngx-decaf-crud-field", inputs: { operation: "operation", name: "name", className: "className", 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", 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" }, host: { listeners: { "window:fieldsetUpdateGroupEvent": "handleFieldsetUpdateGroupEvent($event)" }, properties: { "attr.id": "uid", "attr.class": "className" } }, 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 @if(['checkbox', 'radio'].includes(type)) {\n <ion-icon class=\"dcf-margin-small-top\" color=\"primary\" size=\"large\" name=\"checkmark-circle-outline\"></ion-icon>\n } @else {\n <br />\n }\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n @if(formControl) {\n <ng-container [formGroup]=\"multiple ? activeFormGroup : formControl.parent\">\n <div\n [id]=\"uid\" #container\n [class]=\"'dcf-input-item ' + (operation || 'create')\"\n (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\"\n [class.dcf-field-required]=\"required\"\n >\n @if(type === 'textarea') {\n <ion-textarea\n [id]=\"name\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\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 @if(!options?.length) {\n <ion-item class=\"dcf-width-1-1\" [hidden]=\"hidden\">\n <ion-checkbox\n [id]=\"name\"\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"left\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span>{{label | translate}}</span>\n </ion-checkbox>\n\n </ion-item>\n } @else {\n <div class=\"dcf-checkbox-group\">\n <label class=\"dcf-label\" [for]=\"path\">{{ label | translate }}</label>\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-item class=\"dcf-width-1-1\" [button]=\"true\">\n <ion-checkbox\n [id]=\"option.text\"\n [mode]=\"mode\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"option.value\"\n [readonly]=\"readonly\"\n [checked]=\"isOptionChecked(option.value)\"\n (ionChange)=\"toggleOptionSelection(option.value, $event)\"\n #component>\n <span>{{ $index + 1 }}. {{ option?.text | translate }}</span>\n </ion-checkbox>\n </ion-item>\n }\n <span class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></span>\n </div>\n }\n\n }\n @else if(type === 'radio' && options?.length) {\n <ion-radio-group class=\"dcf-width-1-1\" [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track $index) {\n <ion-item>\n <ion-radio\n [id]=\"name\"\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 >{{ option?.text | translate }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @if(options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n aa\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n\n </ion-select>\n }\n @else {\n <ion-input\n [class.required]=\"required\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\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 } @else {\n <div>\n <p class=\"dcf-error\">\n {{ 'errors.form.control' | translate:{'0': name} }}\n </p>\n </div>\n }\n\n}\n\n", styles: ["@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)!important}.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}.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,.dcf-input-item.delete{padding:0;margin:0!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item.read ion-item,.dcf-input-item.delete ion-item{--min-height: 30px;margin-bottom:0}.dcf-input-item.read ion-item ion-label,.dcf-input-item.delete ion-item ion-label{margin-top:0!important;margin-bottom:.25rem!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}.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}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-checkbox-group{width:100%}.dcf-checkbox-group .dcf-label{font-weight:600}.dcf-checkbox-group .dcf-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}.dcf-checkbox-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.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: "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"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
3935
4325
|
};
|
|
3936
4326
|
CrudFieldComponent = __decorate([
|
|
3937
4327
|
Dynamic()
|
|
@@ -3951,7 +4341,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
3951
4341
|
IonLabel,
|
|
3952
4342
|
IonText,
|
|
3953
4343
|
IonTextarea
|
|
3954
|
-
], selector: 'ngx-decaf-crud-field', schemas: [CUSTOM_ELEMENTS_SCHEMA], host: { '[attr.id]': 'uid', '[attr.class]': 'className' }, 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 @if(['checkbox', 'radio'].includes(type)) {\n <ion-icon class=\"dcf-margin-small-top\" color=\"primary\" size=\"large\" name=\"checkmark-circle-outline\"></ion-icon>\n } @else {\n <br />\n }\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n @if(formControl) {\n <ng-container [formGroup]=\"multiple ? activeFormGroup : formControl.parent\">\n <div\n [id]=\"uid\" #container\n [class]=\"'dcf-input-item ' + (operation || 'create')\"\n (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\"\n [class.dcf-field-required]=\"required\"\n >\n @if(type === 'textarea') {\n <ion-textarea\n [id]=\"name\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\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 @if(!options?.length) {\n <ion-item class=\"dcf-width-1-1\" [hidden]=\"hidden\">\n <ion-checkbox\n [id]=\"name\"\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"left\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span>{{label | translate}}</span>\n </ion-checkbox>\n\n </ion-item>\n } @else {\n <div class=\"dcf-checkbox-group\">\n <label class=\"dcf-label\" [for]=\"path\">{{ label | translate }}</label>\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-item class=\"dcf-width-1-1\" [button]=\"true\">\n <ion-checkbox\n [id]=\"option.text\"\n [mode]=\"mode\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"option.value\"\n [readonly]=\"readonly\"\n [checked]=\"isOptionChecked(option.value)\"\n (ionChange)=\"toggleOptionSelection(option.value, $event)\"\n #component>\n <span>{{ $index + 1 }}. {{ option?.text | translate }}</span>\n </ion-checkbox>\n </ion-item>\n }\n <span class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></span>\n </div>\n }\n\n }\n @else if(type === 'radio' && options?.length) {\n <ion-radio-group class=\"dcf-width-1-1\" [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track $index) {\n <ion-item>\n <ion-radio\n [id]=\"name\"\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 >{{ option?.text | translate }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @if(options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n aa\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n\n </ion-select>\n }\n @else {\n <ion-input\n [class.required]=\"required\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\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 } @else {\n <div>\n <p class=\"dcf-error\">\n {{ 'errors.form.control' | translate:{'0': name} }}\n </p>\n </div>\n }\n\n}\n\n", styles: ["@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)!important}.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}.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,.dcf-input-item.delete{padding:0;margin:0!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item.read ion-item,.dcf-input-item.delete ion-item{--min-height: 30px;margin-bottom:0}.dcf-input-item.read ion-item ion-label,.dcf-input-item.delete ion-item ion-label{margin-top:0!important;margin-bottom:.25rem!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}.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}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-checkbox-group .dcf-label{font-weight:600}.dcf-checkbox-group .dcf-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}.dcf-checkbox-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"] }]
|
|
4344
|
+
], selector: 'ngx-decaf-crud-field', schemas: [CUSTOM_ELEMENTS_SCHEMA], host: { '[attr.id]': 'uid', '[attr.class]': 'className' }, 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 @if(['checkbox', 'radio'].includes(type)) {\n <ion-icon class=\"dcf-margin-small-top\" color=\"primary\" size=\"large\" name=\"checkmark-circle-outline\"></ion-icon>\n } @else {\n <br />\n }\n }\n </ion-label>\n </ion-item>\n </div>\n </ng-container>\n} @else {\n @if(formControl) {\n <ng-container [formGroup]=\"multiple ? activeFormGroup : formControl.parent\">\n <div\n [id]=\"uid\" #container\n [class]=\"'dcf-input-item ' + (operation || 'create')\"\n (createGroupEvent)=\"multiple ? handleFieldsetCreateGroupEvent($event) : ''\"\n [class.dcf-field-required]=\"required\"\n >\n @if(type === 'textarea') {\n <ion-textarea\n [id]=\"name\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [autoGrow]=\"true\"\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 @if(!options?.length) {\n <ion-item class=\"dcf-width-1-1\" [hidden]=\"hidden\">\n <ion-checkbox\n [id]=\"name\"\n [mode]=\"mode\"\n [errorText]=\"getErrors(container)\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"left\"\n [value]=\"value\"\n [checked]=\"checked\"\n [readonly]=\"readonly\"\n (ionChange)=\"checked = !checked\"\n [formControlName]=\"name\"\n #component>\n <span>{{label | translate}}</span>\n </ion-checkbox>\n\n </ion-item>\n } @else {\n <div class=\"dcf-checkbox-group\">\n <label class=\"dcf-label\" [for]=\"path\">{{ label | translate }}</label>\n @for(option of options; track trackItemFn($index, option.text)) {\n <ion-item class=\"dcf-width-1-1\" [button]=\"true\">\n <ion-checkbox\n [id]=\"option.text\"\n [mode]=\"mode\"\n [labelPlacement]=\"labelPlacement\"\n [justify]=\"justify\"\n [value]=\"option.value\"\n [readonly]=\"readonly\"\n [checked]=\"isOptionChecked(option.value)\"\n (ionChange)=\"toggleOptionSelection(option.value, $event)\"\n #component>\n <span>{{ $index + 1 }}. {{ option?.text | translate }}</span>\n </ion-checkbox>\n </ion-item>\n }\n <span class=\"dcf-error\" [innerHTML]=\"getErrors(container)\"></span>\n </div>\n }\n\n }\n @else if(type === 'radio' && options?.length) {\n <ion-radio-group class=\"dcf-width-1-1\" [formControlName]=\"name\" [value]=\"value\" #component>\n <label class=\"dcf-radio-group-label\" [for]=\"path\">{{label | translate}}</label>\n @for(option of options; track $index) {\n <ion-item>\n <ion-radio\n [id]=\"name\"\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 >{{ option?.text | translate }}</ion-radio>\n </ion-item>\n }\n </ion-radio-group>\n }\n @else if(type === 'select') {\n <ion-select\n [id]=\"name\"\n toggleIcon=\"chevron-down-outline\"\n expandedIcon=\"chevron-up-outline\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [labelPlacement]=\"labelPlacement\"\n [label]=\"label | translate\"\n [value]=\"value\"\n [fill]=\"fill\"\n [placeholder]=\"placeholder | translate\"\n [formControlName]=\"name\"\n [errorText]=\"getErrors(container)\"\n [interface]=\"interface\" #component>\n @if(options?.length) {\n @for(option of options; track trackItemFn($index, option.text)) {\n aa\n <ion-select-option [value]=\"option.value\">\n {{ option.text | translate }}\n </ion-select-option>\n }\n }\n\n </ion-select>\n }\n @else {\n <ion-input\n [class.required]=\"required\"\n [id]=\"name\"\n [type]=\"type\"\n [mode]=\"mode\"\n [hidden]=\"hidden\"\n [inputmode]=\"inputmode\"\n [labelPlacement]=\"labelPlacement\"\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 } @else {\n <div>\n <p class=\"dcf-error\">\n {{ 'errors.form.control' | translate:{'0': name} }}\n </p>\n </div>\n }\n\n}\n\n", styles: ["@media (prefers-color-scheme: light){.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{color:var(--dcf-color-gray-7)!important}.dcf-input-item ion-item{--background-hover: var(--dcf-color-primary);--background-focused: var(--dcf-color-primary);--border-color: var(--dcf-color-gray-2)}ion-checkbox::part(container){border:2px solid var(--dcf-color-primary)}}@media (prefers-color-scheme: dark){.dcf-input-item ion-item{--border-color: var(--dcf-color-gray-6)}}.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,.dcf-input-item.delete{padding:0;margin:0!important}.dcf-input-item.read ion-label,.dcf-input-item.delete ion-label{font-weight:600}.dcf-input-item.read ion-text,.dcf-input-item.delete ion-text{display:block;margin-top:.5rem!important}.dcf-input-item.read ion-item,.dcf-input-item.delete ion-item{--min-height: 30px;margin-bottom:0}.dcf-input-item.read ion-item ion-label,.dcf-input-item.delete ion-item ion-label{margin-top:0!important;margin-bottom:.25rem!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}.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}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-checkbox-group{width:100%}.dcf-checkbox-group .dcf-label{font-weight:600}.dcf-checkbox-group .dcf-label~ion-item{margin-top:.5rem;--inner-padding-start: .75rem}.dcf-checkbox-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"] }]
|
|
3955
4345
|
}], propDecorators: { operation: [{
|
|
3956
4346
|
type: Input,
|
|
3957
4347
|
args: [{ required: true }]
|
|
@@ -4050,15 +4440,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
4050
4440
|
type: Input
|
|
4051
4441
|
}], translatable: [{
|
|
4052
4442
|
type: Input
|
|
4053
|
-
}], handleFieldsetCreateGroupEvent: [{
|
|
4054
|
-
type: HostListener,
|
|
4055
|
-
args: ['window:fieldsetAddGroupEvent', ['$event']]
|
|
4056
4443
|
}], handleFieldsetUpdateGroupEvent: [{
|
|
4057
4444
|
type: HostListener,
|
|
4058
4445
|
args: ['window:fieldsetUpdateGroupEvent', ['$event']]
|
|
4059
|
-
}], handleFieldsetRemoveGroupEvent: [{
|
|
4060
|
-
type: HostListener,
|
|
4061
|
-
args: ['window:fieldsetRemoveGroupEvent', ['$event']]
|
|
4062
4446
|
}] } });
|
|
4063
4447
|
|
|
4064
4448
|
/**
|
|
@@ -4079,7 +4463,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
4079
4463
|
* @class NgxParentComponentDirective
|
|
4080
4464
|
* @extends {NgxParentComponentDirective}
|
|
4081
4465
|
* @implements {OnInit}
|
|
4082
|
-
* @memberOf NgxParentComponentDirective
|
|
4083
4466
|
*/
|
|
4084
4467
|
class NgxParentComponentDirective extends NgxDecafComponentDirective {
|
|
4085
4468
|
constructor() {
|
|
@@ -4092,7 +4475,6 @@ class NgxParentComponentDirective extends NgxDecafComponentDirective {
|
|
|
4092
4475
|
* page assignment, and display properties.
|
|
4093
4476
|
*
|
|
4094
4477
|
* @type {UIModelMetadata[]}
|
|
4095
|
-
* @memberOf NgxParentComponentDirective
|
|
4096
4478
|
*/
|
|
4097
4479
|
this.children = [];
|
|
4098
4480
|
/**
|
|
@@ -4104,7 +4486,6 @@ class NgxParentComponentDirective extends NgxDecafComponentDirective {
|
|
|
4104
4486
|
*
|
|
4105
4487
|
* @type {(number | string[])}
|
|
4106
4488
|
* @default 1
|
|
4107
|
-
* @memberOf NgxParentComponentDirective
|
|
4108
4489
|
*/
|
|
4109
4490
|
this.cols = 1;
|
|
4110
4491
|
/**
|
|
@@ -4115,7 +4496,6 @@ class NgxParentComponentDirective extends NgxDecafComponentDirective {
|
|
|
4115
4496
|
*
|
|
4116
4497
|
* @type {(number | string[])}
|
|
4117
4498
|
* @default 1
|
|
4118
|
-
* @memberOf NgxParentComponentDirective
|
|
4119
4499
|
*/
|
|
4120
4500
|
this.rows = 1;
|
|
4121
4501
|
}
|
|
@@ -4144,17 +4524,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4144
4524
|
constructor() {
|
|
4145
4525
|
super(...arguments);
|
|
4146
4526
|
this.crudFieldComponent = ComponentsTagNames.CRUD_FIELD;
|
|
4147
|
-
/**
|
|
4148
|
-
* @description Angular Location service.
|
|
4149
|
-
* @summary Injected service that provides access to the browser's URL and history.
|
|
4150
|
-
* This service is used for interacting with the browser's history API, allowing
|
|
4151
|
-
* for back navigation and URL manipulation outside of Angular's router.
|
|
4152
|
-
*
|
|
4153
|
-
* @private
|
|
4154
|
-
* @type {Location}
|
|
4155
|
-
* @memberOf CrudFormComponent
|
|
4156
|
-
*/
|
|
4157
|
-
this.location = inject(Location);
|
|
4158
4527
|
/**
|
|
4159
4528
|
* @description Field update trigger mode for form validation.
|
|
4160
4529
|
* @summary Determines when form field validation should be triggered. Options include
|
|
@@ -4163,7 +4532,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4163
4532
|
*
|
|
4164
4533
|
* @type {FieldUpdateMode}
|
|
4165
4534
|
* @default 'change'
|
|
4166
|
-
* @memberOf CrudFormComponent
|
|
4167
4535
|
*/
|
|
4168
4536
|
this.updateOn = 'change';
|
|
4169
4537
|
/**
|
|
@@ -4174,7 +4542,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4174
4542
|
*
|
|
4175
4543
|
* @type {HTMLFormTarget}
|
|
4176
4544
|
* @default '_self'
|
|
4177
|
-
* @memberOf CrudFormComponent
|
|
4178
4545
|
*/
|
|
4179
4546
|
this.target = '_self';
|
|
4180
4547
|
/**
|
|
@@ -4185,9 +4552,18 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4185
4552
|
*
|
|
4186
4553
|
* @type {'get' | 'post' | 'event'}
|
|
4187
4554
|
* @default 'event'
|
|
4188
|
-
* @memberOf CrudFormComponent
|
|
4189
4555
|
*/
|
|
4190
4556
|
this.method = 'event';
|
|
4557
|
+
/**
|
|
4558
|
+
* @description The current CRUD operation being performed.
|
|
4559
|
+
* @summary Specifies the type of operation this form is handling (CREATE, READ, UPDATE, DELETE).
|
|
4560
|
+
* This is a required input that determines form behavior, validation rules, and available actions.
|
|
4561
|
+
* The operation affects form state, button visibility, and submission logic.
|
|
4562
|
+
*
|
|
4563
|
+
* @type {CrudOperations}
|
|
4564
|
+
* @required
|
|
4565
|
+
*/
|
|
4566
|
+
this.operation = OperationKeys.CREATE;
|
|
4191
4567
|
/**
|
|
4192
4568
|
* @description Angular reactive FormGroup for form state management.
|
|
4193
4569
|
* @summary The FormGroup instance that manages all form controls, validation,
|
|
@@ -4195,7 +4571,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4195
4571
|
* controlling form behavior. May be undefined for read-only operations.
|
|
4196
4572
|
*
|
|
4197
4573
|
* @type {FormGroup | undefined}
|
|
4198
|
-
* @memberOf CrudFormComponent
|
|
4199
4574
|
*/
|
|
4200
4575
|
this.formGroup = undefined;
|
|
4201
4576
|
/**
|
|
@@ -4205,7 +4580,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4205
4580
|
* components. This enables decoupled handling of form submission logic.
|
|
4206
4581
|
*
|
|
4207
4582
|
* @type {EventEmitter<ICrudFormEvent>}
|
|
4208
|
-
* @memberOf CrudFormComponent
|
|
4209
4583
|
*/
|
|
4210
4584
|
this.submitEvent = new EventEmitter();
|
|
4211
4585
|
/**
|
|
@@ -4217,7 +4591,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4217
4591
|
*
|
|
4218
4592
|
* @type {string}
|
|
4219
4593
|
* @default Randomly generated 12-character string
|
|
4220
|
-
* @memberOf CrudFormComponent
|
|
4221
4594
|
*/
|
|
4222
4595
|
this.allowClear = true;
|
|
4223
4596
|
// /**
|
|
@@ -4253,18 +4626,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4253
4626
|
// * @memberOf CrudFormComponent
|
|
4254
4627
|
// */
|
|
4255
4628
|
// protected translateService: TranslateService = inject(TranslateService);
|
|
4256
|
-
/**
|
|
4257
|
-
* @description Reference to CRUD operation constants for template usage.
|
|
4258
|
-
* @summary Exposes the OperationKeys enum to the component template, enabling
|
|
4259
|
-
* conditional rendering and behavior based on operation types. This protected
|
|
4260
|
-
* readonly property ensures that template logic can access operation constants
|
|
4261
|
-
* while maintaining encapsulation and preventing accidental modification.
|
|
4262
|
-
*
|
|
4263
|
-
* @protected
|
|
4264
|
-
* @readonly
|
|
4265
|
-
* @memberOf CrudFormComponent
|
|
4266
|
-
*/
|
|
4267
|
-
this.OperationKeys = OperationKeys;
|
|
4268
4629
|
this.activeFormGroupIndex = 0;
|
|
4269
4630
|
}
|
|
4270
4631
|
get activeFormGroup() {
|
|
@@ -4278,13 +4639,13 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4278
4639
|
* form input. Configuration options are merged with default settings.
|
|
4279
4640
|
*
|
|
4280
4641
|
* @returns {Promise<void>}
|
|
4281
|
-
* @memberOf CrudFormComponent
|
|
4282
4642
|
*/
|
|
4283
4643
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
4284
4644
|
async ngOnInit(model) {
|
|
4285
4645
|
// dont call super.ngOnInit to model conflicts
|
|
4286
4646
|
if (this.operation === OperationKeys.READ || this.operation === OperationKeys.DELETE)
|
|
4287
4647
|
this.formGroup = undefined;
|
|
4648
|
+
this.initialized = true;
|
|
4288
4649
|
}
|
|
4289
4650
|
/**
|
|
4290
4651
|
* @description Component cleanup lifecycle method.
|
|
@@ -4293,7 +4654,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4293
4654
|
* and ensure proper resource cleanup.
|
|
4294
4655
|
*
|
|
4295
4656
|
* @returns {void}
|
|
4296
|
-
* @memberOf CrudFormComponent
|
|
4297
4657
|
*/
|
|
4298
4658
|
ngOnDestroy() {
|
|
4299
4659
|
if (this.formGroup)
|
|
@@ -4331,7 +4691,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4331
4691
|
* since these operations don't have modifiable form data to reset.
|
|
4332
4692
|
*
|
|
4333
4693
|
* @returns {void}
|
|
4334
|
-
* @memberOf CrudFormComponent
|
|
4335
4694
|
*/
|
|
4336
4695
|
handleReset() {
|
|
4337
4696
|
if (![OperationKeys.DELETE, OperationKeys.READ].includes(this.operation) && this.allowClear)
|
|
@@ -4555,8 +4914,7 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
|
|
|
4555
4914
|
* @memberOf LayoutComponent
|
|
4556
4915
|
*/
|
|
4557
4916
|
constructor() {
|
|
4558
|
-
super();
|
|
4559
|
-
this.initializeProps = true;
|
|
4917
|
+
super('LayoutComponent');
|
|
4560
4918
|
/**
|
|
4561
4919
|
* @description Media breakpoint for responsive behavior.
|
|
4562
4920
|
* @summary Determines the responsive breakpoint at which the layout should adapt.
|
|
@@ -4569,7 +4927,6 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
|
|
|
4569
4927
|
* @memberOf LayoutComponent
|
|
4570
4928
|
*/
|
|
4571
4929
|
this.gap = 'collapse';
|
|
4572
|
-
this.match = true;
|
|
4573
4930
|
/**
|
|
4574
4931
|
* @description Media breakpoint for responsive behavior.
|
|
4575
4932
|
* @summary Determines the responsive breakpoint at which the layout should adapt.
|
|
@@ -4582,7 +4939,30 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
|
|
|
4582
4939
|
* @memberOf LayoutComponent
|
|
4583
4940
|
*/
|
|
4584
4941
|
this.breakpoint = UIMediaBreakPoints.MEDIUM;
|
|
4585
|
-
|
|
4942
|
+
/**
|
|
4943
|
+
* @description Media breakpoint for responsive behavior.
|
|
4944
|
+
* @summary Determines the responsive breakpoint at which the layout should adapt.
|
|
4945
|
+
* This affects how the grid behaves on different screen sizes, allowing for
|
|
4946
|
+
* mobile-first or desktop-first responsive design patterns. The breakpoint
|
|
4947
|
+
* is automatically processed to ensure compatibility with the UI framework.
|
|
4948
|
+
*
|
|
4949
|
+
* @type {UIMediaBreakPointsType}
|
|
4950
|
+
* @default 'medium'
|
|
4951
|
+
* @memberOf LayoutComponent
|
|
4952
|
+
*/
|
|
4953
|
+
this.grid = true;
|
|
4954
|
+
/**
|
|
4955
|
+
* @description Media breakpoint for responsive behavior.
|
|
4956
|
+
* @summary Determines the responsive breakpoint at which the layout should adapt.
|
|
4957
|
+
* This affects how the grid behaves on different screen sizes, allowing for
|
|
4958
|
+
* mobile-first or desktop-first responsive design patterns. The breakpoint
|
|
4959
|
+
* is automatically processed to ensure compatibility with the UI framework.
|
|
4960
|
+
*
|
|
4961
|
+
* @type {UIMediaBreakPointsType}
|
|
4962
|
+
* @default 'medium'
|
|
4963
|
+
* @memberOf LayoutComponent
|
|
4964
|
+
*/
|
|
4965
|
+
this.match = true;
|
|
4586
4966
|
}
|
|
4587
4967
|
/**
|
|
4588
4968
|
* @description Getter that converts columns input to an array format.
|
|
@@ -4617,10 +4997,13 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
|
|
|
4617
4997
|
if (typeof rows === Primitives.NUMBER)
|
|
4618
4998
|
rows = Array.from({ length: Number(rows) }, () => ({ title: '' }));
|
|
4619
4999
|
return rows.map((row, index) => {
|
|
5000
|
+
const rowsLength = this.rows;
|
|
4620
5001
|
return {
|
|
4621
5002
|
title: typeof row === Primitives.STRING ? row : row?.['title'] || "",
|
|
4622
5003
|
cols: this.children.filter((child) => {
|
|
4623
|
-
|
|
5004
|
+
let row = child.props?.['row'] ?? 1;
|
|
5005
|
+
if (row > rowsLength)
|
|
5006
|
+
row = rowsLength;
|
|
4624
5007
|
child['col'] = child.props?.['col'] ?? this.cols?.length ?? 1;
|
|
4625
5008
|
if (row === index + 1)
|
|
4626
5009
|
return child;
|
|
@@ -4642,10 +5025,14 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
|
|
|
4642
5025
|
this.breakpoint = `@${this.breakpoint}`.toLowerCase();
|
|
4643
5026
|
this.cols = this._cols;
|
|
4644
5027
|
this.rows = this._rows;
|
|
5028
|
+
// if(this._rows.length === 1)
|
|
5029
|
+
// this.match = false;
|
|
5030
|
+
// if(this._cols.length === 1)
|
|
5031
|
+
// this.grid = false;
|
|
4645
5032
|
this.initialized = true;
|
|
4646
5033
|
}
|
|
4647
5034
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4648
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: LayoutComponent, isStandalone: true, selector: "ngx-decaf-layout", inputs: {
|
|
5035
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: LayoutComponent, isStandalone: true, selector: "ngx-decaf-layout", inputs: { gap: "gap", breakpoint: "breakpoint", grid: "grid", match: "match" }, usesInheritance: true, ngImport: i0, template: "\n@if(initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n <div [id]=\"uid\"\n [class]=\" !grid ? '' : 'dcf-grid ' + 'dcf-grid-' + gap\"\n [class.dcf-grid-match]=\"match\"\n\n >\n @if(row?.title?.length) {\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 [parentComponent]=\"parentComponent || child.parentComponent || child?.formGroup\"\n [children]=\"child?.children || []\"\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: "component", type: ModelRendererComponent, selector: "ngx-decaf-model-renderer", inputs: ["globals", "projectable", "rendererId"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "projectable", "model", "parentComponent", "parent"], outputs: ["listenEvent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
4649
5036
|
};
|
|
4650
5037
|
LayoutComponent = __decorate([
|
|
4651
5038
|
Dynamic(),
|
|
@@ -4653,21 +5040,20 @@ LayoutComponent = __decorate([
|
|
|
4653
5040
|
], LayoutComponent);
|
|
4654
5041
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: LayoutComponent, decorators: [{
|
|
4655
5042
|
type: Component,
|
|
4656
|
-
args: [{ selector: 'ngx-decaf-layout', imports: [TranslatePipe, ModelRendererComponent, ComponentRendererComponent], standalone: true, template: "\n@if(initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n <div [id]=\"uid\"\n [class]=\"'dcf-grid ' + 'dcf-grid-' + gap\"\n [class.dcf-grid-match]=\"match\"\n\n >\n @if(row?.title?.length) {\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 [parentComponent]=\"parentComponent || child.parentComponent || child?.formGroup\"\n [children]=\"child?.children || []\"\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"] }]
|
|
4657
|
-
}], ctorParameters: () => [], propDecorators: {
|
|
5043
|
+
args: [{ selector: 'ngx-decaf-layout', imports: [TranslatePipe, ModelRendererComponent, ComponentRendererComponent], standalone: true, template: "\n@if(initialized) {\n @for (row of rows; track trackItemFn($index, row); let rowIndex = $index) {\n <div [id]=\"uid\"\n [class]=\" !grid ? '' : 'dcf-grid ' + 'dcf-grid-' + gap\"\n [class.dcf-grid-match]=\"match\"\n\n >\n @if(row?.title?.length) {\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 [parentComponent]=\"parentComponent || child.parentComponent || child?.formGroup\"\n [children]=\"child?.children || []\"\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"] }]
|
|
5044
|
+
}], ctorParameters: () => [], propDecorators: { gap: [{
|
|
4658
5045
|
type: Input
|
|
4659
|
-
}],
|
|
5046
|
+
}], breakpoint: [{
|
|
4660
5047
|
type: Input
|
|
4661
|
-
}],
|
|
5048
|
+
}], grid: [{
|
|
4662
5049
|
type: Input
|
|
4663
|
-
}],
|
|
5050
|
+
}], match: [{
|
|
4664
5051
|
type: Input
|
|
4665
5052
|
}] } });
|
|
4666
5053
|
|
|
4667
5054
|
let CrudFormComponent = class CrudFormComponent extends NgxFormDirective {
|
|
4668
5055
|
constructor() {
|
|
4669
|
-
super();
|
|
4670
|
-
this.componentName = 'CrudFormComponent';
|
|
5056
|
+
super('CrudFormComponent');
|
|
4671
5057
|
}
|
|
4672
5058
|
/**
|
|
4673
5059
|
* @description Component initialization lifecycle method.
|
|
@@ -4680,7 +5066,6 @@ let CrudFormComponent = class CrudFormComponent extends NgxFormDirective {
|
|
|
4680
5066
|
* @memberOf CrudFormComponent
|
|
4681
5067
|
*/
|
|
4682
5068
|
async ngOnInit() {
|
|
4683
|
-
// console.log(this.formGroup);
|
|
4684
5069
|
this.options = Object.assign({}, DefaultFormReactiveOptions, this.options || {});
|
|
4685
5070
|
await super.ngOnInit();
|
|
4686
5071
|
}
|
|
@@ -4716,7 +5101,7 @@ let CrudFormComponent = class CrudFormComponent extends NgxFormDirective {
|
|
|
4716
5101
|
});
|
|
4717
5102
|
}
|
|
4718
5103
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CrudFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4719
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-
|
|
5104
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: CrudFormComponent, isStandalone: true, selector: "ngx-decaf-crud-form", host: { properties: { "attr.id": "uid" } }, usesInheritance: true, ngImport: i0, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (submit)=\"submit($event)\"\n novalidate\n [target]=\"target\">\n @if(!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [children]=\"children || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [rows]=\"rows\"\n [cols]=\"cols\" />\n\n <!-- @for (child of children; track $index) {\n <ngx-decaf-component-renderer\n [class]=\"(child?.props?.className ? 'dcf-form-item ' + child.props.className : 'dcf-form-item')\"\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [formRoot]=\"formGroup\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n } -->\n }\n @if(initialized) {\n <div class=\"dcf-buttons-grid 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 }\n\n </form>\n} @else {\n <section [class]=\"'dcf-grid dcf-grid-small dcf-child-width-1-1 dcf-form-grid ' + operation\" #component [id]=\"uid\">\n @if(!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n @for (child of children; track $index) {\n <div [class]=\"(child?.props?.className ? 'dcf-form-item ' + child.props.className : 'dcf-form-item')\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n }\n }\n </section>\n <section [class]=\"'dcf-buttons-grid 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 </section>\n}\n\n", styles: [".dcf-buttons-grid{margin-top:.5rem;margin-bottom:0}.dcf-buttons-grid.read{margin-bottom:1rem}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid{padding:1rem}.dcf-form-grid .dcf-form-item{margin-bottom:1.8rem;margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:1rem}::ng-deep ngx-decaf-stepped-form .dcf-input-item{margin-bottom:1.8rem;margin-top:0!important}::ng-deep ngx-decaf-fieldset .dcf-input-item{margin-bottom:1.8rem;margin-top:0!important}\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: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["gap", "breakpoint", "grid", "match"] }, { kind: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "projectable", "model", "parentComponent", "parent"], outputs: ["listenEvent"] }, { 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"] }] }); }
|
|
4720
5105
|
};
|
|
4721
5106
|
CrudFormComponent = __decorate([
|
|
4722
5107
|
Dynamic(),
|
|
@@ -4724,7 +5109,7 @@ CrudFormComponent = __decorate([
|
|
|
4724
5109
|
], CrudFormComponent);
|
|
4725
5110
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CrudFormComponent, decorators: [{
|
|
4726
5111
|
type: Component,
|
|
4727
|
-
args: [{ standalone: true, selector: 'ngx-decaf-crud-form', imports: [ReactiveFormsModule, LayoutComponent, ComponentRendererComponent, IonButton, IonIcon], host: { '[attr.id]': 'uid' }, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-
|
|
5112
|
+
args: [{ standalone: true, selector: 'ngx-decaf-crud-form', imports: [ReactiveFormsModule, LayoutComponent, ComponentRendererComponent, IonButton, IonIcon], host: { '[attr.id]': 'uid' }, template: "@if(operation !== 'read' && operation !== 'delete') {\n <form\n [class]=\"'dcf-form-grid ' + operation\" #component\n [id]=\"rendererId\"\n [formGroup]=\"formGroup\"\n (submit)=\"submit($event)\"\n novalidate\n [target]=\"target\">\n @if(!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n <ngx-decaf-layout\n [children]=\"children || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [rows]=\"rows\"\n [cols]=\"cols\" />\n\n <!-- @for (child of children; track $index) {\n <ngx-decaf-component-renderer\n [class]=\"(child?.props?.className ? 'dcf-form-item ' + child.props.className : 'dcf-form-item')\"\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [formRoot]=\"formGroup\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n } -->\n }\n @if(initialized) {\n <div class=\"dcf-buttons-grid 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 }\n\n </form>\n} @else {\n <section [class]=\"'dcf-grid dcf-grid-small dcf-child-width-1-1 dcf-form-grid ' + operation\" #component [id]=\"uid\">\n @if(!children?.length) {\n <ng-content #formContent></ng-content>\n } @else {\n @for (child of children; track $index) {\n <div [class]=\"(child?.props?.className ? 'dcf-form-item ' + child.props.className : 'dcf-form-item')\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n }\n }\n </section>\n <section [class]=\"'dcf-buttons-grid 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 </section>\n}\n\n", styles: [".dcf-buttons-grid{margin-top:.5rem;margin-bottom:0}.dcf-buttons-grid.read{margin-bottom:1rem}@media (min-width: 577px){.dcf-buttons-grid.dcf-flex{flex-direction:row-reverse}}@media (max-width: 576px){.dcf-buttons-grid.dcf-flex>div{width:100%}.dcf-buttons-grid.dcf-flex>div+div{margin-top:1rem}.dcf-buttons-grid.dcf-flex ion-button{width:100%}}.dcf-form-grid{padding:1rem}.dcf-form-grid .dcf-form-item{margin-bottom:1.8rem;margin-top:0!important}.dcf-form-grid.read .dcf-form-item{margin-bottom:1rem}::ng-deep ngx-decaf-stepped-form .dcf-input-item{margin-bottom:1.8rem;margin-top:0!important}::ng-deep ngx-decaf-fieldset .dcf-input-item{margin-bottom:1.8rem;margin-top:0!important}\n"] }]
|
|
4728
5113
|
}], ctorParameters: () => [] });
|
|
4729
5114
|
|
|
4730
5115
|
/**
|
|
@@ -4834,10 +5219,10 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxDecafComponentDir
|
|
|
4834
5219
|
* and this value should correspond to an available icon name.
|
|
4835
5220
|
*
|
|
4836
5221
|
* @type {string}
|
|
4837
|
-
* @default "
|
|
5222
|
+
* @default "folder-open-outline"
|
|
4838
5223
|
* @memberOf EmptyStateComponent
|
|
4839
5224
|
*/
|
|
4840
|
-
this.icon = "
|
|
5225
|
+
this.icon = "folder-open-outline";
|
|
4841
5226
|
/**
|
|
4842
5227
|
* @description The size of the displayed icon.
|
|
4843
5228
|
* @summary Controls the size of the icon shown in the empty state.
|
|
@@ -4890,6 +5275,7 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxDecafComponentDir
|
|
|
4890
5275
|
*/
|
|
4891
5276
|
this.buttonSize = 'default';
|
|
4892
5277
|
this.sanitizer = inject(DomSanitizer);
|
|
5278
|
+
this.enableCreationByModelRoute = false;
|
|
4893
5279
|
addIcons(allIcons);
|
|
4894
5280
|
}
|
|
4895
5281
|
/**
|
|
@@ -4922,15 +5308,12 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxDecafComponentDir
|
|
|
4922
5308
|
async ngOnInit() {
|
|
4923
5309
|
this.initialize();
|
|
4924
5310
|
this.showIcon = stringToBoolean(this.showIcon);
|
|
4925
|
-
// if(this.translatable) {
|
|
4926
|
-
// this.title = generateLocaleFromString(this.locale, this.title);
|
|
4927
|
-
// this.subtitle = generateLocaleFromString(this.locale, this.subtitle);
|
|
4928
|
-
// this.buttonText = generateLocaleFromString(this.locale, this.buttonText);
|
|
4929
|
-
// }
|
|
4930
5311
|
this.titleColor = `dcf-title color-${this.titleColor}`;
|
|
4931
5312
|
this.subtitleColor = `dcf-subtitle color-${this.titleColor}`;
|
|
4932
5313
|
if (this.searchValue)
|
|
4933
5314
|
this.searchSubtitle = await this.getSearchSubtitle(this.subtitle);
|
|
5315
|
+
if (!this.buttonLink && this.model && this.route)
|
|
5316
|
+
this.enableCreationByModelRoute = true;
|
|
4934
5317
|
}
|
|
4935
5318
|
/**
|
|
4936
5319
|
* @description Handles click events on the action button.
|
|
@@ -5002,7 +5385,7 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxDecafComponentDir
|
|
|
5002
5385
|
return this.sanitizer.bypassSecurityTrustHtml(result);
|
|
5003
5386
|
}
|
|
5004
5387
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5005
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: EmptyStateComponent, isStandalone: true, selector: "ngx-decaf-empty-state", inputs: { title: "title", titleColor: "titleColor", subtitle: "subtitle", subtitleColor: "subtitleColor", showIcon: "showIcon", icon: "icon", iconSize: "iconSize", iconColor: "iconColor", buttonLink: "buttonLink", buttonText: "buttonText", buttonFill: "buttonFill", buttonColor: "buttonColor", buttonSize: "buttonSize", searchValue: "searchValue" }, usesInheritance: true, ngImport: i0, template: "\n<ion-card [id]=\"uid\" [class]=\"className\">\n <ion-card-content>\n @if(icon && showIcon) {\n <div class=\"dcf-icon-container\">\n <ion-icon\n name=\"
|
|
5388
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: EmptyStateComponent, isStandalone: true, selector: "ngx-decaf-empty-state", inputs: { title: "title", titleColor: "titleColor", subtitle: "subtitle", subtitleColor: "subtitleColor", showIcon: "showIcon", icon: "icon", iconSize: "iconSize", iconColor: "iconColor", buttonLink: "buttonLink", buttonText: "buttonText", buttonFill: "buttonFill", buttonColor: "buttonColor", buttonSize: "buttonSize", searchValue: "searchValue" }, usesInheritance: true, ngImport: i0, template: "\n<ion-card [id]=\"uid\" [class]=\"className\">\n <ion-card-content>\n @if(icon && showIcon) {\n <div class=\"dcf-icon-container\">\n <ion-icon\n [name]=\"icon\"\n [size]=\"iconSize\"\n [color]=\"iconColor\"\n />\n </div>\n }\n @if(title) {\n <h5 [class]=\"titleColor\" [innerHTML]=\"title\"></h5>\n }\n @if(subtitle) {\n <p [class]=\"subtitleColor\" [innerHTML]=\"searchValue ? searchSubtitle : subtitle\"></p>\n }\n @if(!enableCreationByModelRoute) {\n @if(buttonLink && buttonText) {\n <div>\n <ion-button\n [size]=\"buttonSize\"\n [fill]=\"buttonFill\"\n [color]=\"buttonColor\"\n (click)=\"handleClick()\">\n {{ buttonText }}\n </ion-button>\n </div>\n }\n } @else {\n\n <div>\n <ion-button\n class=\"dcf-margin-top\"\n [size]=\"buttonSize\"\n [fill]=\"buttonFill\"\n [color]=\"buttonColor\"\n (click)=\"changeOperation(OperationKeys.CREATE)\" fill=\"clear\">\n {{ buttonText?.length ? buttonText : locale + '.button_create' | translate }}\n </ion-button>\n </div>\n\n }\n\n </ion-card-content>\n</ion-card>\n", styles: ["ion-card{text-align:center}ion-card ion-button{margin-top:.75rem}ion-card ion-icon{font-size:2.5rem}ion-card .dcf-icon-container{transform:scale(1.25);opacity:.75;margin-top:1.25rem!important;margin-bottom:.5rem!important}ion-card .dcf-ititle{font-weight:600!important;color:var(--dcf-color-gray-6)!important}ion-card .dcf-isubtitle{font-weight:500!important}\n"], dependencies: [{ kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { 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: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
5006
5389
|
};
|
|
5007
5390
|
EmptyStateComponent = __decorate([
|
|
5008
5391
|
Dynamic(),
|
|
@@ -5013,8 +5396,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
5013
5396
|
args: [{ selector: 'ngx-decaf-empty-state', standalone: true, imports: [
|
|
5014
5397
|
IonCard,
|
|
5015
5398
|
IonCardContent,
|
|
5016
|
-
IonIcon
|
|
5017
|
-
|
|
5399
|
+
IonIcon,
|
|
5400
|
+
TranslatePipe,
|
|
5401
|
+
IonButton
|
|
5402
|
+
], template: "\n<ion-card [id]=\"uid\" [class]=\"className\">\n <ion-card-content>\n @if(icon && showIcon) {\n <div class=\"dcf-icon-container\">\n <ion-icon\n [name]=\"icon\"\n [size]=\"iconSize\"\n [color]=\"iconColor\"\n />\n </div>\n }\n @if(title) {\n <h5 [class]=\"titleColor\" [innerHTML]=\"title\"></h5>\n }\n @if(subtitle) {\n <p [class]=\"subtitleColor\" [innerHTML]=\"searchValue ? searchSubtitle : subtitle\"></p>\n }\n @if(!enableCreationByModelRoute) {\n @if(buttonLink && buttonText) {\n <div>\n <ion-button\n [size]=\"buttonSize\"\n [fill]=\"buttonFill\"\n [color]=\"buttonColor\"\n (click)=\"handleClick()\">\n {{ buttonText }}\n </ion-button>\n </div>\n }\n } @else {\n\n <div>\n <ion-button\n class=\"dcf-margin-top\"\n [size]=\"buttonSize\"\n [fill]=\"buttonFill\"\n [color]=\"buttonColor\"\n (click)=\"changeOperation(OperationKeys.CREATE)\" fill=\"clear\">\n {{ buttonText?.length ? buttonText : locale + '.button_create' | translate }}\n </ion-button>\n </div>\n\n }\n\n </ion-card-content>\n</ion-card>\n", styles: ["ion-card{text-align:center}ion-card ion-button{margin-top:.75rem}ion-card ion-icon{font-size:2.5rem}ion-card .dcf-icon-container{transform:scale(1.25);opacity:.75;margin-top:1.25rem!important;margin-bottom:.5rem!important}ion-card .dcf-ititle{font-weight:600!important;color:var(--dcf-color-gray-6)!important}ion-card .dcf-isubtitle{font-weight:500!important}\n"] }]
|
|
5018
5403
|
}], ctorParameters: () => [], propDecorators: { title: [{
|
|
5019
5404
|
type: Input
|
|
5020
5405
|
}], titleColor: [{
|
|
@@ -5245,11 +5630,6 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
|
|
|
5245
5630
|
return child;
|
|
5246
5631
|
});
|
|
5247
5632
|
}
|
|
5248
|
-
// if(this.model) {
|
|
5249
|
-
// this._repository = getModelRepository(this.model);
|
|
5250
|
-
// console.log(this._repository);
|
|
5251
|
-
// }
|
|
5252
|
-
// console.log(this._repository);
|
|
5253
5633
|
this.initialized = true;
|
|
5254
5634
|
}
|
|
5255
5635
|
/**
|
|
@@ -5347,13 +5727,8 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
|
|
|
5347
5727
|
async handleCreateItem(event) {
|
|
5348
5728
|
if (event && event instanceof CustomEvent)
|
|
5349
5729
|
event.stopImmediatePropagation();
|
|
5350
|
-
// if(this.updatingItem)
|
|
5351
|
-
// return this.handleUpdateItem(this.updatingItem.index, true);
|
|
5352
5730
|
const action = this.updatingItem ? OperationKeys.UPDATE : OperationKeys.CREATE;
|
|
5353
5731
|
const formGroup = this.activeFormGroup;
|
|
5354
|
-
// currentGroup.updateValueAndValidity();
|
|
5355
|
-
// console.log((currentGroup.parent as FormArray).value);
|
|
5356
|
-
const parent = formGroup.parent;
|
|
5357
5732
|
const isValid = NgxDecafFormService.validateFields(formGroup);
|
|
5358
5733
|
// must pass correct pk here
|
|
5359
5734
|
const isUnique = NgxDecafFormService.isUniqueOnGroup(formGroup, action, action === OperationKeys.UPDATE ? this.updatingItem?.index : undefined);
|
|
@@ -5372,68 +5747,13 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
|
|
|
5372
5747
|
value?.[this.pk] || undefined : value;
|
|
5373
5748
|
}
|
|
5374
5749
|
}
|
|
5375
|
-
// windowEventEmitter(EventConstants.FIELDSET_ADD_GROUP, {
|
|
5376
|
-
// formGroup: this.updatingItem ? this.updatingItem : this.formGroup
|
|
5377
|
-
// });
|
|
5378
|
-
// const formParent = this.formGroup as FormArray;
|
|
5379
|
-
// const index = formParent.length - 1;
|
|
5380
|
-
// const formGroup = formParent.at(index) as FormGroup;
|
|
5381
|
-
// console.log(formGroup.errors);
|
|
5382
|
-
// const isValid = NgxDecafFormService.validateFields(this.formGroup as FormGroup);
|
|
5383
|
-
// const isUnique = NgxDecafFormService.isUniqueOnGroup(formGroup, index, OperationKeys.CREATE);
|
|
5384
|
-
// const value = formGroup.value;
|
|
5385
|
-
// console.log(isValid, isUnique);
|
|
5386
|
-
// this.changeDetectorRef.detectChanges();
|
|
5387
|
-
// if(!Object.keys(this.mapper).length)
|
|
5388
|
-
// this.mapper = this.getMapper(value as KeyValue);
|
|
5389
|
-
// if(isValid && isUnique) {
|
|
5390
|
-
// this.isUniqueError = undefined;
|
|
5391
|
-
// this.buttonLabel = this.translateService.instant(this.locale + '.add');
|
|
5392
|
-
// this.setValue();
|
|
5393
|
-
// // const fb = NgxDecafFormService.addGroupToParent((this.formGroup as FormArray).root as FormGroup, this.childOf as string, formParent.length).parent as FormArray;
|
|
5394
|
-
// } else {
|
|
5395
|
-
// this.isUniqueError = typeof value === 'object' ? (value as KeyValue)?.[this.pk] || undefined : value;
|
|
5396
|
-
// }
|
|
5397
|
-
// console.log(this.formGroup);
|
|
5398
|
-
// if(event && event instanceof CustomEvent) {
|
|
5399
|
-
// event.stopImmediatePropagation();
|
|
5400
|
-
// const {formGroup, value, isValid} = event.detail;
|
|
5401
|
-
// this.formGroup = formGroup as FormArray;
|
|
5402
|
-
// if(!this.mapper)
|
|
5403
|
-
// this.mapper = this.getMapper(value as KeyValue);
|
|
5404
|
-
// if(isValid ){
|
|
5405
|
-
// this.isUniqueError = undefined;
|
|
5406
|
-
// this.buttonLabel = this.translateService.instant(this.locale + '.add');
|
|
5407
|
-
// this.setValue();
|
|
5408
|
-
// } else {
|
|
5409
|
-
// this.isUniqueError = (value as KeyValue)?.[this.pk] || undefined;
|
|
5410
|
-
// }
|
|
5411
|
-
// } else {
|
|
5412
|
-
// windowEventEmitter(EventConstants.FIELDSET_ADD_GROUP, {
|
|
5413
|
-
// component: this.component.nativeElement,
|
|
5414
|
-
// index: this.updatingItem ? this.updatingItem.index : this.value?.length,
|
|
5415
|
-
// parent: this.childOf,
|
|
5416
|
-
// operation: !this.updatingItem ? OperationKeys.CREATE : OperationKeys.UPDATE
|
|
5417
|
-
// });
|
|
5418
|
-
// }
|
|
5419
5750
|
}
|
|
5420
|
-
handleUpdateItem(index
|
|
5751
|
+
handleUpdateItem(index) {
|
|
5421
5752
|
const formGroup = this.getFormArrayIndex(index);
|
|
5422
5753
|
if (formGroup) {
|
|
5423
5754
|
this.updatingItem = Object.assign({}, formGroup.value || {}, { index });
|
|
5424
5755
|
this.activeFormGroupIndex = index;
|
|
5425
5756
|
}
|
|
5426
|
-
// this.changeDetectorRef.detectChanges();
|
|
5427
|
-
// const item = this.formGroup.controls.find(control => `${control.get(this.pk)?.value}`.toLowerCase() === cleanSpaces(`${value}`, true)) as FormControl;
|
|
5428
|
-
// if(item) {
|
|
5429
|
-
// this.buttonLabel = this.translateService.instant(this.locale + '.update');
|
|
5430
|
-
// this.updatingItem = Object.assign({}, item.value || {}, {index});
|
|
5431
|
-
// windowEventEmitter(EventConstants.FIELDSET_UPDATE_GROUP, {
|
|
5432
|
-
// parent: this.childOf,
|
|
5433
|
-
// component: this.component.nativeElement,
|
|
5434
|
-
// index: index
|
|
5435
|
-
// });
|
|
5436
|
-
// }
|
|
5437
5757
|
}
|
|
5438
5758
|
/**
|
|
5439
5759
|
* @description Cancels the update mode and resets the UI state.
|
|
@@ -5478,23 +5798,6 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
|
|
|
5478
5798
|
this.setValue();
|
|
5479
5799
|
if (this.activeFormGroupIndex > 0)
|
|
5480
5800
|
this.activeFormGroupIndex = this.activeFormGroupIndex - 1;
|
|
5481
|
-
// if(event && event instanceof CustomEvent) {
|
|
5482
|
-
// event.stopImmediatePropagation();
|
|
5483
|
-
// return this.setValue();
|
|
5484
|
-
// }
|
|
5485
|
-
// const formArray = this.formGroup as FormArray;
|
|
5486
|
-
// const arrayLength = formArray.length;
|
|
5487
|
-
// for (let index = arrayLength - 1; index >= 0; index--) {
|
|
5488
|
-
// const group = formArray.at(index) as FormGroup;
|
|
5489
|
-
// if (cleanSpaces(group.get(this.pk)?.value) === cleanSpaces(value as string)) {
|
|
5490
|
-
// windowEventEmitter(EventConstants.FIELDSET_REMOVE_GROUP, {
|
|
5491
|
-
// parent: this.childOf,
|
|
5492
|
-
// component: this.component.nativeElement,
|
|
5493
|
-
// index,
|
|
5494
|
-
// formGroup: group
|
|
5495
|
-
// });
|
|
5496
|
-
// }
|
|
5497
|
-
// }
|
|
5498
5801
|
}
|
|
5499
5802
|
/**
|
|
5500
5803
|
* @description Handles reordering of items within the fieldset list.
|
|
@@ -5621,16 +5924,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
|
|
|
5621
5924
|
index: index + 1
|
|
5622
5925
|
};
|
|
5623
5926
|
});
|
|
5624
|
-
// const inputContainers = this.component.nativeElement.querySelectorAll('.dcf-input-item');
|
|
5625
|
-
// inputContainers.forEach((container: HTMLElement) => {
|
|
5626
|
-
// const input = container.querySelector('input, ion-input, ion-textarea, textarea') as HTMLInputElement | null;
|
|
5627
|
-
// if(input)
|
|
5628
|
-
// input.value = '';
|
|
5629
|
-
// })
|
|
5630
5927
|
this.updatingItem = undefined;
|
|
5631
|
-
// console.log(this.isUniqueError);
|
|
5632
|
-
// console.log(this.mapper);
|
|
5633
|
-
// console.log(this.items);
|
|
5634
5928
|
}
|
|
5635
5929
|
/**
|
|
5636
5930
|
* @description Automatically configures the field mapping based on the value structure.
|
|
@@ -5662,7 +5956,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
|
|
|
5662
5956
|
return this.mapper;
|
|
5663
5957
|
}
|
|
5664
5958
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: FieldsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5665
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: FieldsetComponent, isStandalone: true, selector: "ngx-decaf-fieldset", inputs: { formControl: "formControl", collapsable: "collapsable", page: "page", customTypes: "customTypes", title: "title", description: "description", multiple: "multiple", value: "value", borders: "borders" }, host: { properties: { "attr.id": "uid" } }, viewQueries: [{ propertyName: "accordionComponent", first: true, predicate: ["accordionComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n [class.remove-border]=\"!borders\"\n [class.open]=\"isOpen\"\n #component>\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"operation === 'read' ? 'open' : ''\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item [class.disable-collapse]=\"!collapsable\" slot=\"header\" [button]=\"collapsable\" (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($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($index)\">\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 <ng-content select=\"[slot=content]\"></ng-content>\n\n @if (this.children?.length) {\n @for (child of children; track $index) {\n <ngx-decaf-component-renderer\n [class]=\"(child?.props?.className ? ' ' + child.props.className : '')\"\n [tag]=\"child?.tag\"\n [parentComponent]=\"formGroup || parentComponent\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\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 @if (items.length < max || !max) {\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 </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}@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}ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}@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{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset{padding-top:1rem;padding-bottom:1rem;background:var(--dcf-card-background);border-radius:6px}.dcf-fieldset.remove-border{border:none!important;padding:0!important;margin:0!important}.dcf-fieldset.open ion-accordion{margin-bottom:1rem}.dcf-fieldset.open ion-accordion.accordion-collapsing,.dcf-fieldset.open ion-accordion.accordion-collapsed{margin-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}.dcf-fieldset ion-accordion{background:var(--dcf-card-background)}.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}.dcf-fieldset ion-accordion [slot=content]{padding-top:1.5rem!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-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: "component", type: ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "projectable", "model", "parentComponent", "parent"], outputs: ["listenEvent"] }, { 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"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
5959
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: FieldsetComponent, isStandalone: true, selector: "ngx-decaf-fieldset", inputs: { formControl: "formControl", collapsable: "collapsable", page: "page", customTypes: "customTypes", title: "title", description: "description", multiple: "multiple", value: "value", borders: "borders" }, viewQueries: [{ propertyName: "accordionComponent", first: true, predicate: ["accordionComponent"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n [class.remove-border]=\"!borders\"\n [class.open]=\"isOpen\"\n #component>\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"operation === 'read' ? 'open' : ''\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item [class.disable-collapse]=\"!collapsable\" slot=\"header\" [button]=\"collapsable\" (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($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($index)\">\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 @if(children?.length) {\n <ngx-decaf-layout\n gap=\"small\"\n [children]=\"children || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n [match]=\"false\"\n\n [rows]=\"rows\"\n [cols]=\"cols\"\n />\n }\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 @if (items.length < max || !max) {\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 </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}@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}ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}@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{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset{padding-top:1rem;padding-bottom:1rem;background:var(--dcf-card-background);border-radius:6px}.dcf-fieldset.remove-border{border:none!important;padding:0!important;margin:0!important}.dcf-fieldset.open ion-accordion{margin-bottom:1rem}.dcf-fieldset.open ion-accordion.accordion-collapsing,.dcf-fieldset.open ion-accordion.accordion-collapsed{margin-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}.dcf-fieldset ion-accordion{background:var(--dcf-card-background)}.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}.dcf-fieldset ion-accordion [slot=content]{padding-top:1.5rem!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-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: "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"] }, { kind: "component", type: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["gap", "breakpoint", "grid", "match"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
5666
5960
|
};
|
|
5667
5961
|
FieldsetComponent = __decorate([
|
|
5668
5962
|
Dynamic(),
|
|
@@ -5672,7 +5966,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
5672
5966
|
type: Component,
|
|
5673
5967
|
args: [{ standalone: true, selector: 'ngx-decaf-fieldset', schemas: [], imports: [
|
|
5674
5968
|
TranslatePipe,
|
|
5675
|
-
ComponentRendererComponent,
|
|
5676
5969
|
ReactiveFormsModule,
|
|
5677
5970
|
IonAccordionGroup,
|
|
5678
5971
|
IonAccordion,
|
|
@@ -5684,7 +5977,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
5684
5977
|
IonReorderGroup,
|
|
5685
5978
|
IonButton,
|
|
5686
5979
|
IonIcon,
|
|
5687
|
-
|
|
5980
|
+
LayoutComponent
|
|
5981
|
+
], template: "\n\n<fieldset\n (fieldsetAddGroupEvent)=\"handleCreateItem($event)\"\n [class]=\"'dcf-fieldset ' + operation\"\n [class.remove-border]=\"!borders\"\n [class.open]=\"isOpen\"\n #component>\n <ion-accordion-group class=\"dcf-width-1-1\" [class.open]=\"isOpen\" [class.hasValidationErrors]=\"hasValidationErrors\" [value]=\"operation === 'read' ? 'open' : ''\" #accordionComponent>\n <ion-accordion value=\"open\">\n <ion-item [class.disable-collapse]=\"!collapsable\" slot=\"header\" [button]=\"collapsable\" (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($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($index)\">\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 @if(children?.length) {\n <ngx-decaf-layout\n gap=\"small\"\n [children]=\"children || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n [match]=\"false\"\n\n [rows]=\"rows\"\n [cols]=\"cols\"\n />\n }\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 @if (items.length < max || !max) {\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 </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}@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}ion-accordion ion-item[slot=header] legend{color:var(--dcf-color-gray-7)}}@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{border:1px solid var(--dcf-color-gray-6)}}.dcf-fieldset{padding-top:1rem;padding-bottom:1rem;background:var(--dcf-card-background);border-radius:6px}.dcf-fieldset.remove-border{border:none!important;padding:0!important;margin:0!important}.dcf-fieldset.open ion-accordion{margin-bottom:1rem}.dcf-fieldset.open ion-accordion.accordion-collapsing,.dcf-fieldset.open ion-accordion.accordion-collapsed{margin-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}.dcf-fieldset ion-accordion{background:var(--dcf-card-background)}.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}.dcf-fieldset ion-accordion [slot=content]{padding-top:1.5rem!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-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"] }]
|
|
5688
5982
|
}], ctorParameters: () => [], propDecorators: { accordionComponent: [{
|
|
5689
5983
|
type: ViewChild,
|
|
5690
5984
|
args: ['accordionComponent', { static: false }]
|
|
@@ -7453,39 +7747,22 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
|
|
|
7453
7747
|
*/
|
|
7454
7748
|
this.disableSort = false;
|
|
7455
7749
|
/**
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
* title: 'empty.title',
|
|
7473
|
-
* subtitle: 'empty.subtitle',
|
|
7474
|
-
* showButton: false,
|
|
7475
|
-
* icon: 'alert-circle-outline',
|
|
7476
|
-
* buttonText: 'locale.empty.button',
|
|
7477
|
-
* link: ''
|
|
7478
|
-
* }
|
|
7479
|
-
* @memberOf ListComponent
|
|
7480
|
-
*/
|
|
7481
|
-
this.empty = {
|
|
7482
|
-
title: 'empty.title',
|
|
7483
|
-
subtitle: 'empty.subtitle',
|
|
7484
|
-
showButton: false,
|
|
7485
|
-
icon: 'alert-circle-outline',
|
|
7486
|
-
buttonText: 'locale.empty.button',
|
|
7487
|
-
link: ''
|
|
7488
|
-
};
|
|
7750
|
+
* @description Configuration for the empty state display.
|
|
7751
|
+
* @summary Customizes how the empty state is displayed when no data is available.
|
|
7752
|
+
* This includes the title, subtitle, button text, icon, and navigation link.
|
|
7753
|
+
*
|
|
7754
|
+
* @type {Partial<IListEmptyOptions>}
|
|
7755
|
+
* @default {
|
|
7756
|
+
* title: 'empty.title',
|
|
7757
|
+
* subtitle: 'empty.subtitle',
|
|
7758
|
+
* showButton: false,
|
|
7759
|
+
* icon: 'alert-circle-outline',
|
|
7760
|
+
* buttonText: 'locale.empty.button',
|
|
7761
|
+
* link: ''
|
|
7762
|
+
* }
|
|
7763
|
+
* @memberOf ListComponent
|
|
7764
|
+
*/
|
|
7765
|
+
this.empty = {};
|
|
7489
7766
|
/**
|
|
7490
7767
|
* @description The current page number in paginated mode.
|
|
7491
7768
|
* @summary Tracks which page is currently being displayed when the component
|
|
@@ -7517,6 +7794,7 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
|
|
|
7517
7794
|
* @memberOf ListComponent
|
|
7518
7795
|
*/
|
|
7519
7796
|
this.skeletonData = new Array(2);
|
|
7797
|
+
this.searching = false;
|
|
7520
7798
|
/**
|
|
7521
7799
|
* @description The last page number that was displayed.
|
|
7522
7800
|
* @summary Keeps track of the previously displayed page number, which is useful
|
|
@@ -7609,9 +7887,10 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
|
|
|
7609
7887
|
this.disableSort = stringToBoolean(this.disableSort);
|
|
7610
7888
|
if (typeof this.item?.['tag'] === 'boolean' && this.item?.['tag'] === true)
|
|
7611
7889
|
this.item['tag'] = ComponentsTagNames.LIST_ITEM;
|
|
7890
|
+
this.empty = Object.assign({}, DefaultListEmptyOptions, this.empty);
|
|
7612
7891
|
await this.refresh();
|
|
7613
|
-
if
|
|
7614
|
-
|
|
7892
|
+
// if(this.operations.includes(OperationKeys.CREATE) && this.route)
|
|
7893
|
+
// this.empty.link = `${this.route}/${OperationKeys.CREATE}`;
|
|
7615
7894
|
if (!this.initialized)
|
|
7616
7895
|
return this.parseProps(this);
|
|
7617
7896
|
this.initialized = true;
|
|
@@ -7782,6 +8061,7 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
|
|
|
7782
8061
|
* @memberOf ListComponent
|
|
7783
8062
|
*/
|
|
7784
8063
|
async handleSearch(value) {
|
|
8064
|
+
this.searching = value !== undefined;
|
|
7785
8065
|
if (this.type === ListComponentsTypes.INFINITE) {
|
|
7786
8066
|
this.loadMoreData = false;
|
|
7787
8067
|
if (value === undefined) {
|
|
@@ -8073,8 +8353,10 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
|
|
|
8073
8353
|
if (!this.indexes)
|
|
8074
8354
|
this.indexes = (Object.values(this.mapper) || [this.pk]);
|
|
8075
8355
|
const condition = this.parseConditions(this.searchValue);
|
|
8356
|
+
this.changeDetectorRef.detectChanges();
|
|
8076
8357
|
request = await this.parseResult(await repo.query(condition, (this.sortBy || this.pk), this.sortDirection));
|
|
8077
8358
|
data = [];
|
|
8359
|
+
this.changeDetectorRef.detectChanges();
|
|
8078
8360
|
}
|
|
8079
8361
|
data = this.type === ListComponentsTypes.INFINITE ? [...(data).concat(request)] : [...request];
|
|
8080
8362
|
}
|
|
@@ -8311,8 +8593,14 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
|
|
|
8311
8593
|
return accum;
|
|
8312
8594
|
}, []);
|
|
8313
8595
|
}
|
|
8596
|
+
parseSearchValue() {
|
|
8597
|
+
if (typeof this.searchValue === Primitives.STRING)
|
|
8598
|
+
return this.searchValue || "";
|
|
8599
|
+
const searchValue = this.searchValue;
|
|
8600
|
+
return (searchValue?.query).map(item => `${item.index} ${item.condition} ${item.value}`).join(", ");
|
|
8601
|
+
}
|
|
8314
8602
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: ListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8315
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: ListComponent, isStandalone: true, selector: "ngx-decaf-list", inputs: { type: "type", 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",
|
|
8603
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: ListComponent, isStandalone: true, selector: "ngx-decaf-list", inputs: { type: "type", 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", 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) {\n @if(model && enableFilter) {\n @if(data?.length || searching) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\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(!searching) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [model]=\"model\"\n [icon]=\"empty.icon\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\" />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n [model]=\"model\"\n className=\"empty-search\"\n [translatable]=\"true\"\n [title]=\"locale + '.search.title' | translate\"\n [subtitle]=\"locale + '.search.subtitle' | translate: {'0': parseSearchValue()}\"\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: "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", "projectable", "model", "parentComponent", "parent"], outputs: ["listenEvent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
8316
8604
|
};
|
|
8317
8605
|
ListComponent = __decorate([
|
|
8318
8606
|
Dynamic(),
|
|
@@ -8339,7 +8627,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
8339
8627
|
EmptyStateComponent,
|
|
8340
8628
|
FilterComponent,
|
|
8341
8629
|
ComponentRendererComponent
|
|
8342
|
-
], 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
|
|
8630
|
+
], 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) {\n @if(model && enableFilter) {\n @if(data?.length || searching) {\n <ngx-decaf-filter\n [model]=\"model\"\n [sortDirection]=\"sortDirection\"\n [disableSort]=\"disableSort\"\n (filterEvent)=\"handleFilter($event)\"\n (searchEvent)=\"handleSearch($event)\"\n />\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(!searching) {\n <ngx-decaf-empty-state\n [title]=\"(locale + '.'+ empty.title) | translate\"\n [model]=\"model\"\n [icon]=\"empty.icon\"\n [subtitle]=\"(locale + '.'+ empty.subtitle) | translate\" />\n } @else {\n <ngx-decaf-empty-state\n icon=\"search-outline\"\n [model]=\"model\"\n className=\"empty-search\"\n [translatable]=\"true\"\n [title]=\"locale + '.search.title' | translate\"\n [subtitle]=\"locale + '.search.subtitle' | translate: {'0': parseSearchValue()}\"\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"] }]
|
|
8343
8631
|
}], ctorParameters: () => [], propDecorators: { type: [{
|
|
8344
8632
|
type: Input
|
|
8345
8633
|
}], showSearchbar: [{
|
|
@@ -8376,8 +8664,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
8376
8664
|
type: Input
|
|
8377
8665
|
}], disableSort: [{
|
|
8378
8666
|
type: Input
|
|
8379
|
-
}], emptyIcon: [{
|
|
8380
|
-
type: Input
|
|
8381
8667
|
}], empty: [{
|
|
8382
8668
|
type: Input
|
|
8383
8669
|
}], refreshEvent: [{
|
|
@@ -8786,7 +9072,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
8786
9072
|
args: ['window:resize', ['$event']]
|
|
8787
9073
|
}] } });
|
|
8788
9074
|
|
|
8789
|
-
let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponentDirective
|
|
9075
|
+
let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponentDirective {
|
|
8790
9076
|
/**
|
|
8791
9077
|
* @description Creates an instance of SteppedFormComponent.
|
|
8792
9078
|
* @summary Initializes a new SteppedFormComponent instance and registers the required
|
|
@@ -8892,17 +9178,6 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponent
|
|
|
8892
9178
|
* @memberOf SteppedFormComponent
|
|
8893
9179
|
*/
|
|
8894
9180
|
this.pagesArray = [];
|
|
8895
|
-
/**
|
|
8896
|
-
* @description Angular Location service.
|
|
8897
|
-
* @summary Injected service that provides access to the browser's URL and history.
|
|
8898
|
-
* This service is used for interacting with the browser's history API, allowing
|
|
8899
|
-
* for back navigation and URL manipulation outside of Angular's router.
|
|
8900
|
-
*
|
|
8901
|
-
* @private
|
|
8902
|
-
* @type {Location}
|
|
8903
|
-
* @memberOf CrudFormComponent
|
|
8904
|
-
*/
|
|
8905
|
-
this.location = inject(Location);
|
|
8906
9181
|
/**
|
|
8907
9182
|
* @description Event emitter for form submission.
|
|
8908
9183
|
* @summary Emits events when the form is submitted, typically on the last page
|
|
@@ -8938,12 +9213,16 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponent
|
|
|
8938
9213
|
* @memberOf SteppedFormComponent
|
|
8939
9214
|
*/
|
|
8940
9215
|
async ngOnInit() {
|
|
8941
|
-
console.log(this);
|
|
8942
9216
|
if (!this.locale)
|
|
8943
9217
|
this.locale = getLocaleContext("SteppedFormComponent");
|
|
8944
9218
|
this.activePage = this.startPage;
|
|
8945
|
-
if (
|
|
8946
|
-
this.pageTitles =
|
|
9219
|
+
if (typeof this.pages === 'object') {
|
|
9220
|
+
this.pageTitles = this.pages;
|
|
9221
|
+
}
|
|
9222
|
+
else {
|
|
9223
|
+
if (!this.pageTitles.length)
|
|
9224
|
+
this.pageTitles = Array.from({ length: this.pages }, () => ({ title: '', description: '' }));
|
|
9225
|
+
}
|
|
8947
9226
|
this.pages = this.pageTitles.length;
|
|
8948
9227
|
if (this.paginated) {
|
|
8949
9228
|
this.children = [...this.children.map((c) => {
|
|
@@ -8969,6 +9248,7 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponent
|
|
|
8969
9248
|
});
|
|
8970
9249
|
this.activeFormGroup = this.formGroup;
|
|
8971
9250
|
}
|
|
9251
|
+
this.initialized = true;
|
|
8972
9252
|
}
|
|
8973
9253
|
/**
|
|
8974
9254
|
* @description Cleanup method called when the component is destroyed.
|
|
@@ -9087,7 +9367,7 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponent
|
|
|
9087
9367
|
this.timerSubscription = timer(10).subscribe(() => this.activeChildren = this.children.filter(c => c.props?.['page'] === page));
|
|
9088
9368
|
}
|
|
9089
9369
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SteppedFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9090
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SteppedFormComponent, isStandalone: true, selector: "ngx-decaf-stepped-form", inputs: { children: "children", paginated: "paginated", pages: "pages", pageTitles: "pageTitles", operation: "operation", startPage: "startPage", formGroup: "formGroup" }, outputs: { submitEvent: "submitEvent" },
|
|
9370
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.7", type: SteppedFormComponent, isStandalone: true, selector: "ngx-decaf-stepped-form", inputs: { children: "children", paginated: "paginated", pages: "pages", pageTitles: "pageTitles", operation: "operation", startPage: "startPage", formGroup: "formGroup" }, outputs: { submitEvent: "submitEvent" }, usesInheritance: true, ngImport: i0, template: "<form class=\"dcf-steped-form\" [class.paginated]=\"paginated\" novalidate>\n @if(paginated) {\n <div class=\"dcf-page-steps\">\n <div class=\"dcf-grid dcf-grid-collapse skip\">\n @for(page of pageTitles; track $index;) {\n <div class=\"dcf-flex dcf-flex-middle\">\n <div class=\"dcf-step\" [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n @if((page?.title || page?.description)) {\n <div class=\"dcf-information dcf-visible@s\">\n @if(page?.title) {\n <div class=\"dcf-title\">{{ page?.title | translate }}</div>\n }\n @if(page?.description) {\n <div class=\"dcf-description\">{{ page?.description | translate }}</div>\n }\n <div class=\"dcf-separator\"></div>\n </div>\n }\n @if($index < pageTitles.length - 1) {\n <div class=\"dcf-arrow-container\">\n <svg width=\"8\" height=\"12\" viewBox=\"0 0 8 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.5 1L6.5 6L1.5 11\" />\n </svg>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if(pageTitles[activePage - 1]?.title || pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-current-step\">\n <div>\n @if(pageTitles[activePage - 1]?.title) {\n <div class=\"dcf-title\">{{ pageTitles[activePage - 1]?.title | translate }}</div>\n }\n @if(pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-description\">{{ pageTitles[activePage - 1]?.description | translate }}</div>\n }\n </div>\n </div>\n }\n\n @if(initialized && activeChildren?.length) {\n <ngx-decaf-layout\n [children]=\"activeChildren || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [match]=\"false\"\n\n />\n <!-- @for(child of activeChildren; track $index) {\n <div class=\"dcf-step-form-container\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n\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 <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 color=\"light\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon> -->\n {{locale + '.previous' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"solid\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n {{locale + '.submit' | translate}}\n } @else {\n {{locale + '.next' | translate}}\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon> -->\n }\n </ion-button>\n </div>\n </div>\n } @else {\n <div class=\"dcf-single-step\">\n @for (item of children; track $index) {\n <ion-card>\n <ion-card-content>\n @if(item.title || item.description) {\n <div class=\"dcf-information\">\n <div>\n @if(item.title) {\n <div class=\"dcf-title\">{{ item.title | translate }}</div>\n }\n @if(item.description) {\n <div class=\"dcf-description\">{{ item.description | translate }}</div>\n }\n </div>\n </div>\n }\n <div>\n @if(initialized && item.items?.length) {\n <div>\n <ngx-decaf-layout\n [children]=\"item.items || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [match]=\"false\"\n\n />\n </div>\n\n }\n </div>\n </ion-card-content>\n </ion-card>\n }\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-small dcf-flex dcf-flex-right\">\n <div class=\"dcf-width-auto@s dcf-width-1-1\">\n <ion-button color=\"light\" (click)=\"handleBack()\">\n {{locale + '.cancel' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-auto@s dcf-width-1-1\">\n <ion-button fill=\"solid\" (click)=\"handleNext(true)\">\n {{locale + '.submit' | translate}}\n </ion-button>\n </div>\n </div>\n </div>\n }\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.paginated{padding:2rem 1rem}.dcf-page-steps{display:flex;justify-content:center;align-items:center;margin-bottom:2rem;overflow-x:auto;flex-wrap:nowrap}.dcf-page-steps .dcf-grid{display:flex!important;flex-wrap:nowrap!important;align-items:center}.dcf-step{height:38px;min-width:38px;width:38px;background:var(--dcf-color-gray-2);margin:0;display:flex;color:var(--dcf-color-gray-7);justify-content:center;align-items:center;font-size:1rem;font-weight:600;border-radius:var(--dcf-border-radius)}.dcf-step.dcf-active{color:var(--dcf-color-light);background:var(--ion-color-primary);box-shadow:0 2px 6px #144c714d}.dcf-step.dcf-passed{color:var(--dcf-color-primary-shade);background:var(--dcf-color-gray-3)}.dcf-information{padding-left:.5rem}.dcf-title{font-size:.875rem;font-weight:600;margin:0;color:var(--dcf-color-gray-7)}.dcf-description{font-size:.8rem;font-weight:500;margin:0;margin-top:.25rem;color:var(--dcf-color-gray-4)}.dcf-arrow-container{display:flex;align-items:center;justify-content:center;padding:0 .5rem;height:38px}.dcf-arrow-container{display:flex;align-items:center;justify-content:center;padding:0 1rem;height:40px}.dcf-arrow-container svg{width:1rem;height:1rem;stroke:var(--dcf-color-gray-8);stroke-opacity:.7;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}ion-button[color=light]{--background: var(--dcf-color-gray-7) !important}.dcf-current-step{margin-top:-.5rem!important;margin-bottom:1.75rem!important;display:flex;align-items:center;justify-content:center}@media (min-width: 639px){.dcf-current-step{display:none}}.dcf-single-step .dcf-information{margin-bottom:1rem}.dcf-single-step .dcf-step-container:not(.ngx-decaf-fieldset){padding-bottom:1.5rem;padding-top:.5rem}.dcf-single-step ion-card{margin-bottom:1.5rem}.dcf-single-step ion-card .dcf-information{margin-top:.75rem}.dcf-step-form-container{margin-bottom:1.75rem!important}::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset,::ng-deep ngx-decaf-fieldset{padding-top:0!important;padding-bottom:0!important}::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset ion-button,::ng-deep ngx-decaf-fieldset ion-button{margin-top:1rem!important}\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: LayoutComponent, selector: "ngx-decaf-layout", inputs: ["gap", "breakpoint", "grid", "match"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
9091
9371
|
};
|
|
9092
9372
|
SteppedFormComponent = __decorate([
|
|
9093
9373
|
Dynamic(),
|
|
@@ -9101,9 +9381,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
9101
9381
|
IonSkeletonText,
|
|
9102
9382
|
IonText,
|
|
9103
9383
|
IonButton,
|
|
9104
|
-
LayoutComponent
|
|
9105
|
-
|
|
9106
|
-
], standalone: true, host: { '[attr.id]': 'uid' }, template: "<form class=\"dcf-steped-form\" [class.paginated]=\"paginated\" novalidate>\n @if(paginated) {\n <div class=\"dcf-page-steps\">\n <div class=\"dcf-grid dcf-grid-collapse skip\">\n @for(page of pageTitles; track $index;) {\n <div class=\"dcf-flex dcf-flex-middle\">\n <div class=\"dcf-step\" [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n @if((page?.title || page?.description)) {\n <div class=\"dcf-information dcf-visible@s\">\n @if(page?.title) {\n <div class=\"dcf-title\">{{ page?.title | translate }}</div>\n }\n @if(page?.description) {\n <div class=\"dcf-description\">{{ page?.description | translate }}</div>\n }\n <div class=\"dcf-separator\"></div>\n </div>\n }\n @if($index < pageTitles.length - 1) {\n <div class=\"dcf-arrow-container\">\n <svg width=\"8\" height=\"12\" viewBox=\"0 0 8 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.5 1L6.5 6L1.5 11\" />\n </svg>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if(pageTitles[activePage - 1]?.title || pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-current-step\">\n <div>\n @if(pageTitles[activePage - 1]?.title) {\n <div class=\"dcf-title\">{{ pageTitles[activePage - 1]?.title | translate }}</div>\n }\n @if(pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-description\">{{ pageTitles[activePage - 1]?.description | translate }}</div>\n }\n </div>\n </div>\n }\n\n @if(formGroup) {\n <!-- <ngx-decaf-layout\n [children]=\"children || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [initializeProps]=\"false\"\n [rows]=\"rows ?? 1\"\n [cols]=\"cols ?? 1\" /> -->\n @for(child of activeChildren; track $index) {\n <div class=\"dcf-step-form-container\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n\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 <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 color=\"light\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon> -->\n {{locale + '.previous' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"solid\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n {{locale + '.submit' | translate}}\n } @else {\n {{locale + '.next' | translate}}\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon> -->\n }\n </ion-button>\n </div>\n </div>\n } @else {\n <div class=\"dcf-single-step\">\n @for (item of children; track $index) {\n <ion-card>\n <ion-card-content>\n @if(item.title || item.description) {\n <div class=\"dcf-information\">\n <div>\n @if(item.title) {\n <div class=\"dcf-title\">{{ item.title | translate }}</div>\n }\n @if(item.description) {\n <div class=\"dcf-description\">{{ item.description | translate }}</div>\n }\n </div>\n </div>\n }\n <div class=\"dcf-grid dcf-grid-small dcf-child-width-1-1\">\n @for (child of item.items; track $index) {\n <ngx-decaf-component-renderer\n [class]=\"'dcf-step-container ' + (child?.props?.className ? child.props.className + ' ' : ' ') + child.tag\"\n [tag]=\"child?.tag\"\n [projectable]=\"false\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n }\n </div>\n </ion-card-content>\n </ion-card>\n }\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-small dcf-flex dcf-flex-right\">\n <div class=\"dcf-width-auto@s dcf-width-1-1\">\n <ion-button color=\"light\" (click)=\"handleBack()\">\n {{locale + '.cancel' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-auto@s dcf-width-1-1\">\n <ion-button fill=\"solid\" (click)=\"handleNext(true)\">\n {{locale + '.submit' | translate}}\n </ion-button>\n </div>\n </div>\n </div>\n }\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.paginated{padding:2rem 1rem}.dcf-page-steps{display:flex;justify-content:center;align-items:center;margin-bottom:2rem;overflow-x:auto;flex-wrap:nowrap}.dcf-page-steps .dcf-grid{display:flex!important;flex-wrap:nowrap!important;align-items:center}.dcf-step{height:38px;min-width:38px;width:38px;background:var(--dcf-color-gray-2);margin:0;display:flex;color:var(--dcf-color-gray-7);justify-content:center;align-items:center;font-size:1rem;font-weight:600;border-radius:var(--dcf-border-radius)}.dcf-step.dcf-active{color:var(--dcf-color-light);background:var(--ion-color-primary);box-shadow:0 2px 6px #144c714d}.dcf-step.dcf-passed{color:var(--dcf-color-primary-shade);background:var(--dcf-color-gray-3)}.dcf-information{padding-left:.5rem}.dcf-title{font-size:.875rem;font-weight:600;margin:0;color:var(--dcf-color-gray-7)}.dcf-description{font-size:.8rem;font-weight:500;margin:0;margin-top:.25rem;color:var(--dcf-color-gray-4)}.dcf-arrow-container{display:flex;align-items:center;justify-content:center;padding:0 .5rem;height:38px}.dcf-arrow-container{display:flex;align-items:center;justify-content:center;padding:0 1rem;height:40px}.dcf-arrow-container svg{width:1rem;height:1rem;stroke:var(--dcf-color-gray-8);stroke-opacity:.7;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}ion-button[color=light]{--background: var(--dcf-color-gray-7) !important}.dcf-current-step{margin-top:-.5rem!important;margin-bottom:1.75rem!important;display:flex;align-items:center;justify-content:center}@media (min-width: 639px){.dcf-current-step{display:none}}.dcf-single-step .dcf-information{margin-bottom:1rem}.dcf-single-step .dcf-step-container:not(.ngx-decaf-fieldset){padding-bottom:1.5rem;padding-top:.5rem}.dcf-single-step ion-card{margin-bottom:1.5rem}.dcf-single-step ion-card .dcf-information{margin-top:.75rem}.dcf-step-form-container{margin-bottom:1.75rem!important}::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset,::ng-deep ngx-decaf-fieldset{padding-top:0!important;padding-bottom:0!important}::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset ion-button,::ng-deep ngx-decaf-fieldset ion-button{margin-top:1rem!important}\n"] }]
|
|
9384
|
+
LayoutComponent
|
|
9385
|
+
], standalone: true, template: "<form class=\"dcf-steped-form\" [class.paginated]=\"paginated\" novalidate>\n @if(paginated) {\n <div class=\"dcf-page-steps\">\n <div class=\"dcf-grid dcf-grid-collapse skip\">\n @for(page of pageTitles; track $index;) {\n <div class=\"dcf-flex dcf-flex-middle\">\n <div class=\"dcf-step\" [class.dcf-active]=\"activePage === $index + 1\" [class.dcf-passed]=\"($index + 1) < activePage\">{{ $index + 1 }}</div>\n @if((page?.title || page?.description)) {\n <div class=\"dcf-information dcf-visible@s\">\n @if(page?.title) {\n <div class=\"dcf-title\">{{ page?.title | translate }}</div>\n }\n @if(page?.description) {\n <div class=\"dcf-description\">{{ page?.description | translate }}</div>\n }\n <div class=\"dcf-separator\"></div>\n </div>\n }\n @if($index < pageTitles.length - 1) {\n <div class=\"dcf-arrow-container\">\n <svg width=\"8\" height=\"12\" viewBox=\"0 0 8 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M1.5 1L6.5 6L1.5 11\" />\n </svg>\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if(pageTitles[activePage - 1]?.title || pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-current-step\">\n <div>\n @if(pageTitles[activePage - 1]?.title) {\n <div class=\"dcf-title\">{{ pageTitles[activePage - 1]?.title | translate }}</div>\n }\n @if(pageTitles[activePage - 1]?.description) {\n <div class=\"dcf-description\">{{ pageTitles[activePage - 1]?.description | translate }}</div>\n }\n </div>\n </div>\n }\n\n @if(initialized && activeChildren?.length) {\n <ngx-decaf-layout\n [children]=\"activeChildren || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [match]=\"false\"\n\n />\n <!-- @for(child of activeChildren; track $index) {\n <div class=\"dcf-step-form-container\">\n <ngx-decaf-component-renderer\n [tag]=\"child?.tag\"\n (listenEvent)=\"handleEvent($event)\"\n [children]=\"child?.children || []\"\n [globals]=\"{props: child.props}\"\n />\n </div>\n\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 <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 color=\"light\" (click)=\"handleBack()\" [disabled]=\"activePage <= 1\">\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-back-outline\"></ion-icon> -->\n {{locale + '.previous' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-1-2@s\">\n <ion-button fill=\"solid\" (click)=\"handleNext(activePage === pages ? true : false)\">\n @if(activePage === pages) {\n {{locale + '.submit' | translate}}\n } @else {\n {{locale + '.next' | translate}}\n <!-- <ion-icon aria-hidden=\"true\" name=\"arrow-forward-outline\"></ion-icon> -->\n }\n </ion-button>\n </div>\n </div>\n } @else {\n <div class=\"dcf-single-step\">\n @for (item of children; track $index) {\n <ion-card>\n <ion-card-content>\n @if(item.title || item.description) {\n <div class=\"dcf-information\">\n <div>\n @if(item.title) {\n <div class=\"dcf-title\">{{ item.title | translate }}</div>\n }\n @if(item.description) {\n <div class=\"dcf-description\">{{ item.description | translate }}</div>\n }\n </div>\n </div>\n }\n <div>\n @if(initialized && item.items?.length) {\n <div>\n <ngx-decaf-layout\n [children]=\"item.items || []\"\n [parentComponent]=\"formGroup || parentComponent\"\n gap=\"small\"\n [rows]=\"rows\"\n [cols]=\"cols\"\n [match]=\"false\"\n\n />\n </div>\n\n }\n </div>\n </ion-card-content>\n </ion-card>\n }\n <div class=\"dcf-buttons-container dcf-grid dcf-grid-small dcf-flex dcf-flex-right\">\n <div class=\"dcf-width-auto@s dcf-width-1-1\">\n <ion-button color=\"light\" (click)=\"handleBack()\">\n {{locale + '.cancel' | translate}}\n </ion-button>\n </div>\n\n <div class=\"dcf-width-auto@s dcf-width-1-1\">\n <ion-button fill=\"solid\" (click)=\"handleNext(true)\">\n {{locale + '.submit' | translate}}\n </ion-button>\n </div>\n </div>\n </div>\n }\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.paginated{padding:2rem 1rem}.dcf-page-steps{display:flex;justify-content:center;align-items:center;margin-bottom:2rem;overflow-x:auto;flex-wrap:nowrap}.dcf-page-steps .dcf-grid{display:flex!important;flex-wrap:nowrap!important;align-items:center}.dcf-step{height:38px;min-width:38px;width:38px;background:var(--dcf-color-gray-2);margin:0;display:flex;color:var(--dcf-color-gray-7);justify-content:center;align-items:center;font-size:1rem;font-weight:600;border-radius:var(--dcf-border-radius)}.dcf-step.dcf-active{color:var(--dcf-color-light);background:var(--ion-color-primary);box-shadow:0 2px 6px #144c714d}.dcf-step.dcf-passed{color:var(--dcf-color-primary-shade);background:var(--dcf-color-gray-3)}.dcf-information{padding-left:.5rem}.dcf-title{font-size:.875rem;font-weight:600;margin:0;color:var(--dcf-color-gray-7)}.dcf-description{font-size:.8rem;font-weight:500;margin:0;margin-top:.25rem;color:var(--dcf-color-gray-4)}.dcf-arrow-container{display:flex;align-items:center;justify-content:center;padding:0 .5rem;height:38px}.dcf-arrow-container{display:flex;align-items:center;justify-content:center;padding:0 1rem;height:40px}.dcf-arrow-container svg{width:1rem;height:1rem;stroke:var(--dcf-color-gray-8);stroke-opacity:.7;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}ion-button[color=light]{--background: var(--dcf-color-gray-7) !important}.dcf-current-step{margin-top:-.5rem!important;margin-bottom:1.75rem!important;display:flex;align-items:center;justify-content:center}@media (min-width: 639px){.dcf-current-step{display:none}}.dcf-single-step .dcf-information{margin-bottom:1rem}.dcf-single-step .dcf-step-container:not(.ngx-decaf-fieldset){padding-bottom:1.5rem;padding-top:.5rem}.dcf-single-step ion-card{margin-bottom:1.5rem}.dcf-single-step ion-card .dcf-information{margin-top:.75rem}.dcf-step-form-container{margin-bottom:1.75rem!important}::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset,::ng-deep ngx-decaf-fieldset{padding-top:0!important;padding-bottom:0!important}::ng-deep ngx-decaf-component-renderer.ngx-decaf-fieldset ion-button,::ng-deep ngx-decaf-fieldset ion-button{margin-top:1rem!important}\n"] }]
|
|
9107
9386
|
}], ctorParameters: () => [], propDecorators: { children: [{
|
|
9108
9387
|
type: Input
|
|
9109
9388
|
}], paginated: [{
|
|
@@ -9277,5 +9556,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
9277
9556
|
* Generated bundle index. Do not edit.
|
|
9278
9557
|
*/
|
|
9279
9558
|
|
|
9280
|
-
export { AngularEngineKeys, BaseComponentProps, CPTKN, CollapsableDirective, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_PROVIDER, DB_ADAPTER_PROVIDER_TOKEN, DefaultFormReactiveOptions, Dynamic, DynamicModule, EmptyStateComponent, EventConstants, FieldsetComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, FormConstants, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, I18nParser, LOCALE_ROOT_TOKEN, LayoutComponent, ListComponent, ListComponentsTypes, ListItemComponent, LoggerLevels, ModelRendererComponent, NgxDecafComponentDirective, NgxDecafFormFieldDirective, NgxDecafFormService, NgxEventHandler, NgxPageDirective, NgxRenderingEngine, PaginationComponent, RouteDirections, SearchbarComponent, SteppedFormComponent, cleanSpaces, dataMapper, formatDate, generateRandomValue, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getModelRepository, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidDate, itemMapper, parseToValidDate, provideDbAdapter, provideI18n, provideI18nLoader, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
|
|
9559
|
+
export { AngularEngineKeys, BaseComponentProps, CPTKN, CollapsableDirective, ComponentRendererComponent, ComponentsTagNames, CrudFieldComponent, CrudFormComponent, CssClasses, DB_ADAPTER_PROVIDER, DB_ADAPTER_PROVIDER_TOKEN, DefaultFormReactiveOptions, DefaultListEmptyOptions, Dynamic, DynamicModule, EmptyStateComponent, EventConstants, FieldsetComponent, FilterComponent, ForAngularCommonModule, ForAngularComponentsModule, FormConstants, I18N_CONFIG_TOKEN, I18nLoader, I18nLoaderFactory, I18nParser, LOCALE_ROOT_TOKEN, LayoutComponent, ListComponent, ListComponentsTypes, ListItemComponent, LoggerLevels, ModelRendererComponent, NgxDecafComponentDirective, NgxDecafFormFieldDirective, NgxDecafFormService, NgxEventHandler, NgxPageDirective, NgxRenderingEngine, PaginationComponent, RouteDirections, SearchbarComponent, SteppedFormComponent, cleanSpaces, dataMapper, formatDate, generateRandomValue, getInjectablesRegistry, getLocaleContext, getLocaleContextByKey, getLocaleFromClassName, getLocaleLanguage, getLogger, getModelRepository, getOnWindow, getOnWindowDocument, getWindow, getWindowDocument, getWindowWidth, isDarkMode, isDevelopmentMode, isNotUndefined, isValidDate, itemMapper, parseToValidDate, provideDbAdapter, provideI18n, provideI18nLoader, removeFocusTrap, setOnWindow, stringToBoolean, windowEventEmitter };
|
|
9281
9560
|
//# sourceMappingURL=decaf-ts-for-angular.mjs.map
|