@decaf-ts/for-angular 0.0.36 → 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 +997 -719
- package/fesm2022/decaf-ts-for-angular.mjs.map +1 -1
- package/index.d.ts +1173 -591
- package/package.json +3 -2
|
@@ -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';
|
|
@@ -24,9 +24,11 @@ import * as allIcons from 'ionicons/icons';
|
|
|
24
24
|
import { chevronUpOutline, chevronDownOutline, createOutline, alertCircleOutline, chevronForwardOutline, chevronBackOutline, arrowBackOutline, arrowForwardOutline } from 'ionicons/icons';
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* @description Angular engine key constants
|
|
27
|
+
* @description Angular engine key constants.
|
|
28
28
|
* @summary Contains key strings used by the Angular rendering engine for reflection,
|
|
29
|
-
* 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.
|
|
30
32
|
* @typedef {Object} AngularEngineKeys
|
|
31
33
|
* @property {string} REFLECT - Prefix for reflection metadata keys
|
|
32
34
|
* @property {string} DYNAMIC - Key for dynamic component identification
|
|
@@ -40,8 +42,10 @@ import { chevronUpOutline, chevronDownOutline, createOutline, alertCircleOutline
|
|
|
40
42
|
* @property {string} RENDER - Key for renderable components
|
|
41
43
|
* @property {string} RENDERED_ID - Template for rendered component IDs
|
|
42
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
|
|
43
47
|
* @const AngularEngineKeys
|
|
44
|
-
* @memberOf module:engine
|
|
48
|
+
* @memberOf module:lib/engine/constants
|
|
45
49
|
*/
|
|
46
50
|
const AngularEngineKeys = {
|
|
47
51
|
REFLECT: `${UIKeys.REFLECT}.angular.`,
|
|
@@ -57,32 +61,40 @@ const AngularEngineKeys = {
|
|
|
57
61
|
RENDERED_ID: 'rendered-as-{0}',
|
|
58
62
|
PARENT: '_parent',
|
|
59
63
|
VALIDATION_PARENT_KEY: VALIDATION_PARENT_KEY,
|
|
64
|
+
FLAVOUR: "angular",
|
|
60
65
|
};
|
|
61
66
|
/**
|
|
62
|
-
* @description Form validation state constants
|
|
67
|
+
* @description Form validation state constants.
|
|
63
68
|
* @summary Contains constants representing the possible validation states of a form.
|
|
64
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.
|
|
65
72
|
* @typedef {Object} FormConstants
|
|
66
73
|
* @property {string} VALID - Constant representing a valid form state
|
|
67
74
|
* @property {string} INVALID - Constant representing an invalid form state
|
|
68
75
|
* @const FormConstants
|
|
69
|
-
* @memberOf module:engine
|
|
76
|
+
* @memberOf module:lib/engine/constants
|
|
70
77
|
*/
|
|
71
78
|
const FormConstants = {
|
|
72
79
|
VALID: 'VALID',
|
|
73
80
|
INVALID: 'INVALID',
|
|
74
81
|
};
|
|
75
82
|
/**
|
|
76
|
-
* @description Event name constants
|
|
77
|
-
* @summary
|
|
78
|
-
* These
|
|
79
|
-
*
|
|
80
|
-
* @
|
|
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
|
|
81
88
|
* @property {string} BACK_BUTTON_NAVIGATION - Event fired when back button navigation ends
|
|
82
|
-
* @property {string}
|
|
83
|
-
* @property {string}
|
|
84
|
-
* @property {string}
|
|
85
|
-
* @
|
|
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
|
|
86
98
|
*/
|
|
87
99
|
const EventConstants = {
|
|
88
100
|
BACK_BUTTON_NAVIGATION: 'backButtonNavigationEndEvent',
|
|
@@ -96,9 +108,11 @@ const EventConstants = {
|
|
|
96
108
|
// FIELDSET_GROUP_VALIDATION: 'fieldsetGroupValidationEvent'
|
|
97
109
|
};
|
|
98
110
|
/**
|
|
99
|
-
* @description Logger level constants
|
|
100
|
-
* @summary
|
|
101
|
-
* 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.
|
|
102
116
|
* @enum {number}
|
|
103
117
|
* @readonly
|
|
104
118
|
* @property {number} ALL - Log everything (most verbose)
|
|
@@ -107,7 +121,7 @@ const EventConstants = {
|
|
|
107
121
|
* @property {number} WARN - Log warnings
|
|
108
122
|
* @property {number} ERROR - Log errors
|
|
109
123
|
* @property {number} CRITICAL - Log critical errors (least verbose)
|
|
110
|
-
* @memberOf module:engine
|
|
124
|
+
* @memberOf module:lib/engine/constants
|
|
111
125
|
*/
|
|
112
126
|
var LoggerLevels;
|
|
113
127
|
(function (LoggerLevels) {
|
|
@@ -120,15 +134,16 @@ var LoggerLevels;
|
|
|
120
134
|
})(LoggerLevels || (LoggerLevels = {}));
|
|
121
135
|
;
|
|
122
136
|
/**
|
|
123
|
-
* @description Route direction constants
|
|
124
|
-
* @summary
|
|
125
|
-
* 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.
|
|
126
141
|
* @enum {string}
|
|
127
142
|
* @readonly
|
|
128
143
|
* @property {string} BACK - Navigate back to the previous page
|
|
129
144
|
* @property {string} FORWARD - Navigate forward to the next page
|
|
130
145
|
* @property {string} ROOT - Navigate to the root/home page
|
|
131
|
-
* @memberOf module:engine
|
|
146
|
+
* @memberOf module:lib/engine/constants
|
|
132
147
|
*/
|
|
133
148
|
var RouteDirections;
|
|
134
149
|
(function (RouteDirections) {
|
|
@@ -137,15 +152,18 @@ var RouteDirections;
|
|
|
137
152
|
RouteDirections["ROOT"] = "root";
|
|
138
153
|
})(RouteDirections || (RouteDirections = {}));
|
|
139
154
|
/**
|
|
140
|
-
* @description Component tag name constants
|
|
141
|
-
* @summary
|
|
142
|
-
* 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.
|
|
143
159
|
* @enum {string}
|
|
144
160
|
* @readonly
|
|
145
161
|
* @property {string} LIST_ITEM - Tag name for list item component
|
|
146
162
|
* @property {string} LIST_INFINITE - Tag name for infinite scrolling list component
|
|
147
163
|
* @property {string} LIST_PAGINATED - Tag name for paginated list component
|
|
148
|
-
* @
|
|
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
|
|
149
167
|
*/
|
|
150
168
|
var ComponentsTagNames;
|
|
151
169
|
(function (ComponentsTagNames) {
|
|
@@ -156,13 +174,16 @@ var ComponentsTagNames;
|
|
|
156
174
|
ComponentsTagNames["LAYOUT_COMPONENT"] = "ngx-decaf-layout";
|
|
157
175
|
})(ComponentsTagNames || (ComponentsTagNames = {}));
|
|
158
176
|
/**
|
|
159
|
-
* @description Base component property name constants
|
|
160
|
-
* @summary
|
|
161
|
-
* 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.
|
|
162
182
|
* @enum {string}
|
|
163
183
|
* @readonly
|
|
164
184
|
* @property {string} MODEL - Property name for the component's data model
|
|
165
185
|
* @property {string} LOCALE - Property name for localization settings
|
|
186
|
+
* @property {string} LOCALE_ROOT - Property name for the locale root identifier
|
|
166
187
|
* @property {string} PK - Property name for primary key
|
|
167
188
|
* @property {string} ITEMS - Property name for collection items
|
|
168
189
|
* @property {string} ROUTE - Property name for routing information
|
|
@@ -171,7 +192,10 @@ var ComponentsTagNames;
|
|
|
171
192
|
* @property {string} TRANSLATABLE - Property name for translation flag
|
|
172
193
|
* @property {string} MAPPER - Property name for property mapper
|
|
173
194
|
* @property {string} INITIALIZED - Property name for initialization state
|
|
174
|
-
* @
|
|
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
|
|
175
199
|
*/
|
|
176
200
|
var BaseComponentProps;
|
|
177
201
|
(function (BaseComponentProps) {
|
|
@@ -190,14 +214,48 @@ var BaseComponentProps;
|
|
|
190
214
|
BaseComponentProps["PARENT_COMPONENT"] = "parentComponent";
|
|
191
215
|
BaseComponentProps["FORM_GROUP_COMPONENT_PROPS"] = "componentProps";
|
|
192
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
|
+
*/
|
|
193
227
|
var ListComponentsTypes;
|
|
194
228
|
(function (ListComponentsTypes) {
|
|
195
229
|
ListComponentsTypes["INFINITE"] = "infinite";
|
|
196
230
|
ListComponentsTypes["PAGINATED"] = "paginated";
|
|
197
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
|
+
*/
|
|
198
242
|
const CssClasses = {
|
|
199
243
|
BUTTONS_CONTAINER: 'buttons-container',
|
|
200
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
|
+
*/
|
|
201
259
|
const DefaultFormReactiveOptions = {
|
|
202
260
|
buttons: {
|
|
203
261
|
submit: {
|
|
@@ -208,6 +266,30 @@ const DefaultFormReactiveOptions = {
|
|
|
208
266
|
},
|
|
209
267
|
},
|
|
210
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
|
+
};
|
|
211
293
|
|
|
212
294
|
/**
|
|
213
295
|
* @module module:lib/engine/ValidatorFactory
|
|
@@ -706,11 +788,17 @@ function generateRandomValue(length = 8, onlyNumbers = false) {
|
|
|
706
788
|
return result;
|
|
707
789
|
}
|
|
708
790
|
/**
|
|
709
|
-
* 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.
|
|
710
796
|
*
|
|
711
|
-
* @
|
|
712
|
-
* @
|
|
713
|
-
*
|
|
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
|
|
714
802
|
*/
|
|
715
803
|
function stringToBoolean(prop) {
|
|
716
804
|
if (typeof prop === 'string')
|
|
@@ -718,10 +806,18 @@ function stringToBoolean(prop) {
|
|
|
718
806
|
return prop;
|
|
719
807
|
}
|
|
720
808
|
/**
|
|
721
|
-
* 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
|
|
722
818
|
*
|
|
723
|
-
* @
|
|
724
|
-
* @
|
|
819
|
+
* @function isValidDate
|
|
820
|
+
* @memberOf module:lib/helpers/utils
|
|
725
821
|
*/
|
|
726
822
|
function isValidDate(date) {
|
|
727
823
|
try {
|
|
@@ -741,12 +837,21 @@ function isValidDate(date) {
|
|
|
741
837
|
}
|
|
742
838
|
}
|
|
743
839
|
/**
|
|
744
|
-
* 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.
|
|
745
847
|
*
|
|
746
|
-
* @param {
|
|
848
|
+
* @param {string | Date | number} date - The date to format. Can be a Date object, a timestamp number, or a date string
|
|
747
849
|
* @param {string} [locale] - The locale to use for formatting. If not provided, the system's locale will be used
|
|
748
|
-
* @
|
|
749
|
-
*
|
|
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
|
|
750
855
|
*/
|
|
751
856
|
function formatDate(date, locale) {
|
|
752
857
|
if (!locale)
|
|
@@ -763,12 +868,21 @@ function formatDate(date, locale) {
|
|
|
763
868
|
return r;
|
|
764
869
|
}
|
|
765
870
|
/**
|
|
766
|
-
* 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
|
|
767
883
|
*
|
|
768
|
-
* @
|
|
769
|
-
*
|
|
770
|
-
* @return {(Date | null)} A valid Date object if parsing is successful, or null if the date is invalid
|
|
771
|
-
* or doesn't match the expected format
|
|
884
|
+
* @function parseToValidDate
|
|
885
|
+
* @memberOf module:lib/helpers/utils
|
|
772
886
|
*/
|
|
773
887
|
function parseToValidDate(date) {
|
|
774
888
|
if (isValidDate(date))
|
|
@@ -786,13 +900,22 @@ function parseToValidDate(date) {
|
|
|
786
900
|
return date;
|
|
787
901
|
}
|
|
788
902
|
/**
|
|
789
|
-
* 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.
|
|
790
910
|
*
|
|
791
|
-
* @param {KeyValue} item - The source object to be mapped
|
|
911
|
+
* @param {KeyValue} item - The source object to be mapped
|
|
792
912
|
* @param {KeyValue} mapper - An object that defines the mapping rules. Keys represent the new property names,
|
|
793
|
-
* and values represent the path to the corresponding values in the source object
|
|
794
|
-
* @param {KeyValue} [props] - Optional additional properties to be included in the mapped object
|
|
795
|
-
* @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
|
|
796
919
|
*/
|
|
797
920
|
function itemMapper(item, mapper, props) {
|
|
798
921
|
return Object.entries(mapper).reduce((accum, [key, value]) => {
|
|
@@ -819,15 +942,23 @@ function itemMapper(item, mapper, props) {
|
|
|
819
942
|
}, {});
|
|
820
943
|
}
|
|
821
944
|
/**
|
|
822
|
-
* 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.
|
|
823
952
|
*
|
|
824
|
-
* @template T - The type of the resulting mapped items
|
|
825
|
-
* @param {
|
|
826
|
-
* @param {KeyValue} mapper - An object that defines the mapping rules
|
|
827
|
-
* @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
|
|
828
959
|
*
|
|
829
|
-
* @
|
|
830
|
-
*
|
|
960
|
+
* @function dataMapper
|
|
961
|
+
* @memberOf module:lib/helpers/utils
|
|
831
962
|
*/
|
|
832
963
|
function dataMapper(data, mapper, props) {
|
|
833
964
|
if (!data || !data.length)
|
|
@@ -906,13 +1037,11 @@ async function isDarkMode() {
|
|
|
906
1037
|
*/
|
|
907
1038
|
|
|
908
1039
|
/**
|
|
909
|
-
* @module
|
|
1040
|
+
* @module lib/engine/NgxDecafFormService
|
|
910
1041
|
* @description Utilities to create and manage Angular forms in Decaf components.
|
|
911
1042
|
* @summary The NgxDecafFormService exposes helpers to build FormGroup/FormArray instances
|
|
912
1043
|
* from component metadata or UI model definitions, register forms in a registry,
|
|
913
1044
|
* validate and extract form data, and create controls with appropriate validators.
|
|
914
|
-
*
|
|
915
|
-
* @link {@link NgxDecafFormService}
|
|
916
1045
|
*/
|
|
917
1046
|
/**
|
|
918
1047
|
* @description Service for managing Angular forms and form controls.
|
|
@@ -935,7 +1064,6 @@ async function isDarkMode() {
|
|
|
935
1064
|
*
|
|
936
1065
|
* // Getting form data
|
|
937
1066
|
* const formData = NgxDecafFormService.getFormData(form);
|
|
938
|
-
*
|
|
939
1067
|
* @mermaid
|
|
940
1068
|
* sequenceDiagram
|
|
941
1069
|
* participant C as Component
|
|
@@ -957,46 +1085,42 @@ class NgxDecafFormService {
|
|
|
957
1085
|
* @description WeakMap that stores control properties for form controls.
|
|
958
1086
|
* @summary A WeakMap that associates AbstractControl instances with their corresponding FieldProperties.
|
|
959
1087
|
* This allows the service to track metadata for form controls without creating memory leaks.
|
|
960
|
-
*
|
|
961
1088
|
* @type {WeakMap<AbstractControl, FieldProperties>}
|
|
962
1089
|
* @private
|
|
963
1090
|
* @static
|
|
964
|
-
* @memberOf NgxDecafFormService
|
|
965
1091
|
*/
|
|
966
1092
|
static { this.controls = new WeakMap(); }
|
|
967
1093
|
/**
|
|
968
1094
|
* @description Registry of form groups indexed by their unique identifiers.
|
|
969
1095
|
* @summary A Map that stores FormGroup instances with their unique string identifiers.
|
|
970
1096
|
* This allows global access to registered forms throughout the application.
|
|
971
|
-
*
|
|
972
1097
|
* @type {Map<string, FormGroup>}
|
|
973
1098
|
* @private
|
|
974
1099
|
* @static
|
|
975
|
-
* @memberOf NgxDecafFormService
|
|
976
1100
|
*/
|
|
977
1101
|
static { this.formRegistry = new Map(); }
|
|
978
1102
|
/**
|
|
979
1103
|
* @description Creates a new form group or form array with the specified identifier.
|
|
980
|
-
* @summary Generates a FormGroup or FormArray based on the provided
|
|
981
|
-
*
|
|
982
|
-
*
|
|
983
|
-
*
|
|
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.
|
|
984
1108
|
* @param {string} id - Unique identifier for the form
|
|
985
|
-
* @param {
|
|
1109
|
+
* @param {boolean} [formArray=false] - Whether to create a FormArray instead of a FormGroup
|
|
986
1110
|
* @param {boolean} [registry=true] - Whether to register the form in the global registry
|
|
987
|
-
* @return {FormGroup | FormArray} The created form instance
|
|
988
|
-
*
|
|
1111
|
+
* @return {FormGroup | FormArray} The created or existing form instance
|
|
989
1112
|
* @mermaid
|
|
990
1113
|
* sequenceDiagram
|
|
991
1114
|
* participant C as Component
|
|
992
1115
|
* participant NFS as NgxDecafFormService
|
|
993
1116
|
* participant FR as Form Registry
|
|
994
1117
|
* participant AF as Angular Forms
|
|
995
|
-
*
|
|
996
|
-
* C->>NFS: createForm(id, props, registry)
|
|
1118
|
+
* C->>NFS: createForm(id, formArray, registry)
|
|
997
1119
|
* NFS->>FR: Check if form exists
|
|
998
|
-
* alt Form
|
|
999
|
-
*
|
|
1120
|
+
* alt Form exists
|
|
1121
|
+
* FR-->>NFS: Return existing form
|
|
1122
|
+
* else Form doesn't exist
|
|
1123
|
+
* alt formArray is true
|
|
1000
1124
|
* NFS->>AF: new FormArray([])
|
|
1001
1125
|
* else
|
|
1002
1126
|
* NFS->>AF: new FormGroup({})
|
|
@@ -1006,9 +1130,7 @@ class NgxDecafFormService {
|
|
|
1006
1130
|
* end
|
|
1007
1131
|
* end
|
|
1008
1132
|
* NFS-->>C: Return FormGroup | FormArray
|
|
1009
|
-
*
|
|
1010
1133
|
* @static
|
|
1011
|
-
* @memberOf NgxDecafFormService
|
|
1012
1134
|
*/
|
|
1013
1135
|
static createForm(id, formArray = false, registry = true) {
|
|
1014
1136
|
const form = this.formRegistry.get(id) ?? (formArray ? new FormArray([]) : new FormGroup({}));
|
|
@@ -1021,20 +1143,26 @@ class NgxDecafFormService {
|
|
|
1021
1143
|
* @summary Registers a FormGroup or FormArray with a unique identifier for global access throughout
|
|
1022
1144
|
* the application. This allows forms to be retrieved and managed centrally. Throws an error if
|
|
1023
1145
|
* the identifier is already in use to prevent conflicts.
|
|
1024
|
-
*
|
|
1025
1146
|
* @param {string} formId - The unique identifier for the form
|
|
1026
1147
|
* @param {FormParent} formGroup - The FormGroup or FormArray to be registered
|
|
1027
1148
|
* @return {void}
|
|
1028
1149
|
* @throws {Error} If a FormGroup with the given id is already registered
|
|
1029
|
-
*
|
|
1030
1150
|
* @static
|
|
1031
|
-
* @memberOf NgxDecafFormService
|
|
1032
1151
|
*/
|
|
1033
1152
|
static addRegistry(formId, formGroup) {
|
|
1034
1153
|
if (this.formRegistry.has(formId))
|
|
1035
1154
|
throw new Error(`A FormGroup with id '${formId}' is already registered.`);
|
|
1036
1155
|
this.formRegistry.set(formId, formGroup);
|
|
1037
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
|
+
*/
|
|
1038
1166
|
static getOnRegistry(id) {
|
|
1039
1167
|
return this.formRegistry.get(id);
|
|
1040
1168
|
}
|
|
@@ -1043,12 +1171,9 @@ class NgxDecafFormService {
|
|
|
1043
1171
|
* @summary Deletes a FormGroup or FormArray from the registry using its unique identifier.
|
|
1044
1172
|
* This cleans up the registry and allows the identifier to be reused. The form itself
|
|
1045
1173
|
* is not destroyed, only removed from the central registry.
|
|
1046
|
-
*
|
|
1047
1174
|
* @param {string} formId - The unique identifier of the form to be removed
|
|
1048
1175
|
* @return {void}
|
|
1049
|
-
*
|
|
1050
1176
|
* @static
|
|
1051
|
-
* @memberOf NgxDecafFormService
|
|
1052
1177
|
*/
|
|
1053
1178
|
static removeRegistry(formId) {
|
|
1054
1179
|
this.formRegistry.delete(formId);
|
|
@@ -1058,20 +1183,17 @@ class NgxDecafFormService {
|
|
|
1058
1183
|
* @summary Traverses the form group structure to find the parent group and control name for a given path.
|
|
1059
1184
|
* Handles complex nested structures including arrays and sub-groups. Creates missing intermediate
|
|
1060
1185
|
* groups as needed and properly configures FormArray controls for multiple value scenarios.
|
|
1061
|
-
*
|
|
1062
1186
|
* @param {FormGroup} formGroup - The root FormGroup to traverse
|
|
1063
1187
|
* @param {string} path - The dot-separated path to the control (e.g., 'user.address.street')
|
|
1064
1188
|
* @param {IComponentInput} componentProps - Properties defining the component configuration
|
|
1065
1189
|
* @param {KeyValue} parentProps - Properties from the parent component for context
|
|
1066
1190
|
* @return {FormParentGroup} A tuple containing the parent FormGroup and the control name
|
|
1067
|
-
*
|
|
1068
1191
|
* @private
|
|
1069
1192
|
* @mermaid
|
|
1070
1193
|
* sequenceDiagram
|
|
1071
1194
|
* participant NFS as NgxDecafFormService
|
|
1072
1195
|
* participant FG as FormGroup
|
|
1073
1196
|
* participant FA as FormArray
|
|
1074
|
-
*
|
|
1075
1197
|
* NFS->>NFS: Split path into parts
|
|
1076
1198
|
* loop For each path part
|
|
1077
1199
|
* alt Control doesn't exist
|
|
@@ -1085,9 +1207,7 @@ class NgxDecafFormService {
|
|
|
1085
1207
|
* NFS->>NFS: Navigate to next level
|
|
1086
1208
|
* end
|
|
1087
1209
|
* NFS-->>NFS: Return [parentGroup, controlName]
|
|
1088
|
-
*
|
|
1089
1210
|
* @static
|
|
1090
|
-
* @memberOf NgxDecafFormService
|
|
1091
1211
|
*/
|
|
1092
1212
|
static resolveParentGroup(formGroup, path, componentProps, parentProps) {
|
|
1093
1213
|
const isMultiple = parentProps?.multiple || parentProps?.type === Array.name || false;
|
|
@@ -1134,14 +1254,11 @@ class NgxDecafFormService {
|
|
|
1134
1254
|
* @description Retrieves component properties from a FormGroup or FormArray.
|
|
1135
1255
|
* @summary Extracts component properties stored in the form group metadata. If a FormGroup is provided
|
|
1136
1256
|
* and groupArrayName is specified, it will look for the FormArray within the form structure.
|
|
1137
|
-
*
|
|
1138
1257
|
* @param {FormGroup | FormArray} formGroup - The form group or form array to extract properties from
|
|
1139
1258
|
* @param {string} [key] - Optional key to retrieve a specific property
|
|
1140
1259
|
* @param {string} [groupArrayName] - Optional name of the group array if formGroup is not a FormArray
|
|
1141
1260
|
* @return {Partial<FieldProperties>} The component properties or a specific property if key is provided
|
|
1142
|
-
*
|
|
1143
1261
|
* @static
|
|
1144
|
-
* @memberOf NgxDecafFormService
|
|
1145
1262
|
*/
|
|
1146
1263
|
static getComponentPropsFromGroupArray(formGroup, key, groupArrayName) {
|
|
1147
1264
|
if (!(formGroup instanceof FormArray) && typeof groupArrayName === Primitives.STRING)
|
|
@@ -1153,14 +1270,12 @@ class NgxDecafFormService {
|
|
|
1153
1270
|
* @description Adds a new group to a parent FormArray.
|
|
1154
1271
|
* @summary Creates and adds a new FormGroup to the specified parent FormArray based on the
|
|
1155
1272
|
* component properties stored in the parent's metadata. This is used for dynamic form arrays
|
|
1156
|
-
* where new groups need to be added at runtime.
|
|
1157
|
-
*
|
|
1158
|
-
* @param {FormParent} parentForm - The
|
|
1159
|
-
* @param {number} index - The index position
|
|
1160
|
-
* @return {
|
|
1161
|
-
*
|
|
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
|
|
1162
1278
|
* @static
|
|
1163
|
-
* @memberOf NgxDecafFormService
|
|
1164
1279
|
*/
|
|
1165
1280
|
static addGroupToParent(parentForm, index) {
|
|
1166
1281
|
if (parentForm instanceof FormGroup)
|
|
@@ -1173,14 +1288,11 @@ class NgxDecafFormService {
|
|
|
1173
1288
|
* @description Retrieves a FormGroup from a parent FormArray at the specified index.
|
|
1174
1289
|
* @summary Gets a FormGroup from the specified parent FormArray. If the group doesn't exist
|
|
1175
1290
|
* at the given index, it will create a new one using addGroupToParent.
|
|
1176
|
-
*
|
|
1177
|
-
* @param {FormGroup} formGroup - The root form group containing the parent FormArray
|
|
1291
|
+
* @param {FormParent} formGroup - The root form group containing the parent FormArray
|
|
1178
1292
|
* @param {string} parentName - The name of the parent FormArray to retrieve the group from
|
|
1179
1293
|
* @param {number} [index=1] - The index of the group to retrieve
|
|
1180
1294
|
* @return {FormGroup} The FormGroup at the specified index
|
|
1181
|
-
*
|
|
1182
1295
|
* @static
|
|
1183
|
-
* @memberOf NgxDecafFormService
|
|
1184
1296
|
*/
|
|
1185
1297
|
static getGroupFromParent(formGroup, parentName, index = 1) {
|
|
1186
1298
|
const childGroup = (formGroup.get(parentName) || formGroup).at(index);
|
|
@@ -1188,6 +1300,17 @@ class NgxDecafFormService {
|
|
|
1188
1300
|
return childGroup;
|
|
1189
1301
|
return this.addGroupToParent(formGroup, index).at(index);
|
|
1190
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
|
+
*/
|
|
1191
1314
|
static cloneFormControl(control) {
|
|
1192
1315
|
const syncValidators = (control.validator ? [control.validator] : []).filter(fn => {
|
|
1193
1316
|
// if(lastIndex > 0)
|
|
@@ -1225,14 +1348,13 @@ class NgxDecafFormService {
|
|
|
1225
1348
|
* @description Checks if a value is unique within a FormArray group.
|
|
1226
1349
|
* @summary Validates that the primary key value in a FormGroup is unique among all groups
|
|
1227
1350
|
* in the parent FormArray. The uniqueness check behavior differs based on the operation type.
|
|
1228
|
-
*
|
|
1351
|
+
* For both CREATE and UPDATE operations, it checks that no other group in the array has the same
|
|
1352
|
+
* primary key value.
|
|
1229
1353
|
* @param {FormGroup} formGroup - The FormGroup to check for uniqueness
|
|
1230
|
-
* @param {number} index - The index of the current group within the FormArray
|
|
1231
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
|
|
1232
1356
|
* @return {boolean} True if the value is unique, false otherwise
|
|
1233
|
-
*
|
|
1234
1357
|
* @static
|
|
1235
|
-
* @memberOf NgxDecafFormService
|
|
1236
1358
|
*/
|
|
1237
1359
|
static isUniqueOnGroup(formGroup, operation = OperationKeys.CREATE, index) {
|
|
1238
1360
|
const formArray = formGroup.parent;
|
|
@@ -1258,12 +1380,9 @@ class NgxDecafFormService {
|
|
|
1258
1380
|
* @description Enables all controls within a FormGroup or FormArray.
|
|
1259
1381
|
* @summary Recursively enables all form controls within the provided FormGroup or FormArray.
|
|
1260
1382
|
* This is useful for making all controls interactive after they have been disabled.
|
|
1261
|
-
*
|
|
1262
1383
|
* @param {FormArray | FormGroup} formGroup - The FormGroup or FormArray to enable all controls for
|
|
1263
1384
|
* @return {void}
|
|
1264
|
-
*
|
|
1265
1385
|
* @static
|
|
1266
|
-
* @memberOf NgxDecafFormService
|
|
1267
1386
|
*/
|
|
1268
1387
|
static enableAllGroupControls(formGroup) {
|
|
1269
1388
|
Object.keys(formGroup.controls).forEach(key => {
|
|
@@ -1282,17 +1401,15 @@ class NgxDecafFormService {
|
|
|
1282
1401
|
* @description Adds a form control to a form group based on component properties.
|
|
1283
1402
|
* @summary Creates and configures a FormControl within the specified FormGroup using the provided
|
|
1284
1403
|
* component properties. Handles nested paths, multiple controls (FormArrays), and control registration.
|
|
1285
|
-
* This method supports complex form structures with nested groups and arrays.
|
|
1286
|
-
*
|
|
1287
|
-
* @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
|
|
1288
1407
|
* @param {IComponentInput} componentProps - The component properties defining the control configuration
|
|
1289
|
-
* @param {
|
|
1408
|
+
* @param {Partial<IComponentInput>} [parentProps={}] - Properties from the parent component for context
|
|
1290
1409
|
* @param {number} [index=0] - The index for multiple controls in FormArrays
|
|
1291
|
-
* @return {
|
|
1292
|
-
*
|
|
1410
|
+
* @return {FormParent} The updated form parent (FormGroup or FormArray)
|
|
1293
1411
|
* @private
|
|
1294
1412
|
* @static
|
|
1295
|
-
* @memberOf NgxDecafFormService
|
|
1296
1413
|
*/
|
|
1297
1414
|
static addFormControl(formGroup, componentProps, parentProps = {}, index = 0) {
|
|
1298
1415
|
const isMultiple = parentProps?.['multiple'] || parentProps?.['type'] === 'Array' || false;
|
|
@@ -1328,18 +1445,15 @@ class NgxDecafFormService {
|
|
|
1328
1445
|
* @summary Finds and returns an AbstractControl from a registered form using the form id and optional path.
|
|
1329
1446
|
* This method provides centralized access to form controls across the application by leveraging
|
|
1330
1447
|
* the form registry system.
|
|
1331
|
-
*
|
|
1332
1448
|
* @param {string} formId - The unique identifier of the form in the registry
|
|
1333
1449
|
* @param {string} [path] - The optional dot-separated path to a specific control within the form
|
|
1334
1450
|
* @return {AbstractControl} The requested AbstractControl (FormGroup, FormArray, or FormControl)
|
|
1335
1451
|
* @throws {Error} If the form is not found in the registry or the control is not found in the form
|
|
1336
|
-
*
|
|
1337
1452
|
* @mermaid
|
|
1338
1453
|
* sequenceDiagram
|
|
1339
1454
|
* participant C as Component
|
|
1340
1455
|
* participant NFS as NgxDecafFormService
|
|
1341
1456
|
* participant FR as Form Registry
|
|
1342
|
-
*
|
|
1343
1457
|
* C->>NFS: getControlFromForm(formId, path?)
|
|
1344
1458
|
* NFS->>FR: Get form by formId
|
|
1345
1459
|
* alt Form not found
|
|
@@ -1358,9 +1472,7 @@ class NgxDecafFormService {
|
|
|
1358
1472
|
* NFS-->>C: Return form
|
|
1359
1473
|
* end
|
|
1360
1474
|
* end
|
|
1361
|
-
*
|
|
1362
1475
|
* @static
|
|
1363
|
-
* @memberOf NgxDecafFormService
|
|
1364
1476
|
*/
|
|
1365
1477
|
static getControlFromForm(formId, path) {
|
|
1366
1478
|
const form = this.formRegistry.get(formId);
|
|
@@ -1378,18 +1490,15 @@ class NgxDecafFormService {
|
|
|
1378
1490
|
* @summary Generates a FormGroup from an array of UIModelMetadata objects, extracting component
|
|
1379
1491
|
* properties and creating appropriate form controls. This method is specifically designed to work
|
|
1380
1492
|
* with the UI decorator system and provides automatic form generation from metadata.
|
|
1381
|
-
*
|
|
1382
1493
|
* @param {string} id - Unique identifier for the form
|
|
1383
1494
|
* @param {boolean} [registry=false] - Whether to register the created form in the global registry
|
|
1384
1495
|
* @param {UIModelMetadata[]} [children] - Array of UI model metadata objects to create controls from
|
|
1385
1496
|
* @return {FormGroup} The created FormGroup with controls for each child metadata
|
|
1386
|
-
*
|
|
1387
1497
|
* @mermaid
|
|
1388
1498
|
* sequenceDiagram
|
|
1389
1499
|
* participant C as Component
|
|
1390
1500
|
* participant NFS as NgxDecafFormService
|
|
1391
1501
|
* participant AF as Angular Forms
|
|
1392
|
-
*
|
|
1393
1502
|
* C->>NFS: createFormFromChildren(id, registry, children)
|
|
1394
1503
|
* NFS->>AF: new FormGroup({})
|
|
1395
1504
|
* loop For each child metadata
|
|
@@ -1400,9 +1509,7 @@ class NgxDecafFormService {
|
|
|
1400
1509
|
* NFS->>NFS: addRegistry(id, form)
|
|
1401
1510
|
* end
|
|
1402
1511
|
* NFS-->>C: Return FormGroup
|
|
1403
|
-
*
|
|
1404
1512
|
* @static
|
|
1405
|
-
* @memberOf NgxDecafFormService
|
|
1406
1513
|
*/
|
|
1407
1514
|
static createFormFromChildren(id, registry = false, children) {
|
|
1408
1515
|
const form = new FormGroup({});
|
|
@@ -1419,18 +1526,15 @@ class NgxDecafFormService {
|
|
|
1419
1526
|
* @summary Generates a FormGroup based on an array of component configurations and optionally registers it.
|
|
1420
1527
|
* This method processes component input configurations to create appropriate form controls with
|
|
1421
1528
|
* validation and initial values.
|
|
1422
|
-
*
|
|
1423
1529
|
* @param {string} id - The unique identifier for the form
|
|
1424
1530
|
* @param {IComponentConfig[]} components - An array of component configurations defining the form structure
|
|
1425
1531
|
* @param {boolean} [registry=false] - Whether to register the created form in the global registry
|
|
1426
1532
|
* @return {FormGroup} The created FormGroup with controls for each component configuration
|
|
1427
|
-
*
|
|
1428
1533
|
* @mermaid
|
|
1429
1534
|
* sequenceDiagram
|
|
1430
1535
|
* participant C as Component
|
|
1431
1536
|
* participant NFS as NgxDecafFormService
|
|
1432
1537
|
* participant AF as Angular Forms
|
|
1433
|
-
*
|
|
1434
1538
|
* C->>NFS: createFormFromComponents(id, components, registry)
|
|
1435
1539
|
* NFS->>AF: new FormGroup({})
|
|
1436
1540
|
* loop For each component config
|
|
@@ -1441,9 +1545,7 @@ class NgxDecafFormService {
|
|
|
1441
1545
|
* NFS->>NFS: addRegistry(id, form)
|
|
1442
1546
|
* end
|
|
1443
1547
|
* NFS-->>C: Return FormGroup
|
|
1444
|
-
*
|
|
1445
1548
|
* @static
|
|
1446
|
-
* @memberOf NgxDecafFormService
|
|
1447
1549
|
*/
|
|
1448
1550
|
static createFormFromComponents(id, components, registry = false) {
|
|
1449
1551
|
const form = new FormGroup({});
|
|
@@ -1458,54 +1560,51 @@ class NgxDecafFormService {
|
|
|
1458
1560
|
* @description Adds a control to a form based on component properties.
|
|
1459
1561
|
* @summary Creates and adds a form control to a form (existing or new) based on the provided component properties.
|
|
1460
1562
|
* Handles multi-page forms by managing FormArray structures and proper indexing. This method supports
|
|
1461
|
-
* complex form scenarios including nested controls and page-based form organization.
|
|
1462
|
-
*
|
|
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.
|
|
1463
1565
|
* @param {string} id - The unique identifier of the form
|
|
1464
1566
|
* @param {FieldProperties} componentProperties - The properties of the component to create the control from
|
|
1465
1567
|
* @param {FieldProperties} [parentProps] - Optional parent properties for context and configuration
|
|
1466
|
-
* @return {
|
|
1467
|
-
*
|
|
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
|
|
1468
1570
|
* @mermaid
|
|
1469
1571
|
* sequenceDiagram
|
|
1470
1572
|
* participant C as Component
|
|
1471
1573
|
* participant NFS as NgxDecafFormService
|
|
1472
1574
|
* participant F as Form
|
|
1473
|
-
*
|
|
1474
1575
|
* C->>NFS: addControlFromProps(id, componentProps, parentProps?)
|
|
1475
|
-
* NFS->>NFS: createForm(id,
|
|
1476
|
-
* alt Multi-page form (parentProps.pages >
|
|
1576
|
+
* NFS->>NFS: createForm(id, formArray, true)
|
|
1577
|
+
* alt Multi-page form (parentProps.pages > 0)
|
|
1477
1578
|
* NFS->>NFS: Calculate page index
|
|
1478
|
-
*
|
|
1579
|
+
* alt Group doesn't exist at index
|
|
1580
|
+
* NFS->>F: Create new FormGroup at index
|
|
1581
|
+
* end
|
|
1479
1582
|
* NFS->>NFS: Set form to page FormGroup
|
|
1480
1583
|
* end
|
|
1481
1584
|
* alt componentProperties has path
|
|
1482
1585
|
* NFS->>NFS: addFormControl(form, componentProperties, parentProps)
|
|
1483
1586
|
* end
|
|
1484
1587
|
* NFS-->>C: Return form/control
|
|
1485
|
-
*
|
|
1486
1588
|
* @static
|
|
1487
|
-
* @memberOf NgxDecafFormService
|
|
1488
1589
|
*/
|
|
1489
1590
|
static addControlFromProps(id, componentProperties, parentProps) {
|
|
1490
1591
|
const formArray = (componentProperties?.pages && componentProperties?.pages >= 1 || componentProperties.multiple === true);
|
|
1491
1592
|
let form = this.createForm(id, formArray, true);
|
|
1492
|
-
const formLength = form.length;
|
|
1493
1593
|
if (parentProps?.pages && parentProps?.pages > 0) {
|
|
1494
|
-
|
|
1594
|
+
const index = componentProperties.page || parentProps.page;
|
|
1495
1595
|
if (!(typeof index === 'number') || index === 0)
|
|
1496
1596
|
throw Error(`Property 'page' is required and greather than 0 on ${componentProperties.name}`);
|
|
1497
|
-
if
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
}
|
|
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
|
+
// }
|
|
1509
1608
|
let group = form.controls[index - 1];
|
|
1510
1609
|
if (!group) {
|
|
1511
1610
|
group = new FormGroup({});
|
|
@@ -1522,17 +1621,14 @@ class NgxDecafFormService {
|
|
|
1522
1621
|
* @summary Extracts and processes the data from a FormGroup, handling different input types and nested form groups.
|
|
1523
1622
|
* Performs type conversion for various HTML5 input types, validates nested controls, and manages
|
|
1524
1623
|
* multiple control scenarios. Automatically enables all group controls after data extraction.
|
|
1525
|
-
*
|
|
1526
1624
|
* @param {FormGroup} formGroup - The FormGroup to extract data from
|
|
1527
1625
|
* @return {Record<string, unknown>} An object containing the processed form data with proper type conversions
|
|
1528
|
-
*
|
|
1529
1626
|
* @mermaid
|
|
1530
1627
|
* sequenceDiagram
|
|
1531
1628
|
* participant C as Component
|
|
1532
1629
|
* participant NFS as NgxDecafFormService
|
|
1533
1630
|
* participant FG as FormGroup
|
|
1534
1631
|
* participant FC as FormControl
|
|
1535
|
-
*
|
|
1536
1632
|
* C->>NFS: getFormData(formGroup)
|
|
1537
1633
|
* loop For each control in formGroup
|
|
1538
1634
|
* alt Control is not FormControl
|
|
@@ -1556,9 +1652,7 @@ class NgxDecafFormService {
|
|
|
1556
1652
|
* end
|
|
1557
1653
|
* NFS->>NFS: enableAllGroupControls(formGroup)
|
|
1558
1654
|
* NFS-->>C: Return processed data object
|
|
1559
|
-
*
|
|
1560
1655
|
* @static
|
|
1561
|
-
* @memberOf NgxDecafFormService
|
|
1562
1656
|
*/
|
|
1563
1657
|
static getFormData(formGroup) {
|
|
1564
1658
|
const data = {};
|
|
@@ -1609,13 +1703,11 @@ class NgxDecafFormService {
|
|
|
1609
1703
|
* @summary Recursively validates all fields in a form control or form group, marking them as touched and dirty.
|
|
1610
1704
|
* Performs comprehensive validation including uniqueness checks for primary keys in FormArray scenarios.
|
|
1611
1705
|
* This method ensures all validation rules are applied and form state is properly updated.
|
|
1612
|
-
*
|
|
1613
1706
|
* @param {AbstractControl} control - The control or form group to validate
|
|
1614
1707
|
* @param {string} [pk] - Optional primary key field name for uniqueness validation
|
|
1615
1708
|
* @param {string} [path] - The path to the control within the form for error reporting
|
|
1616
1709
|
* @return {boolean} True if all fields are valid, false otherwise
|
|
1617
1710
|
* @throws {Error} If no control is found at the specified path or if the control type is unknown
|
|
1618
|
-
*
|
|
1619
1711
|
* @mermaid
|
|
1620
1712
|
* sequenceDiagram
|
|
1621
1713
|
* participant C as Component
|
|
@@ -1623,7 +1715,6 @@ class NgxDecafFormService {
|
|
|
1623
1715
|
* participant FC as FormControl
|
|
1624
1716
|
* participant FG as FormGroup
|
|
1625
1717
|
* participant FA as FormArray
|
|
1626
|
-
*
|
|
1627
1718
|
* C->>NFS: validateFields(control, pk?, path?)
|
|
1628
1719
|
* alt Control is FormControl
|
|
1629
1720
|
* NFS->>FC: markAsTouched()
|
|
@@ -1649,9 +1740,7 @@ class NgxDecafFormService {
|
|
|
1649
1740
|
* else Unknown control type
|
|
1650
1741
|
* NFS-->>C: Throw Error
|
|
1651
1742
|
* end
|
|
1652
|
-
*
|
|
1653
1743
|
* @static
|
|
1654
|
-
* @memberOf NgxDecafFormService
|
|
1655
1744
|
*/
|
|
1656
1745
|
static validateFields(control, pk, path) {
|
|
1657
1746
|
control = path ? control.get(path) : control;
|
|
@@ -1702,8 +1791,12 @@ class NgxDecafFormService {
|
|
|
1702
1791
|
/**
|
|
1703
1792
|
* @description Generates validators from component properties.
|
|
1704
1793
|
* @summary Creates an array of ValidatorFn based on the supported validation keys in the component properties.
|
|
1705
|
-
*
|
|
1706
|
-
*
|
|
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
|
|
1707
1800
|
*/
|
|
1708
1801
|
static validatorsFromProps(props) {
|
|
1709
1802
|
const supportedValidationKeys = Validation.keys();
|
|
@@ -1718,18 +1811,15 @@ class NgxDecafFormService {
|
|
|
1718
1811
|
* @summary Generates a FormControl with validators and initial configuration based on the provided
|
|
1719
1812
|
* component properties. Handles different input types, sets initial values, and configures
|
|
1720
1813
|
* validation rules and update modes.
|
|
1721
|
-
*
|
|
1722
1814
|
* @param {FieldProperties} props - The component properties defining the control configuration
|
|
1723
1815
|
* @param {FieldUpdateMode} [updateMode='change'] - The update mode for the control ('change', 'blur', 'submit')
|
|
1724
1816
|
* @return {FormControl} The created FormControl with proper configuration and validators
|
|
1725
|
-
*
|
|
1726
1817
|
* @mermaid
|
|
1727
1818
|
* sequenceDiagram
|
|
1728
1819
|
* participant C as Component
|
|
1729
1820
|
* participant NFS as NgxDecafFormService
|
|
1730
1821
|
* participant VF as ValidatorFactory
|
|
1731
1822
|
* participant AF as Angular Forms
|
|
1732
|
-
*
|
|
1733
1823
|
* C->>NFS: fromProps(props, updateMode?)
|
|
1734
1824
|
* NFS->>NFS: validatorsFromProps(props)
|
|
1735
1825
|
* NFS->>VF: Create validators from props
|
|
@@ -1744,9 +1834,7 @@ class NgxDecafFormService {
|
|
|
1744
1834
|
* NFS->>AF: new FormControl(config)
|
|
1745
1835
|
* AF-->>NFS: Return FormControl
|
|
1746
1836
|
* NFS-->>C: Return configured FormControl
|
|
1747
|
-
*
|
|
1748
1837
|
* @static
|
|
1749
|
-
* @memberOf NgxDecafFormService
|
|
1750
1838
|
*/
|
|
1751
1839
|
static fromProps(props, updateMode = 'change') {
|
|
1752
1840
|
const validators = this.validatorsFromProps(props);
|
|
@@ -1770,12 +1858,9 @@ class NgxDecafFormService {
|
|
|
1770
1858
|
* @summary Gets the FieldProperties associated with a form control from the internal WeakMap.
|
|
1771
1859
|
* This method provides access to the original component properties that were used to create
|
|
1772
1860
|
* the control, enabling validation, rendering, and behavior configuration.
|
|
1773
|
-
*
|
|
1774
1861
|
* @param {FormControl | FormArray | FormGroup} control - The form control to get properties for
|
|
1775
1862
|
* @return {FieldProperties} The properties associated with the control, or empty object if not found
|
|
1776
|
-
*
|
|
1777
1863
|
* @static
|
|
1778
|
-
* @memberOf NgxDecafFormService
|
|
1779
1864
|
*/
|
|
1780
1865
|
static getPropsFromControl(control) {
|
|
1781
1866
|
return this.controls.get(control) || {};
|
|
@@ -1785,18 +1870,15 @@ class NgxDecafFormService {
|
|
|
1785
1870
|
* @summary Traverses up the DOM tree to find the nearest parent element with the specified tag name.
|
|
1786
1871
|
* This is useful for finding container elements or specific parent components in the DOM hierarchy.
|
|
1787
1872
|
* The search is case-insensitive for tag name matching.
|
|
1788
|
-
*
|
|
1789
1873
|
* @param {HTMLElement} el - The starting element to traverse from
|
|
1790
1874
|
* @param {string} tag - The tag name to search for (case-insensitive)
|
|
1791
1875
|
* @return {HTMLElement} The found parent element with the specified tag
|
|
1792
1876
|
* @throws {Error} If no parent with the specified tag is found in the DOM tree
|
|
1793
|
-
*
|
|
1794
1877
|
* @mermaid
|
|
1795
1878
|
* sequenceDiagram
|
|
1796
1879
|
* participant C as Component
|
|
1797
1880
|
* participant NFS as NgxDecafFormService
|
|
1798
1881
|
* participant DOM as DOM Tree
|
|
1799
|
-
*
|
|
1800
1882
|
* C->>NFS: getParentEl(element, tagName)
|
|
1801
1883
|
* loop Traverse up DOM tree
|
|
1802
1884
|
* NFS->>DOM: Get parentElement
|
|
@@ -1807,9 +1889,7 @@ class NgxDecafFormService {
|
|
|
1807
1889
|
* NFS-->>C: Throw Error
|
|
1808
1890
|
* end
|
|
1809
1891
|
* end
|
|
1810
|
-
*
|
|
1811
1892
|
* @static
|
|
1812
|
-
* @memberOf NgxDecafFormService
|
|
1813
1893
|
*/
|
|
1814
1894
|
static getParentEl(el, tag) {
|
|
1815
1895
|
let parent;
|
|
@@ -1826,30 +1906,35 @@ class NgxDecafFormService {
|
|
|
1826
1906
|
* @summary Associates a form control with its component properties for later retrieval.
|
|
1827
1907
|
* This enables the service to maintain metadata about controls without creating memory leaks,
|
|
1828
1908
|
* as WeakMap automatically cleans up references when controls are garbage collected.
|
|
1829
|
-
*
|
|
1830
1909
|
* @param {AbstractControl} control - The control to register (FormControl, FormGroup, or FormArray)
|
|
1831
1910
|
* @param {FieldProperties} props - The properties to associate with the control
|
|
1832
1911
|
* @return {void}
|
|
1833
|
-
*
|
|
1834
1912
|
* @static
|
|
1835
|
-
* @memberOf NgxDecafFormService
|
|
1836
1913
|
*/
|
|
1837
1914
|
static register(control, props) {
|
|
1838
1915
|
this.controls.set(control, props);
|
|
1839
1916
|
}
|
|
1840
1917
|
/**
|
|
1841
|
-
* @description Unregisters a control.
|
|
1918
|
+
* @description Unregisters a control from the internal WeakMap.
|
|
1842
1919
|
* @summary Removes a control and its associated properties from the internal WeakMap.
|
|
1843
|
-
*
|
|
1844
|
-
*
|
|
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
|
|
1845
1925
|
*/
|
|
1846
1926
|
static unregister(control) {
|
|
1847
1927
|
return this.controls.delete(control);
|
|
1848
1928
|
}
|
|
1849
1929
|
/**
|
|
1850
|
-
* @description Resets a form group.
|
|
1851
|
-
* @summary Recursively resets all controls in a form group
|
|
1852
|
-
*
|
|
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
|
|
1853
1938
|
*/
|
|
1854
1939
|
static reset(formGroup) {
|
|
1855
1940
|
if (formGroup instanceof FormControl) {
|
|
@@ -1873,32 +1958,29 @@ class NgxDecafFormService {
|
|
|
1873
1958
|
}
|
|
1874
1959
|
|
|
1875
1960
|
/**
|
|
1876
|
-
* @module
|
|
1961
|
+
* @module lib/engine/NgxRenderingEngine
|
|
1877
1962
|
* @description Angular rendering engine for Decaf model-driven UIs.
|
|
1878
1963
|
* @summary Implements NgxRenderingEngine which converts model decorator metadata
|
|
1879
1964
|
* into Angular components, manages component registration, and orchestrates
|
|
1880
1965
|
* dynamic component creation and input mapping.
|
|
1881
|
-
*
|
|
1882
1966
|
* @link {@link NgxRenderingEngine}
|
|
1883
1967
|
*/
|
|
1884
1968
|
/**
|
|
1885
|
-
* @description Angular implementation of the RenderingEngine
|
|
1886
|
-
* @summary This class extends the base RenderingEngine to provide Angular-specific rendering capabilities
|
|
1887
|
-
*
|
|
1888
|
-
*
|
|
1889
|
-
*
|
|
1890
|
-
*
|
|
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.
|
|
1891
1974
|
* @template AngularFieldDefinition - Type for Angular-specific field definitions
|
|
1892
1975
|
* @template AngularDynamicOutput - Type for Angular-specific component output
|
|
1893
|
-
*
|
|
1894
1976
|
* @class NgxRenderingEngine
|
|
1977
|
+
* @extends {RenderingEngine<AngularFieldDefinition, AngularDynamicOutput>}
|
|
1895
1978
|
* @example
|
|
1896
1979
|
* ```typescript
|
|
1897
1980
|
* const engine = NgxRenderingEngine.get();
|
|
1898
1981
|
* engine.initialize();
|
|
1899
1982
|
* const output = engine.render(myModel, {}, viewContainerRef, injector, templateRef);
|
|
1900
1983
|
* ```
|
|
1901
|
-
*
|
|
1902
1984
|
* @mermaid
|
|
1903
1985
|
* sequenceDiagram
|
|
1904
1986
|
* participant Client
|
|
@@ -1914,49 +1996,61 @@ class NgxDecafFormService {
|
|
|
1914
1996
|
* Components-->>Engine: component constructor
|
|
1915
1997
|
* Engine->>Engine: createComponent(component, inputs, metadata, vcr, injector, template)
|
|
1916
1998
|
* Engine-->>Client: return AngularDynamicOutput
|
|
1999
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
1917
2000
|
*/
|
|
1918
2001
|
class NgxRenderingEngine extends RenderingEngine {
|
|
1919
2002
|
/**
|
|
1920
|
-
* @description Current operation context for component visibility control
|
|
2003
|
+
* @description Current operation context for component visibility control.
|
|
1921
2004
|
* @summary Static property that stores the current operation being performed,
|
|
1922
2005
|
* which is used to determine component visibility through the 'hidden' property.
|
|
1923
2006
|
* Components can specify operations where they should be hidden, and this property
|
|
1924
2007
|
* provides the context for those visibility checks. The value is typically extracted
|
|
1925
2008
|
* from the global properties during the rendering process.
|
|
1926
|
-
*
|
|
1927
2009
|
* @private
|
|
1928
2010
|
* @static
|
|
1929
2011
|
* @type {string | undefined}
|
|
2012
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
1930
2013
|
*/
|
|
1931
2014
|
static { this._operation = undefined; }
|
|
1932
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
|
+
*/
|
|
1933
2027
|
static { this._parentProps = undefined; }
|
|
1934
2028
|
/**
|
|
1935
|
-
* @description Constructs a new NgxRenderingEngine instance
|
|
2029
|
+
* @description Constructs a new NgxRenderingEngine instance.
|
|
1936
2030
|
* @summary Initializes a new instance of the Angular rendering engine by calling the parent
|
|
1937
2031
|
* constructor with the 'angular' engine type identifier. This constructor sets up the base
|
|
1938
2032
|
* rendering engine functionality with Angular-specific configurations and prepares the
|
|
1939
2033
|
* instance for component registration and rendering operations.
|
|
1940
|
-
*
|
|
1941
2034
|
* @constructor
|
|
2035
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
1942
2036
|
*/
|
|
1943
2037
|
constructor() {
|
|
1944
|
-
super(
|
|
2038
|
+
super(AngularEngineKeys.FLAVOUR);
|
|
1945
2039
|
}
|
|
1946
2040
|
/**
|
|
1947
|
-
* @description Converts a field definition to an Angular component output
|
|
2041
|
+
* @description Converts a field definition to an Angular component output.
|
|
1948
2042
|
* @summary This private method takes a field definition and creates the corresponding Angular component.
|
|
1949
|
-
* It handles component instantiation, input property mapping,
|
|
1950
|
-
* 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
|
|
1951
2045
|
* child components recursively.
|
|
1952
|
-
*
|
|
1953
2046
|
* @param {FieldDefinition<AngularFieldDefinition>} fieldDef - The field definition to convert
|
|
1954
2047
|
* @param {ViewContainerRef} vcr - The view container reference for component creation
|
|
1955
2048
|
* @param {Injector} injector - The Angular injector for dependency injection
|
|
1956
2049
|
* @param {TemplateRef<any>} tpl - The template reference for content projection
|
|
1957
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
|
|
1958
2053
|
* @return {AngularDynamicOutput} The Angular component output with component reference and inputs
|
|
1959
|
-
*
|
|
1960
2054
|
* @mermaid
|
|
1961
2055
|
* sequenceDiagram
|
|
1962
2056
|
* participant Method as fromFieldDefinition
|
|
@@ -1977,6 +2071,8 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
1977
2071
|
* Method->>Method: Create component instance
|
|
1978
2072
|
* end
|
|
1979
2073
|
* Method-->>Caller: return AngularDynamicOutput
|
|
2074
|
+
* @private
|
|
2075
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
1980
2076
|
*/
|
|
1981
2077
|
fromFieldDefinition(fieldDef, vcr, injector, tpl, registryFormId = Date.now().toString(36).toUpperCase(), createComponent = true, formGroup) {
|
|
1982
2078
|
const cmp = fieldDef?.['component'] || NgxRenderingEngine.components(fieldDef.tag);
|
|
@@ -2046,11 +2142,10 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2046
2142
|
return result;
|
|
2047
2143
|
}
|
|
2048
2144
|
/**
|
|
2049
|
-
* @description Creates an Angular component instance
|
|
2145
|
+
* @description Creates an Angular component instance with inputs and template projection.
|
|
2050
2146
|
* @summary This static utility method creates an Angular component instance with the specified
|
|
2051
2147
|
* inputs and template. It uses Angular's component creation API to instantiate the component
|
|
2052
2148
|
* and then sets the input properties using the provided metadata.
|
|
2053
|
-
*
|
|
2054
2149
|
* @param {Type<unknown>} component - The component type to create
|
|
2055
2150
|
* @param {KeyValue} [inputs={}] - The input properties to set on the component
|
|
2056
2151
|
* @param {ComponentMirror<unknown>} metadata - The component metadata for input validation
|
|
@@ -2058,6 +2153,8 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2058
2153
|
* @param {Injector} injector - The Angular injector for dependency injection
|
|
2059
2154
|
* @param {Node[]} [template=[]] - The template nodes to project into the component
|
|
2060
2155
|
* @return {ComponentRef<unknown>} The created component reference
|
|
2156
|
+
* @static
|
|
2157
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2061
2158
|
*/
|
|
2062
2159
|
static createComponent(component, inputs = {}, metadata, vcr, injector, template = []) {
|
|
2063
2160
|
const componentInstance = vcr.createComponent(component, {
|
|
@@ -2068,26 +2165,29 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2068
2165
|
return componentInstance;
|
|
2069
2166
|
}
|
|
2070
2167
|
/**
|
|
2071
|
-
* @description Extracts decorator metadata from a model
|
|
2168
|
+
* @description Extracts decorator metadata from a model.
|
|
2072
2169
|
* @summary This method provides access to the field definition generated from a model's
|
|
2073
2170
|
* decorators. It's a convenience wrapper around the toFieldDefinition method that
|
|
2074
2171
|
* converts a model to a field definition based on its decorators and the provided
|
|
2075
2172
|
* global properties.
|
|
2076
|
-
*
|
|
2077
2173
|
* @param {Model} model - The model to extract decorators from
|
|
2078
2174
|
* @param {Record<string, unknown>} globalProps - Global properties to include in the field definition
|
|
2079
2175
|
* @return {FieldDefinition<AngularFieldDefinition>} The field definition generated from the model
|
|
2176
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2080
2177
|
*/
|
|
2081
2178
|
getDecorators(model, globalProps) {
|
|
2082
2179
|
return this.toFieldDefinition(model, globalProps);
|
|
2083
2180
|
}
|
|
2084
2181
|
/**
|
|
2085
|
-
* @description Destroys the current engine instance
|
|
2086
|
-
* @summary This static method clears the current instance reference,
|
|
2087
|
-
* destroying the singleton instance of the rendering engine.
|
|
2088
|
-
*
|
|
2089
|
-
*
|
|
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
|
|
2090
2188
|
* @return {Promise<void>} A promise that resolves when the instance is destroyed
|
|
2189
|
+
* @static
|
|
2190
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2091
2191
|
*/
|
|
2092
2192
|
static async destroy(formId) {
|
|
2093
2193
|
if (formId)
|
|
@@ -2096,12 +2196,11 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2096
2196
|
NgxRenderingEngine._parentProps = undefined;
|
|
2097
2197
|
}
|
|
2098
2198
|
/**
|
|
2099
|
-
* @description Renders a model into an Angular component output
|
|
2199
|
+
* @description Renders a model into an Angular component output.
|
|
2100
2200
|
* @summary This method takes a model and converts it to an Angular component output.
|
|
2101
2201
|
* It first stores a reference to the model, then converts it to a field definition
|
|
2102
2202
|
* using the base RenderingEngine's toFieldDefinition method, and finally converts
|
|
2103
2203
|
* that field definition to an Angular component output using fromFieldDefinition.
|
|
2104
|
-
*
|
|
2105
2204
|
* @template M - Type extending Model
|
|
2106
2205
|
* @param {M} model - The model to render
|
|
2107
2206
|
* @param {Record<string, unknown>} globalProps - Global properties to pass to the component
|
|
@@ -2109,7 +2208,6 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2109
2208
|
* @param {Injector} injector - The Angular injector for dependency injection
|
|
2110
2209
|
* @param {TemplateRef<any>} tpl - The template reference for content projection
|
|
2111
2210
|
* @return {AngularDynamicOutput} The Angular component output with component reference and inputs
|
|
2112
|
-
*
|
|
2113
2211
|
* @mermaid
|
|
2114
2212
|
* sequenceDiagram
|
|
2115
2213
|
* participant Client as Client Code
|
|
@@ -2124,6 +2222,8 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2124
2222
|
* Render->>FromField: fromFieldDefinition(fieldDef, vcr, injector, tpl)
|
|
2125
2223
|
* FromField-->>Render: AngularDynamicOutput
|
|
2126
2224
|
* Render-->>Client: return AngularDynamicOutput
|
|
2225
|
+
* @override
|
|
2226
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2127
2227
|
*/
|
|
2128
2228
|
render(model, globalProps, vcr, injector, tpl) {
|
|
2129
2229
|
let result;
|
|
@@ -2147,12 +2247,13 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2147
2247
|
return result;
|
|
2148
2248
|
}
|
|
2149
2249
|
/**
|
|
2150
|
-
* @description Initializes the rendering engine
|
|
2250
|
+
* @description Initializes the rendering engine.
|
|
2151
2251
|
* @summary This method initializes the rendering engine. It checks if the engine is already initialized
|
|
2152
2252
|
* and sets the initialized flag to true. This method is called before the engine is used
|
|
2153
2253
|
* to ensure it's properly set up for rendering operations.
|
|
2154
|
-
*
|
|
2155
2254
|
* @return {Promise<void>} A promise that resolves when initialization is complete
|
|
2255
|
+
* @override
|
|
2256
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2156
2257
|
*/
|
|
2157
2258
|
async initialize() {
|
|
2158
2259
|
if (this.initialized)
|
|
@@ -2161,15 +2262,16 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2161
2262
|
this.initialized = true;
|
|
2162
2263
|
}
|
|
2163
2264
|
/**
|
|
2164
|
-
* @description Registers a component with the rendering engine
|
|
2265
|
+
* @description Registers a component with the rendering engine.
|
|
2165
2266
|
* @summary This static method registers a component constructor with the rendering engine
|
|
2166
2267
|
* under a specific name. It initializes the components registry if needed and throws
|
|
2167
2268
|
* an error if a component is already registered under the same name to prevent
|
|
2168
2269
|
* accidental overrides.
|
|
2169
|
-
*
|
|
2170
2270
|
* @param {string} name - The name to register the component under
|
|
2171
2271
|
* @param {Constructor<unknown>} constructor - The component constructor
|
|
2172
2272
|
* @return {void}
|
|
2273
|
+
* @static
|
|
2274
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2173
2275
|
*/
|
|
2174
2276
|
static registerComponent(name, constructor) {
|
|
2175
2277
|
if (!this._components)
|
|
@@ -2181,14 +2283,15 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2181
2283
|
};
|
|
2182
2284
|
}
|
|
2183
2285
|
/**
|
|
2184
|
-
* @description Retrieves registered components from the rendering engine
|
|
2286
|
+
* @description Retrieves registered components from the rendering engine.
|
|
2185
2287
|
* @summary This static method retrieves either all registered components or a specific component
|
|
2186
2288
|
* by its selector. When called without a selector, it returns an array of all registered
|
|
2187
2289
|
* components. When called with a selector, it returns the specific component if found,
|
|
2188
2290
|
* or throws an error if the component is not registered.
|
|
2189
|
-
*
|
|
2190
2291
|
* @param {string} [selector] - Optional selector to retrieve a specific component
|
|
2191
2292
|
* @return {Object|Array} Either a specific component or an array of all components
|
|
2293
|
+
* @static
|
|
2294
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2192
2295
|
*/
|
|
2193
2296
|
static components(selector) {
|
|
2194
2297
|
if (!selector)
|
|
@@ -2198,30 +2301,30 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2198
2301
|
return this._components[selector];
|
|
2199
2302
|
}
|
|
2200
2303
|
/**
|
|
2201
|
-
* @description Generates a key for reflection metadata
|
|
2304
|
+
* @description Generates a key for reflection metadata storage.
|
|
2202
2305
|
* @summary This static method generates a key for reflection metadata by prefixing the input key
|
|
2203
2306
|
* with the Angular engine's reflection prefix. This is used for storing and retrieving
|
|
2204
2307
|
* metadata in a namespaced way to avoid conflicts with other metadata.
|
|
2205
|
-
*
|
|
2206
2308
|
* @param {string} key - The base key to prefix
|
|
2207
2309
|
* @return {string} The prefixed key for reflection metadata
|
|
2310
|
+
* @static
|
|
2311
|
+
* @override
|
|
2312
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2208
2313
|
*/
|
|
2209
2314
|
static key(key) {
|
|
2210
2315
|
return `${AngularEngineKeys.REFLECT}${key}`;
|
|
2211
2316
|
}
|
|
2212
2317
|
/**
|
|
2213
|
-
* @description Sets input properties on a component instance
|
|
2318
|
+
* @description Sets input properties on a component instance.
|
|
2214
2319
|
* @summary This static utility method sets input properties on a component instance
|
|
2215
2320
|
* based on the provided inputs object and component metadata. It handles both simple
|
|
2216
2321
|
* values and nested objects, recursively processing object properties. The method
|
|
2217
2322
|
* validates each input against the component's metadata to ensure only valid inputs
|
|
2218
2323
|
* are set.
|
|
2219
|
-
*
|
|
2220
2324
|
* @param {ComponentRef<unknown>} component - The component reference to set inputs on
|
|
2221
2325
|
* @param {KeyValue} inputs - The input properties to set
|
|
2222
2326
|
* @param {ComponentMirror<unknown>} metadata - The component metadata for input validation
|
|
2223
2327
|
* @return {void}
|
|
2224
|
-
*
|
|
2225
2328
|
* @mermaid
|
|
2226
2329
|
* sequenceDiagram
|
|
2227
2330
|
* participant Caller
|
|
@@ -2241,6 +2344,8 @@ class NgxRenderingEngine extends RenderingEngine {
|
|
|
2241
2344
|
* SetInputs->>Component: setInput(key, value)
|
|
2242
2345
|
* end
|
|
2243
2346
|
* end
|
|
2347
|
+
* @static
|
|
2348
|
+
* @memberOf module:lib/engine/NgxRenderingEngine
|
|
2244
2349
|
*/
|
|
2245
2350
|
static setInputs(component, inputs, metadata) {
|
|
2246
2351
|
function parseInputValue(component, input) {
|
|
@@ -2343,7 +2448,8 @@ var errors = {
|
|
|
2343
2448
|
lessThanOrEqual: "This field must be less than or equal to field {0}",
|
|
2344
2449
|
greaterThan: "This field must be greater than field {0}",
|
|
2345
2450
|
greaterThanOrEqual: "This field must be greater than or equal to field {0}",
|
|
2346
|
-
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>."
|
|
2347
2453
|
};
|
|
2348
2454
|
var component = {
|
|
2349
2455
|
fieldset: {
|
|
@@ -2377,7 +2483,7 @@ var component = {
|
|
|
2377
2483
|
},
|
|
2378
2484
|
empty_state: {
|
|
2379
2485
|
title: "No data found",
|
|
2380
|
-
|
|
2486
|
+
button_create: "Create",
|
|
2381
2487
|
search: {
|
|
2382
2488
|
title: "Not data found for search",
|
|
2383
2489
|
subtitle: "You searched for: <ion-text color=\"primary\" class=\"display-block ion-text-center text-bold\">{0}</ion-text>",
|
|
@@ -2506,12 +2612,11 @@ function provideI18n(config = { fallbackLang: 'en', lang: 'en' }, resources = []
|
|
|
2506
2612
|
}
|
|
2507
2613
|
|
|
2508
2614
|
/**
|
|
2509
|
-
* @module
|
|
2615
|
+
* @module lib/engine/NgxDecafComponentDirective
|
|
2510
2616
|
* @description Base decaf component abstraction providing shared inputs and utilities.
|
|
2511
2617
|
* @summary NgxDecafComponentDirective is the abstract foundation for Decaf components and provides common
|
|
2512
2618
|
* inputs (model, mapper, pk, props), logging, repository resolution, and event dispatch helpers.
|
|
2513
2619
|
* It centralizes shared behavior for child components and simplifies integration with the rendering engine.
|
|
2514
|
-
*
|
|
2515
2620
|
* @link {@link NgxDecafComponentDirective}
|
|
2516
2621
|
*/
|
|
2517
2622
|
try {
|
|
@@ -2520,194 +2625,250 @@ try {
|
|
|
2520
2625
|
catch (e) {
|
|
2521
2626
|
throw new Error(`Failed to load rendering engine: ${e}`);
|
|
2522
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
|
+
*/
|
|
2523
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
|
+
*/
|
|
2524
2652
|
// eslint-disable-next-line @angular-eslint/prefer-inject
|
|
2525
2653
|
constructor(componentName, localeRoot) {
|
|
2526
2654
|
super();
|
|
2527
|
-
this.componentName = componentName;
|
|
2528
|
-
this.localeRoot = localeRoot;
|
|
2529
2655
|
/**
|
|
2530
|
-
* @description Unique identifier for the
|
|
2531
|
-
* @summary A unique identifier
|
|
2532
|
-
* This is
|
|
2533
|
-
*
|
|
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.
|
|
2534
2660
|
* @type {string | number}
|
|
2535
|
-
* @
|
|
2661
|
+
* @default generateRandomValue(16)
|
|
2662
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2536
2663
|
*/
|
|
2537
2664
|
this.uid = generateRandomValue(16);
|
|
2538
2665
|
/**
|
|
2539
|
-
* @description Field mapping configuration.
|
|
2666
|
+
* @description Field mapping configuration object or function.
|
|
2540
2667
|
* @summary Defines how fields from the data model should be mapped to properties used by the component.
|
|
2541
|
-
* This allows for flexible data binding between the model and the component's display logic.
|
|
2542
|
-
*
|
|
2543
|
-
* @type {Record<string, string>}
|
|
2544
|
-
* @
|
|
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
|
|
2545
2673
|
*/
|
|
2546
2674
|
this.mapper = {};
|
|
2547
2675
|
/**
|
|
2548
|
-
* @description Available CRUD operations for this component.
|
|
2676
|
+
* @description Available CRUD operations for this component instance.
|
|
2549
2677
|
* @summary Defines which CRUD operations (Create, Read, Update, Delete) are available
|
|
2550
|
-
* for this component. This affects which operations can be performed on the data
|
|
2551
|
-
*
|
|
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[]}
|
|
2552
2681
|
* @default [OperationKeys.READ]
|
|
2553
|
-
* @memberOf NgxDecafComponentDirective
|
|
2682
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2554
2683
|
*/
|
|
2555
2684
|
this.operations = [OperationKeys.READ];
|
|
2556
2685
|
/**
|
|
2557
|
-
* @description
|
|
2558
|
-
* @summary Specifies which
|
|
2559
|
-
*
|
|
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.
|
|
2560
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.
|
|
2561
2702
|
* @type {number}
|
|
2562
2703
|
* @default 1
|
|
2563
|
-
* @memberOf NgxDecafComponentDirective
|
|
2704
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2564
2705
|
*/
|
|
2565
2706
|
this.row = 1;
|
|
2566
2707
|
/**
|
|
2567
|
-
* @description
|
|
2568
|
-
* @summary Specifies
|
|
2569
|
-
* This is
|
|
2570
|
-
*
|
|
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.
|
|
2571
2712
|
* @type {number}
|
|
2572
2713
|
* @default 1
|
|
2573
|
-
* @memberOf NgxDecafComponentDirective
|
|
2714
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2574
2715
|
*/
|
|
2575
2716
|
this.col = 1;
|
|
2576
2717
|
/**
|
|
2577
|
-
* @description Additional CSS class names
|
|
2718
|
+
* @description Additional CSS class names for component styling.
|
|
2578
2719
|
* @summary Allows custom CSS classes to be added to the component's root element.
|
|
2579
2720
|
* These classes are appended to any automatically generated classes based on other
|
|
2580
2721
|
* component properties. Multiple classes can be provided as a space-separated string.
|
|
2581
2722
|
* This provides a way to customize the component's appearance beyond the built-in styling options.
|
|
2582
|
-
*
|
|
2583
2723
|
* @type {string}
|
|
2584
2724
|
* @default ""
|
|
2585
|
-
* @memberOf NgxDecafComponentDirective
|
|
2725
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2586
2726
|
*/
|
|
2587
2727
|
this.className = '';
|
|
2588
2728
|
/**
|
|
2589
|
-
* @description
|
|
2590
|
-
* @summary
|
|
2591
|
-
*
|
|
2592
|
-
* the application
|
|
2593
|
-
*
|
|
2594
|
-
* @
|
|
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
|
|
2595
2735
|
* @type {MenuController}
|
|
2596
|
-
* @memberOf NgxDecafComponentDirective
|
|
2736
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2597
2737
|
*/
|
|
2598
2738
|
this.menuController = inject(MenuController);
|
|
2599
2739
|
/**
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
*/
|
|
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
|
+
*/
|
|
2610
2749
|
this.changeDetectorRef = inject(ChangeDetectorRef);
|
|
2611
2750
|
/**
|
|
2612
|
-
* @description Angular Renderer2 service for
|
|
2751
|
+
* @description Angular Renderer2 service for platform-agnostic DOM manipulation.
|
|
2613
2752
|
* @summary Injected service that provides a safe, platform-agnostic way to manipulate DOM elements.
|
|
2614
2753
|
* This service ensures proper handling of DOM operations across different platforms and environments,
|
|
2615
|
-
* including server-side rendering and web workers.
|
|
2616
|
-
*
|
|
2754
|
+
* including server-side rendering and web workers, without direct DOM access.
|
|
2617
2755
|
* @protected
|
|
2618
2756
|
* @type {Renderer2}
|
|
2619
|
-
* @memberOf
|
|
2757
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2620
2758
|
*/
|
|
2621
2759
|
this.renderer = inject(Renderer2);
|
|
2622
2760
|
/**
|
|
2623
|
-
* @description Translation service for internationalization.
|
|
2761
|
+
* @description Translation service for application internationalization.
|
|
2624
2762
|
* @summary Injected service that provides translation capabilities for UI text.
|
|
2625
|
-
* Used to translate button labels
|
|
2626
|
-
*
|
|
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.
|
|
2627
2765
|
* @protected
|
|
2628
2766
|
* @type {TranslateService}
|
|
2629
|
-
* @memberOf
|
|
2767
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2630
2768
|
*/
|
|
2631
2769
|
this.translateService = inject(TranslateService);
|
|
2632
2770
|
/**
|
|
2633
|
-
* @description Event emitter for custom
|
|
2634
|
-
* @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.
|
|
2635
2773
|
* This allows parent components to listen for and respond to user interactions or
|
|
2636
|
-
* state changes
|
|
2637
|
-
*
|
|
2638
|
-
*
|
|
2774
|
+
* state changes. Events are passed up the component hierarchy to enable coordinated
|
|
2775
|
+
* behavior across the application.
|
|
2639
2776
|
* @type {EventEmitter<IBaseCustomEvent>}
|
|
2640
|
-
* @memberOf NgxDecafComponentDirective
|
|
2777
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2641
2778
|
*/
|
|
2642
2779
|
this.listenEvent = new EventEmitter();
|
|
2643
2780
|
/**
|
|
2644
|
-
* @description Angular Router instance for navigation
|
|
2645
|
-
* @summary Injected Router service used for programmatic navigation
|
|
2646
|
-
*
|
|
2647
|
-
*
|
|
2648
|
-
* @
|
|
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
|
|
2649
2786
|
* @type {Router}
|
|
2650
|
-
* @memberOf NgxDecafComponentDirective
|
|
2787
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2651
2788
|
*/
|
|
2652
2789
|
this.router = inject(Router);
|
|
2653
2790
|
/**
|
|
2654
|
-
* @description Configuration for list item rendering
|
|
2791
|
+
* @description Configuration for list item rendering behavior.
|
|
2655
2792
|
* @summary Defines how list items should be rendered in the component.
|
|
2656
2793
|
* This property holds a configuration object that specifies the tag name
|
|
2657
2794
|
* and other properties needed to render list items correctly. The tag property
|
|
2658
2795
|
* identifies which component should be used to render each item in a list.
|
|
2659
2796
|
* Additional properties can be included to customize the rendering behavior.
|
|
2660
|
-
*
|
|
2661
2797
|
* @type {Record<string, unknown>}
|
|
2662
2798
|
* @default {tag: ""}
|
|
2663
|
-
* @memberOf NgxDecafComponentDirective
|
|
2799
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2664
2800
|
*/
|
|
2665
2801
|
this.item = { tag: '' };
|
|
2666
2802
|
/**
|
|
2667
|
-
* @description Dynamic properties configuration
|
|
2803
|
+
* @description Dynamic properties configuration for runtime customization.
|
|
2668
2804
|
* @summary Contains key-value pairs of dynamic properties that can be applied to the component
|
|
2669
2805
|
* at runtime. This flexible configuration object allows for dynamic property assignment without
|
|
2670
2806
|
* requiring explicit input bindings for every possible configuration option. Properties from
|
|
2671
2807
|
* this object are parsed and applied to the component instance through the parseProps method,
|
|
2672
2808
|
* enabling customizable component behavior based on external configuration.
|
|
2673
|
-
*
|
|
2674
2809
|
* @type {Record<string, unknown>}
|
|
2675
2810
|
* @default {}
|
|
2676
|
-
* @memberOf NgxDecafComponentDirective
|
|
2811
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2677
2812
|
*/
|
|
2678
2813
|
this.props = {};
|
|
2679
2814
|
/**
|
|
2680
|
-
* @description
|
|
2815
|
+
* @description Initialization status flag for the component.
|
|
2681
2816
|
* @summary Tracks whether the component has completed its initialization process.
|
|
2682
2817
|
* This flag is used to prevent duplicate initialization and to determine if
|
|
2683
2818
|
* certain operations that require initialization can be performed.
|
|
2684
|
-
*
|
|
2685
2819
|
* @type {boolean}
|
|
2686
2820
|
* @default false
|
|
2687
|
-
* @memberOf NgxDecafComponentDirective
|
|
2821
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2688
2822
|
*/
|
|
2689
2823
|
this.initialized = false;
|
|
2690
|
-
|
|
2691
|
-
|
|
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)
|
|
2692
2848
|
this.localeRoot = this.componentName;
|
|
2849
|
+
if (this.localeRoot)
|
|
2850
|
+
this.getLocale(this.localeRoot);
|
|
2693
2851
|
this.logger = this.log;
|
|
2694
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
|
+
*/
|
|
2695
2860
|
get localeContext() {
|
|
2696
2861
|
return this.getLocale();
|
|
2697
2862
|
}
|
|
2698
2863
|
/**
|
|
2699
|
-
* @description Getter for the repository instance.
|
|
2700
|
-
* @summary
|
|
2701
|
-
* This
|
|
2702
|
-
*
|
|
2703
|
-
*
|
|
2704
|
-
* The repository
|
|
2705
|
-
*
|
|
2706
|
-
*
|
|
2707
|
-
*
|
|
2708
|
-
* @returns {DecafRepository<Model>} The initialized repository instance.
|
|
2709
|
-
* @private
|
|
2710
|
-
* @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
|
|
2711
2872
|
*/
|
|
2712
2873
|
get repository() {
|
|
2713
2874
|
try {
|
|
@@ -2724,16 +2885,14 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2724
2885
|
return this._repository;
|
|
2725
2886
|
}
|
|
2726
2887
|
/**
|
|
2727
|
-
* @description
|
|
2728
|
-
* @summary
|
|
2729
|
-
*
|
|
2730
|
-
*
|
|
2731
|
-
* it
|
|
2732
|
-
*
|
|
2733
|
-
* the translation settings.
|
|
2734
|
-
*
|
|
2735
|
-
* @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
|
|
2736
2894
|
* @return {void}
|
|
2895
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2737
2896
|
*/
|
|
2738
2897
|
ngOnChanges(changes) {
|
|
2739
2898
|
if (changes[BaseComponentProps.MODEL]) {
|
|
@@ -2745,6 +2904,18 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2745
2904
|
if (changes[BaseComponentProps.LOCALE_ROOT] || changes[BaseComponentProps.COMPONENT_NAME])
|
|
2746
2905
|
this.locale = this.localeContext;
|
|
2747
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
|
+
*/
|
|
2748
2919
|
translate(phrase, params) {
|
|
2749
2920
|
return new Promise((resolve) => {
|
|
2750
2921
|
if (typeof params === Primitives.STRING)
|
|
@@ -2752,10 +2923,31 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2752
2923
|
return resolve(firstValueFrom(this.translateService.get(phrase, (params || {}))));
|
|
2753
2924
|
});
|
|
2754
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
|
+
*/
|
|
2755
2937
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2756
2938
|
async initialize(...args) {
|
|
2757
2939
|
this.initialized = true;
|
|
2758
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
|
+
*/
|
|
2759
2951
|
getLocale(locale) {
|
|
2760
2952
|
if (locale || !this.locale) {
|
|
2761
2953
|
if (locale)
|
|
@@ -2765,13 +2957,13 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2765
2957
|
return this.locale;
|
|
2766
2958
|
}
|
|
2767
2959
|
/**
|
|
2768
|
-
* @description
|
|
2769
|
-
* @summary
|
|
2770
|
-
*
|
|
2771
|
-
*
|
|
2772
|
-
*
|
|
2773
|
-
*
|
|
2774
|
-
* @
|
|
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
|
|
2775
2967
|
*/
|
|
2776
2968
|
getRoute() {
|
|
2777
2969
|
if (!this.route && this.model instanceof Model)
|
|
@@ -2779,14 +2971,15 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2779
2971
|
return this.route || '';
|
|
2780
2972
|
}
|
|
2781
2973
|
/**
|
|
2782
|
-
* @description Resolves and
|
|
2783
|
-
* @summary
|
|
2784
|
-
*
|
|
2785
|
-
*
|
|
2786
|
-
* to
|
|
2787
|
-
*
|
|
2788
|
-
* @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
|
|
2789
2981
|
* @return {void}
|
|
2982
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2790
2983
|
*/
|
|
2791
2984
|
getModel(model) {
|
|
2792
2985
|
if (!(model instanceof Model) && typeof model === Primitives.STRING)
|
|
@@ -2794,16 +2987,16 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2794
2987
|
this.setModelDefinitions(this.model);
|
|
2795
2988
|
}
|
|
2796
2989
|
/**
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
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
|
+
*/
|
|
2807
3000
|
setModelDefinitions(model) {
|
|
2808
3001
|
if (model instanceof Model) {
|
|
2809
3002
|
this.getRoute();
|
|
@@ -2829,33 +3022,34 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2829
3022
|
* component instance. This allows for dynamic property assignment based on configuration
|
|
2830
3023
|
* stored in the props object, enabling flexible component customization without requiring
|
|
2831
3024
|
* explicit property binding for every possible configuration option.
|
|
2832
|
-
*
|
|
2833
3025
|
* The method performs a safe property assignment by checking if each key from the instance
|
|
2834
3026
|
* exists in the props object before applying it. This prevents accidental property
|
|
2835
3027
|
* overwriting and ensures only intended properties are modified.
|
|
2836
|
-
*
|
|
2837
3028
|
* @param {KeyValue} instance - The component instance object to process
|
|
3029
|
+
* @param {string[]} [skip=[]] - Array of property names to skip during parsing
|
|
2838
3030
|
* @return {void}
|
|
2839
|
-
*
|
|
2840
3031
|
* @mermaid
|
|
2841
3032
|
* sequenceDiagram
|
|
2842
3033
|
* participant C as Component
|
|
2843
|
-
* participant
|
|
3034
|
+
* participant D as NgxDecafComponentDirective
|
|
2844
3035
|
* participant P as Props Object
|
|
2845
3036
|
*
|
|
2846
|
-
* C->>
|
|
2847
|
-
*
|
|
3037
|
+
* C->>D: parseProps(instance, skip)
|
|
3038
|
+
* D->>D: Get Object.keys(instance)
|
|
2848
3039
|
* loop For each key in instance
|
|
2849
|
-
*
|
|
2850
|
-
* alt Key
|
|
2851
|
-
*
|
|
2852
|
-
*
|
|
2853
|
-
*
|
|
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
|
|
2854
3049
|
* end
|
|
2855
3050
|
* end
|
|
2856
|
-
*
|
|
2857
3051
|
* @protected
|
|
2858
|
-
* @memberOf
|
|
3052
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2859
3053
|
*/
|
|
2860
3054
|
parseProps(instance, skip = []) {
|
|
2861
3055
|
Object.keys(instance).forEach((key) => {
|
|
@@ -2866,21 +3060,55 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2866
3060
|
});
|
|
2867
3061
|
}
|
|
2868
3062
|
/**
|
|
2869
|
-
* @description Tracks items in ngFor loops for optimal change detection.
|
|
3063
|
+
* @description Tracks items in ngFor loops for optimal change detection performance.
|
|
2870
3064
|
* @summary Provides a tracking function for Angular's *ngFor directive to optimize rendering
|
|
2871
3065
|
* performance. This method generates unique identifiers for list items based on their index
|
|
2872
3066
|
* and content, allowing Angular to efficiently track changes and minimize DOM manipulations
|
|
2873
3067
|
* during list updates. The tracking function is essential for maintaining component state
|
|
2874
3068
|
* and preventing unnecessary re-rendering of unchanged items.
|
|
2875
|
-
*
|
|
3069
|
+
* @protected
|
|
2876
3070
|
* @param {number} index - The index of the item in the list
|
|
2877
3071
|
* @param {KeyValue | string | number} item - The item data to track
|
|
2878
|
-
* @
|
|
2879
|
-
* @memberOf NgxDecafComponentDirective
|
|
3072
|
+
* @return {string | number} A unique identifier for the item
|
|
3073
|
+
* @memberOf module:lib/engine/NgxDecafComponentDirective
|
|
2880
3074
|
*/
|
|
2881
3075
|
trackItemFn(index, item) {
|
|
2882
3076
|
return `${index}-${item}`;
|
|
2883
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
|
+
*/
|
|
2884
3112
|
async handleEvent(event) {
|
|
2885
3113
|
let name = "";
|
|
2886
3114
|
const log = this.log.for(this.handleEvent);
|
|
@@ -2907,8 +3135,70 @@ class NgxDecafComponentDirective extends LoggedClass {
|
|
|
2907
3135
|
}
|
|
2908
3136
|
this.listenEvent.emit(event);
|
|
2909
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
|
+
}
|
|
2910
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 }); }
|
|
2911
|
-
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 }); }
|
|
2912
3202
|
}
|
|
2913
3203
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NgxDecafComponentDirective, decorators: [{
|
|
2914
3204
|
type: Directive,
|
|
@@ -2938,6 +3228,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2938
3228
|
type: Input
|
|
2939
3229
|
}], operations: [{
|
|
2940
3230
|
type: Input
|
|
3231
|
+
}], operation: [{
|
|
3232
|
+
type: Input
|
|
2941
3233
|
}], row: [{
|
|
2942
3234
|
type: Input
|
|
2943
3235
|
}], col: [{
|
|
@@ -2957,12 +3249,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
2957
3249
|
}] } });
|
|
2958
3250
|
|
|
2959
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.
|
|
2960
3266
|
* @class NgxDecafFormFieldDirective
|
|
2961
|
-
* @
|
|
3267
|
+
* @extends {NgxDecafComponentDirective}
|
|
2962
3268
|
* @implements {ControlValueAccessor}
|
|
2963
|
-
* @
|
|
2964
|
-
* @
|
|
2965
|
-
*
|
|
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
|
+
* ```
|
|
2966
3287
|
*/
|
|
2967
3288
|
class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
|
|
2968
3289
|
constructor() {
|
|
@@ -2972,40 +3293,51 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
|
|
|
2972
3293
|
* @summary When working with multiple form groups (form arrays), this indicates
|
|
2973
3294
|
* which form group is currently active or being edited. This is used to manage
|
|
2974
3295
|
* focus and data binding in multi-entry scenarios.
|
|
2975
|
-
*
|
|
2976
3296
|
* @type {number}
|
|
2977
3297
|
* @default 0
|
|
2978
|
-
* @
|
|
3298
|
+
* @public
|
|
2979
3299
|
*/
|
|
2980
3300
|
this.activeFormGroupIndex = 0;
|
|
3301
|
+
this.operation = OperationKeys.CREATE;
|
|
2981
3302
|
/**
|
|
2982
|
-
* @description Field mapping configuration.
|
|
3303
|
+
* @description Field mapping configuration for options.
|
|
2983
3304
|
* @summary Defines how fields from the data model should be mapped to properties used by the component.
|
|
2984
3305
|
* This allows for flexible data binding between the model and the component's display logic.
|
|
2985
|
-
*
|
|
3306
|
+
* Can be either a key-value mapping object or a function that performs the mapping.
|
|
2986
3307
|
* @type {KeyValue | FunctionLike}
|
|
2987
|
-
* @
|
|
3308
|
+
* @public
|
|
2988
3309
|
*/
|
|
2989
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
|
+
*/
|
|
2990
3317
|
this.validationErrorEventDispatched = false;
|
|
2991
|
-
// protected constructor() {}
|
|
2992
3318
|
/**
|
|
2993
|
-
* @
|
|
2994
|
-
* @
|
|
2995
|
-
*
|
|
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
|
|
2996
3324
|
*/
|
|
2997
3325
|
this.sf = sf;
|
|
2998
3326
|
/**
|
|
2999
|
-
* @
|
|
3000
|
-
* @
|
|
3001
|
-
*
|
|
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
|
|
3002
3332
|
*/
|
|
3003
3333
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
3004
3334
|
this.onChange = () => { };
|
|
3005
3335
|
/**
|
|
3006
|
-
* @
|
|
3007
|
-
* @
|
|
3008
|
-
*
|
|
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
|
|
3009
3341
|
*/
|
|
3010
3342
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
3011
3343
|
this.onTouch = () => { };
|
|
@@ -3015,9 +3347,9 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
|
|
|
3015
3347
|
* @summary Returns the appropriate FormGroup based on whether this field supports
|
|
3016
3348
|
* multiple values. For single-value fields, returns the main form group.
|
|
3017
3349
|
* For multi-value fields, returns the form group at the active index from the parent FormArray.
|
|
3018
|
-
*
|
|
3019
|
-
* @
|
|
3020
|
-
* @
|
|
3350
|
+
* If no formGroup is set, returns the parent of the formControl.
|
|
3351
|
+
* @return {FormGroup} The currently active FormGroup for this field
|
|
3352
|
+
* @public
|
|
3021
3353
|
*/
|
|
3022
3354
|
get activeFormGroup() {
|
|
3023
3355
|
if (!this.formGroup)
|
|
@@ -3028,53 +3360,61 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
|
|
|
3028
3360
|
return this.formGroup;
|
|
3029
3361
|
}
|
|
3030
3362
|
return this.formGroup;
|
|
3031
|
-
// const formGroup = this.formGroup as FormGroup;
|
|
3032
|
-
// try {
|
|
3033
|
-
// const root = formGroup.root as FormGroup;
|
|
3034
|
-
// return this.multiple
|
|
3035
|
-
// ? ((root?.controls?.[this.name] as FormArray)?.at(this.activeFormGroupIndex) as FormGroup)
|
|
3036
|
-
// : formGroup;
|
|
3037
|
-
// } catch (error: unknown) {
|
|
3038
|
-
// this.log.error("Error getting active form group:", error as Error);
|
|
3039
|
-
// return formGroup;
|
|
3040
|
-
// }
|
|
3041
3363
|
}
|
|
3042
3364
|
/**
|
|
3043
|
-
* @
|
|
3044
|
-
* @
|
|
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.
|
|
3045
3369
|
* @param {string} obj - The value to be set
|
|
3370
|
+
* @return {void}
|
|
3371
|
+
* @public
|
|
3046
3372
|
*/
|
|
3047
3373
|
writeValue(obj) {
|
|
3048
3374
|
this.value = obj;
|
|
3049
3375
|
}
|
|
3050
3376
|
/**
|
|
3051
|
-
* @
|
|
3052
|
-
* @
|
|
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.
|
|
3053
3380
|
* @param {function(): unknown} fn - The function to be called on change
|
|
3381
|
+
* @return {void}
|
|
3382
|
+
* @public
|
|
3054
3383
|
*/
|
|
3055
3384
|
registerOnChange(fn) {
|
|
3056
3385
|
this.onChange = fn;
|
|
3057
3386
|
}
|
|
3058
3387
|
/**
|
|
3059
|
-
* @
|
|
3060
|
-
* @
|
|
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.
|
|
3061
3391
|
* @param {function(): unknown} fn - The function to be called on touch
|
|
3392
|
+
* @return {void}
|
|
3393
|
+
* @public
|
|
3062
3394
|
*/
|
|
3063
3395
|
registerOnTouched(fn) {
|
|
3064
3396
|
this.onTouch = fn;
|
|
3065
3397
|
}
|
|
3066
3398
|
/**
|
|
3067
|
-
* @
|
|
3068
|
-
* @
|
|
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.
|
|
3069
3402
|
* @param {boolean} isDisabled - Whether the field should be disabled
|
|
3403
|
+
* @return {void}
|
|
3404
|
+
* @public
|
|
3070
3405
|
*/
|
|
3071
3406
|
setDisabledState(isDisabled) {
|
|
3072
3407
|
this.disabled = isDisabled;
|
|
3073
3408
|
}
|
|
3074
3409
|
/**
|
|
3075
|
-
* @
|
|
3076
|
-
* @
|
|
3077
|
-
*
|
|
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
|
|
3078
3418
|
*/
|
|
3079
3419
|
afterViewInit() {
|
|
3080
3420
|
let parent;
|
|
@@ -3096,6 +3436,16 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
|
|
|
3096
3436
|
throw new InternalError(`Invalid operation: ${this.operation}`);
|
|
3097
3437
|
}
|
|
3098
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
|
+
*/
|
|
3099
3449
|
ngOnChanges(changes) {
|
|
3100
3450
|
if (!this.initialized)
|
|
3101
3451
|
super.ngOnChanges(changes);
|
|
@@ -3109,14 +3459,38 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
|
|
|
3109
3459
|
&& (changes['value'].currentValue !== undefined && changes['value'].currentValue !== this.value))
|
|
3110
3460
|
this.setValue(changes['value'].currentValue);
|
|
3111
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
|
+
*/
|
|
3112
3469
|
onDestroy() {
|
|
3113
3470
|
if (this.formGroup)
|
|
3114
3471
|
NgxDecafFormService.unregister(this.formGroup);
|
|
3115
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
|
+
*/
|
|
3116
3481
|
setValue(value) {
|
|
3117
3482
|
this.formControl.setValue(value);
|
|
3118
3483
|
this.formControl.updateValueAndValidity();
|
|
3119
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
|
+
*/
|
|
3120
3494
|
getErrors(parent) {
|
|
3121
3495
|
const formControl = this.formControl;
|
|
3122
3496
|
if (formControl) {
|
|
@@ -3142,12 +3516,15 @@ class NgxDecafFormFieldDirective extends NgxDecafComponentDirective {
|
|
|
3142
3516
|
}
|
|
3143
3517
|
}
|
|
3144
3518
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NgxDecafFormFieldDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3145
|
-
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 }); }
|
|
3146
3520
|
}
|
|
3147
3521
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NgxDecafFormFieldDirective, decorators: [{
|
|
3148
3522
|
type: Directive
|
|
3149
3523
|
}], ctorParameters: () => [], propDecorators: { activeFormGroupIndex: [{
|
|
3150
3524
|
type: Input
|
|
3525
|
+
}], operation: [{
|
|
3526
|
+
type: Input,
|
|
3527
|
+
args: [{ required: true }]
|
|
3151
3528
|
}], parentComponent: [{
|
|
3152
3529
|
type: Input
|
|
3153
3530
|
}], optionsMapper: [{
|
|
@@ -3166,32 +3543,112 @@ class NgxEventHandler extends LoggedClass {
|
|
|
3166
3543
|
}
|
|
3167
3544
|
|
|
3168
3545
|
/**
|
|
3169
|
-
* @module
|
|
3546
|
+
* @module lib/engine/NgxPageDirective
|
|
3170
3547
|
* @description Base page component for Decaf Angular applications.
|
|
3171
3548
|
* @summary Provides a page-level base class (NgxPageDirective) that extends NgxDecafComponentDirective and
|
|
3172
3549
|
* offers page-focused utilities such as menu management, title handling and router event hooks.
|
|
3173
|
-
*
|
|
3174
3550
|
* @link {@link NgxPageDirective}
|
|
3175
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
|
+
*/
|
|
3176
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
|
+
*/
|
|
3177
3572
|
// eslint-disable-next-line @angular-eslint/prefer-inject
|
|
3178
3573
|
constructor(localeRoot, hasMenu = true) {
|
|
3179
3574
|
super(localeRoot);
|
|
3180
3575
|
this.localeRoot = localeRoot;
|
|
3181
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
|
+
*/
|
|
3182
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
|
+
*/
|
|
3183
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
|
+
*/
|
|
3184
3608
|
this.titleService = inject(Title);
|
|
3185
3609
|
}
|
|
3186
|
-
|
|
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
|
+
});
|
|
3187
3629
|
await this.menuController.enable(this.hasMenu);
|
|
3188
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
|
+
*/
|
|
3189
3644
|
setPageTitle(route, menu) {
|
|
3645
|
+
if (!route)
|
|
3646
|
+
route = this.router.url.replace('/', '');
|
|
3190
3647
|
if (menu)
|
|
3191
3648
|
menu = this.menu;
|
|
3192
3649
|
const activeMenu = this.menu.find(item => item?.url?.includes(route));
|
|
3193
3650
|
if (activeMenu)
|
|
3194
|
-
this.titleService.setTitle(
|
|
3651
|
+
this.titleService.setTitle(`${activeMenu?.title || activeMenu?.label}`);
|
|
3195
3652
|
}
|
|
3196
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 }); }
|
|
3197
3654
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.7", type: NgxPageDirective, isStandalone: true, usesInheritance: true, ngImport: i0 }); }
|
|
@@ -3778,7 +4235,6 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxDecafFormFieldDirec
|
|
|
3778
4235
|
if (this.optionsMapper) {
|
|
3779
4236
|
if (this.optionsMapper instanceof Function || typeof this.optionsMapper === 'function') {
|
|
3780
4237
|
const mapper = this.optionsMapper;
|
|
3781
|
-
console.log(this.options);
|
|
3782
4238
|
this.options = this.options.map((option) => {
|
|
3783
4239
|
return mapper(option);
|
|
3784
4240
|
});
|
|
@@ -3847,48 +4303,6 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxDecafFormFieldDirec
|
|
|
3847
4303
|
return false;
|
|
3848
4304
|
return this.formControl.value.includes(value);
|
|
3849
4305
|
}
|
|
3850
|
-
/**
|
|
3851
|
-
* @description Handles fieldset group creation events from parent fieldsets.
|
|
3852
|
-
* @summary Processes events triggered when a new group needs to be added to a fieldset.
|
|
3853
|
-
* Validates the current form group, checks for uniqueness if applicable, and either
|
|
3854
|
-
* creates a new group or provides validation feedback. Updates the active form group
|
|
3855
|
-
* and resets the field for new input after successful creation.
|
|
3856
|
-
*
|
|
3857
|
-
* @param {CustomEvent} event - The fieldset create group event containing group details
|
|
3858
|
-
* @returns {void}
|
|
3859
|
-
* @memberOf CrudFieldComponent
|
|
3860
|
-
*/
|
|
3861
|
-
handleFieldsetCreateGroupEvent(event) {
|
|
3862
|
-
event.stopImmediatePropagation();
|
|
3863
|
-
const { formGroup } = event.detail;
|
|
3864
|
-
// const formGroup = this.formGroup as FormGroup;
|
|
3865
|
-
// const parentFormGroup = this.formGroup?.parent as FormArray;
|
|
3866
|
-
// const isValid = NgxDecafFormService.validateFields(formGroup as FormGroup);
|
|
3867
|
-
// const indexToCheck = operation === OperationKeys.CREATE ?
|
|
3868
|
-
// index === 0 ? index : parentFormGroup.length - 1 : index;
|
|
3869
|
-
// const isUnique = NgxDecafFormService.isUniqueOnGroup(formGroup, indexToCheck, operation || OperationKeys.CREATE);
|
|
3870
|
-
// event = new CustomEvent(EventConstants.FIELDSET_ADD_GROUP, {
|
|
3871
|
-
// detail: {isValid: isValid && isUnique, value: formGroup.value, formGroup: parentFormGroup, formService: NgxDecafFormService},
|
|
3872
|
-
// });
|
|
3873
|
-
// component.dispatchEvent(event);
|
|
3874
|
-
// if(isValid && isUnique) {
|
|
3875
|
-
// const newIndex = parentFormGroup?.length;
|
|
3876
|
-
// if(operation === OperationKeys.CREATE) {
|
|
3877
|
-
// NgxDecafFormService.addGroupToParent(parentFormGroup?.parent as FormGroup, parent, newIndex);
|
|
3878
|
-
// this.activeFormGroup = newIndex;
|
|
3879
|
-
// } else {
|
|
3880
|
-
// this.activeFormGroup = newIndex - 1;
|
|
3881
|
-
// }
|
|
3882
|
-
// this.formGroup = this.activeFormGroup;
|
|
3883
|
-
// // NgxDecafFormService.reset(this.formGroup as FormGroup);
|
|
3884
|
-
// this.formControl = (this.formGroup as FormGroup).get(this.name) as FormControl;
|
|
3885
|
-
// // NgxDecafFormService.reset(this.formControl);
|
|
3886
|
-
// // this.component.nativeElement.setFocus();
|
|
3887
|
-
// } else {
|
|
3888
|
-
// if(isUnique)
|
|
3889
|
-
// this.component.nativeElement.setFocus();
|
|
3890
|
-
// }
|
|
3891
|
-
}
|
|
3892
4306
|
/**
|
|
3893
4307
|
* @description Handles fieldset group update events from parent fieldsets.
|
|
3894
4308
|
* @summary Processes events triggered when an existing group needs to be updated.
|
|
@@ -3906,31 +4320,8 @@ let CrudFieldComponent = class CrudFieldComponent extends NgxDecafFormFieldDirec
|
|
|
3906
4320
|
this.formControl = this.formGroup.get(this.name);
|
|
3907
4321
|
this.value = this.formControl.value;
|
|
3908
4322
|
}
|
|
3909
|
-
/**
|
|
3910
|
-
* @description Handles fieldset group removal events from parent fieldsets.
|
|
3911
|
-
* @summary Processes events triggered when a group needs to be removed from a fieldset.
|
|
3912
|
-
* Removes the specified group from the form array, updates the active form group index,
|
|
3913
|
-
* and refreshes the form references. Dispatches a confirmation event back to the component.
|
|
3914
|
-
*
|
|
3915
|
-
* @param {CustomEvent} event - The fieldset remove group event containing removal details
|
|
3916
|
-
* @returns {void}
|
|
3917
|
-
* @memberOf CrudFieldComponent
|
|
3918
|
-
*/
|
|
3919
|
-
handleFieldsetRemoveGroupEvent(event) {
|
|
3920
|
-
const { component, index } = event.detail;
|
|
3921
|
-
const formArray = this.formGroup?.parent;
|
|
3922
|
-
formArray.removeAt(index);
|
|
3923
|
-
this.activeFormGroupIndex = formArray.length === 1 ? 0 : formArray.length - 1;
|
|
3924
|
-
this.formGroup = this.activeFormGroup;
|
|
3925
|
-
this.formControl = this.formGroup.get(this.name);
|
|
3926
|
-
this.parentComponent = formArray;
|
|
3927
|
-
event = new CustomEvent(EventConstants.FIELDSET_REMOVE_GROUP, {
|
|
3928
|
-
detail: { value: true },
|
|
3929
|
-
});
|
|
3930
|
-
component.dispatchEvent(event);
|
|
3931
|
-
}
|
|
3932
4323
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CrudFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
3933
|
-
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" }] }); }
|
|
3934
4325
|
};
|
|
3935
4326
|
CrudFieldComponent = __decorate([
|
|
3936
4327
|
Dynamic()
|
|
@@ -3950,7 +4341,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
3950
4341
|
IonLabel,
|
|
3951
4342
|
IonText,
|
|
3952
4343
|
IonTextarea
|
|
3953
|
-
], 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"] }]
|
|
3954
4345
|
}], propDecorators: { operation: [{
|
|
3955
4346
|
type: Input,
|
|
3956
4347
|
args: [{ required: true }]
|
|
@@ -4049,15 +4440,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
4049
4440
|
type: Input
|
|
4050
4441
|
}], translatable: [{
|
|
4051
4442
|
type: Input
|
|
4052
|
-
}], handleFieldsetCreateGroupEvent: [{
|
|
4053
|
-
type: HostListener,
|
|
4054
|
-
args: ['window:fieldsetAddGroupEvent', ['$event']]
|
|
4055
4443
|
}], handleFieldsetUpdateGroupEvent: [{
|
|
4056
4444
|
type: HostListener,
|
|
4057
4445
|
args: ['window:fieldsetUpdateGroupEvent', ['$event']]
|
|
4058
|
-
}], handleFieldsetRemoveGroupEvent: [{
|
|
4059
|
-
type: HostListener,
|
|
4060
|
-
args: ['window:fieldsetRemoveGroupEvent', ['$event']]
|
|
4061
4446
|
}] } });
|
|
4062
4447
|
|
|
4063
4448
|
/**
|
|
@@ -4078,7 +4463,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
4078
4463
|
* @class NgxParentComponentDirective
|
|
4079
4464
|
* @extends {NgxParentComponentDirective}
|
|
4080
4465
|
* @implements {OnInit}
|
|
4081
|
-
* @memberOf NgxParentComponentDirective
|
|
4082
4466
|
*/
|
|
4083
4467
|
class NgxParentComponentDirective extends NgxDecafComponentDirective {
|
|
4084
4468
|
constructor() {
|
|
@@ -4091,7 +4475,6 @@ class NgxParentComponentDirective extends NgxDecafComponentDirective {
|
|
|
4091
4475
|
* page assignment, and display properties.
|
|
4092
4476
|
*
|
|
4093
4477
|
* @type {UIModelMetadata[]}
|
|
4094
|
-
* @memberOf NgxParentComponentDirective
|
|
4095
4478
|
*/
|
|
4096
4479
|
this.children = [];
|
|
4097
4480
|
/**
|
|
@@ -4103,7 +4486,6 @@ class NgxParentComponentDirective extends NgxDecafComponentDirective {
|
|
|
4103
4486
|
*
|
|
4104
4487
|
* @type {(number | string[])}
|
|
4105
4488
|
* @default 1
|
|
4106
|
-
* @memberOf NgxParentComponentDirective
|
|
4107
4489
|
*/
|
|
4108
4490
|
this.cols = 1;
|
|
4109
4491
|
/**
|
|
@@ -4114,7 +4496,6 @@ class NgxParentComponentDirective extends NgxDecafComponentDirective {
|
|
|
4114
4496
|
*
|
|
4115
4497
|
* @type {(number | string[])}
|
|
4116
4498
|
* @default 1
|
|
4117
|
-
* @memberOf NgxParentComponentDirective
|
|
4118
4499
|
*/
|
|
4119
4500
|
this.rows = 1;
|
|
4120
4501
|
}
|
|
@@ -4143,17 +4524,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4143
4524
|
constructor() {
|
|
4144
4525
|
super(...arguments);
|
|
4145
4526
|
this.crudFieldComponent = ComponentsTagNames.CRUD_FIELD;
|
|
4146
|
-
/**
|
|
4147
|
-
* @description Angular Location service.
|
|
4148
|
-
* @summary Injected service that provides access to the browser's URL and history.
|
|
4149
|
-
* This service is used for interacting with the browser's history API, allowing
|
|
4150
|
-
* for back navigation and URL manipulation outside of Angular's router.
|
|
4151
|
-
*
|
|
4152
|
-
* @private
|
|
4153
|
-
* @type {Location}
|
|
4154
|
-
* @memberOf CrudFormComponent
|
|
4155
|
-
*/
|
|
4156
|
-
this.location = inject(Location);
|
|
4157
4527
|
/**
|
|
4158
4528
|
* @description Field update trigger mode for form validation.
|
|
4159
4529
|
* @summary Determines when form field validation should be triggered. Options include
|
|
@@ -4162,7 +4532,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4162
4532
|
*
|
|
4163
4533
|
* @type {FieldUpdateMode}
|
|
4164
4534
|
* @default 'change'
|
|
4165
|
-
* @memberOf CrudFormComponent
|
|
4166
4535
|
*/
|
|
4167
4536
|
this.updateOn = 'change';
|
|
4168
4537
|
/**
|
|
@@ -4173,7 +4542,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4173
4542
|
*
|
|
4174
4543
|
* @type {HTMLFormTarget}
|
|
4175
4544
|
* @default '_self'
|
|
4176
|
-
* @memberOf CrudFormComponent
|
|
4177
4545
|
*/
|
|
4178
4546
|
this.target = '_self';
|
|
4179
4547
|
/**
|
|
@@ -4184,9 +4552,18 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4184
4552
|
*
|
|
4185
4553
|
* @type {'get' | 'post' | 'event'}
|
|
4186
4554
|
* @default 'event'
|
|
4187
|
-
* @memberOf CrudFormComponent
|
|
4188
4555
|
*/
|
|
4189
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;
|
|
4190
4567
|
/**
|
|
4191
4568
|
* @description Angular reactive FormGroup for form state management.
|
|
4192
4569
|
* @summary The FormGroup instance that manages all form controls, validation,
|
|
@@ -4194,7 +4571,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4194
4571
|
* controlling form behavior. May be undefined for read-only operations.
|
|
4195
4572
|
*
|
|
4196
4573
|
* @type {FormGroup | undefined}
|
|
4197
|
-
* @memberOf CrudFormComponent
|
|
4198
4574
|
*/
|
|
4199
4575
|
this.formGroup = undefined;
|
|
4200
4576
|
/**
|
|
@@ -4204,7 +4580,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4204
4580
|
* components. This enables decoupled handling of form submission logic.
|
|
4205
4581
|
*
|
|
4206
4582
|
* @type {EventEmitter<ICrudFormEvent>}
|
|
4207
|
-
* @memberOf CrudFormComponent
|
|
4208
4583
|
*/
|
|
4209
4584
|
this.submitEvent = new EventEmitter();
|
|
4210
4585
|
/**
|
|
@@ -4216,7 +4591,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4216
4591
|
*
|
|
4217
4592
|
* @type {string}
|
|
4218
4593
|
* @default Randomly generated 12-character string
|
|
4219
|
-
* @memberOf CrudFormComponent
|
|
4220
4594
|
*/
|
|
4221
4595
|
this.allowClear = true;
|
|
4222
4596
|
// /**
|
|
@@ -4252,18 +4626,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4252
4626
|
// * @memberOf CrudFormComponent
|
|
4253
4627
|
// */
|
|
4254
4628
|
// protected translateService: TranslateService = inject(TranslateService);
|
|
4255
|
-
/**
|
|
4256
|
-
* @description Reference to CRUD operation constants for template usage.
|
|
4257
|
-
* @summary Exposes the OperationKeys enum to the component template, enabling
|
|
4258
|
-
* conditional rendering and behavior based on operation types. This protected
|
|
4259
|
-
* readonly property ensures that template logic can access operation constants
|
|
4260
|
-
* while maintaining encapsulation and preventing accidental modification.
|
|
4261
|
-
*
|
|
4262
|
-
* @protected
|
|
4263
|
-
* @readonly
|
|
4264
|
-
* @memberOf CrudFormComponent
|
|
4265
|
-
*/
|
|
4266
|
-
this.OperationKeys = OperationKeys;
|
|
4267
4629
|
this.activeFormGroupIndex = 0;
|
|
4268
4630
|
}
|
|
4269
4631
|
get activeFormGroup() {
|
|
@@ -4277,13 +4639,13 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4277
4639
|
* form input. Configuration options are merged with default settings.
|
|
4278
4640
|
*
|
|
4279
4641
|
* @returns {Promise<void>}
|
|
4280
|
-
* @memberOf CrudFormComponent
|
|
4281
4642
|
*/
|
|
4282
4643
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
4283
4644
|
async ngOnInit(model) {
|
|
4284
4645
|
// dont call super.ngOnInit to model conflicts
|
|
4285
4646
|
if (this.operation === OperationKeys.READ || this.operation === OperationKeys.DELETE)
|
|
4286
4647
|
this.formGroup = undefined;
|
|
4648
|
+
this.initialized = true;
|
|
4287
4649
|
}
|
|
4288
4650
|
/**
|
|
4289
4651
|
* @description Component cleanup lifecycle method.
|
|
@@ -4292,7 +4654,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4292
4654
|
* and ensure proper resource cleanup.
|
|
4293
4655
|
*
|
|
4294
4656
|
* @returns {void}
|
|
4295
|
-
* @memberOf CrudFormComponent
|
|
4296
4657
|
*/
|
|
4297
4658
|
ngOnDestroy() {
|
|
4298
4659
|
if (this.formGroup)
|
|
@@ -4330,7 +4691,6 @@ class NgxFormDirective extends NgxParentComponentDirective {
|
|
|
4330
4691
|
* since these operations don't have modifiable form data to reset.
|
|
4331
4692
|
*
|
|
4332
4693
|
* @returns {void}
|
|
4333
|
-
* @memberOf CrudFormComponent
|
|
4334
4694
|
*/
|
|
4335
4695
|
handleReset() {
|
|
4336
4696
|
if (![OperationKeys.DELETE, OperationKeys.READ].includes(this.operation) && this.allowClear)
|
|
@@ -4554,8 +4914,7 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
|
|
|
4554
4914
|
* @memberOf LayoutComponent
|
|
4555
4915
|
*/
|
|
4556
4916
|
constructor() {
|
|
4557
|
-
super();
|
|
4558
|
-
this.initializeProps = true;
|
|
4917
|
+
super('LayoutComponent');
|
|
4559
4918
|
/**
|
|
4560
4919
|
* @description Media breakpoint for responsive behavior.
|
|
4561
4920
|
* @summary Determines the responsive breakpoint at which the layout should adapt.
|
|
@@ -4568,7 +4927,6 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
|
|
|
4568
4927
|
* @memberOf LayoutComponent
|
|
4569
4928
|
*/
|
|
4570
4929
|
this.gap = 'collapse';
|
|
4571
|
-
this.match = true;
|
|
4572
4930
|
/**
|
|
4573
4931
|
* @description Media breakpoint for responsive behavior.
|
|
4574
4932
|
* @summary Determines the responsive breakpoint at which the layout should adapt.
|
|
@@ -4581,7 +4939,30 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
|
|
|
4581
4939
|
* @memberOf LayoutComponent
|
|
4582
4940
|
*/
|
|
4583
4941
|
this.breakpoint = UIMediaBreakPoints.MEDIUM;
|
|
4584
|
-
|
|
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;
|
|
4585
4966
|
}
|
|
4586
4967
|
/**
|
|
4587
4968
|
* @description Getter that converts columns input to an array format.
|
|
@@ -4616,10 +4997,13 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
|
|
|
4616
4997
|
if (typeof rows === Primitives.NUMBER)
|
|
4617
4998
|
rows = Array.from({ length: Number(rows) }, () => ({ title: '' }));
|
|
4618
4999
|
return rows.map((row, index) => {
|
|
5000
|
+
const rowsLength = this.rows;
|
|
4619
5001
|
return {
|
|
4620
5002
|
title: typeof row === Primitives.STRING ? row : row?.['title'] || "",
|
|
4621
5003
|
cols: this.children.filter((child) => {
|
|
4622
|
-
|
|
5004
|
+
let row = child.props?.['row'] ?? 1;
|
|
5005
|
+
if (row > rowsLength)
|
|
5006
|
+
row = rowsLength;
|
|
4623
5007
|
child['col'] = child.props?.['col'] ?? this.cols?.length ?? 1;
|
|
4624
5008
|
if (row === index + 1)
|
|
4625
5009
|
return child;
|
|
@@ -4641,10 +5025,14 @@ let LayoutComponent = class LayoutComponent extends NgxParentComponentDirective
|
|
|
4641
5025
|
this.breakpoint = `@${this.breakpoint}`.toLowerCase();
|
|
4642
5026
|
this.cols = this._cols;
|
|
4643
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;
|
|
4644
5032
|
this.initialized = true;
|
|
4645
5033
|
}
|
|
4646
5034
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4647
|
-
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" }] }); }
|
|
4648
5036
|
};
|
|
4649
5037
|
LayoutComponent = __decorate([
|
|
4650
5038
|
Dynamic(),
|
|
@@ -4652,21 +5040,20 @@ LayoutComponent = __decorate([
|
|
|
4652
5040
|
], LayoutComponent);
|
|
4653
5041
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: LayoutComponent, decorators: [{
|
|
4654
5042
|
type: Component,
|
|
4655
|
-
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"] }]
|
|
4656
|
-
}], 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: [{
|
|
4657
5045
|
type: Input
|
|
4658
|
-
}],
|
|
5046
|
+
}], breakpoint: [{
|
|
4659
5047
|
type: Input
|
|
4660
|
-
}],
|
|
5048
|
+
}], grid: [{
|
|
4661
5049
|
type: Input
|
|
4662
|
-
}],
|
|
5050
|
+
}], match: [{
|
|
4663
5051
|
type: Input
|
|
4664
5052
|
}] } });
|
|
4665
5053
|
|
|
4666
5054
|
let CrudFormComponent = class CrudFormComponent extends NgxFormDirective {
|
|
4667
5055
|
constructor() {
|
|
4668
|
-
super();
|
|
4669
|
-
this.componentName = 'CrudFormComponent';
|
|
5056
|
+
super('CrudFormComponent');
|
|
4670
5057
|
}
|
|
4671
5058
|
/**
|
|
4672
5059
|
* @description Component initialization lifecycle method.
|
|
@@ -4679,7 +5066,6 @@ let CrudFormComponent = class CrudFormComponent extends NgxFormDirective {
|
|
|
4679
5066
|
* @memberOf CrudFormComponent
|
|
4680
5067
|
*/
|
|
4681
5068
|
async ngOnInit() {
|
|
4682
|
-
// console.log(this.formGroup);
|
|
4683
5069
|
this.options = Object.assign({}, DefaultFormReactiveOptions, this.options || {});
|
|
4684
5070
|
await super.ngOnInit();
|
|
4685
5071
|
}
|
|
@@ -4715,7 +5101,7 @@ let CrudFormComponent = class CrudFormComponent extends NgxFormDirective {
|
|
|
4715
5101
|
});
|
|
4716
5102
|
}
|
|
4717
5103
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CrudFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4718
|
-
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"] }] }); }
|
|
4719
5105
|
};
|
|
4720
5106
|
CrudFormComponent = __decorate([
|
|
4721
5107
|
Dynamic(),
|
|
@@ -4723,7 +5109,7 @@ CrudFormComponent = __decorate([
|
|
|
4723
5109
|
], CrudFormComponent);
|
|
4724
5110
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CrudFormComponent, decorators: [{
|
|
4725
5111
|
type: Component,
|
|
4726
|
-
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"] }]
|
|
4727
5113
|
}], ctorParameters: () => [] });
|
|
4728
5114
|
|
|
4729
5115
|
/**
|
|
@@ -4833,10 +5219,10 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxDecafComponentDir
|
|
|
4833
5219
|
* and this value should correspond to an available icon name.
|
|
4834
5220
|
*
|
|
4835
5221
|
* @type {string}
|
|
4836
|
-
* @default "
|
|
5222
|
+
* @default "folder-open-outline"
|
|
4837
5223
|
* @memberOf EmptyStateComponent
|
|
4838
5224
|
*/
|
|
4839
|
-
this.icon = "
|
|
5225
|
+
this.icon = "folder-open-outline";
|
|
4840
5226
|
/**
|
|
4841
5227
|
* @description The size of the displayed icon.
|
|
4842
5228
|
* @summary Controls the size of the icon shown in the empty state.
|
|
@@ -4889,6 +5275,7 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxDecafComponentDir
|
|
|
4889
5275
|
*/
|
|
4890
5276
|
this.buttonSize = 'default';
|
|
4891
5277
|
this.sanitizer = inject(DomSanitizer);
|
|
5278
|
+
this.enableCreationByModelRoute = false;
|
|
4892
5279
|
addIcons(allIcons);
|
|
4893
5280
|
}
|
|
4894
5281
|
/**
|
|
@@ -4921,15 +5308,12 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxDecafComponentDir
|
|
|
4921
5308
|
async ngOnInit() {
|
|
4922
5309
|
this.initialize();
|
|
4923
5310
|
this.showIcon = stringToBoolean(this.showIcon);
|
|
4924
|
-
// if(this.translatable) {
|
|
4925
|
-
// this.title = generateLocaleFromString(this.locale, this.title);
|
|
4926
|
-
// this.subtitle = generateLocaleFromString(this.locale, this.subtitle);
|
|
4927
|
-
// this.buttonText = generateLocaleFromString(this.locale, this.buttonText);
|
|
4928
|
-
// }
|
|
4929
5311
|
this.titleColor = `dcf-title color-${this.titleColor}`;
|
|
4930
5312
|
this.subtitleColor = `dcf-subtitle color-${this.titleColor}`;
|
|
4931
5313
|
if (this.searchValue)
|
|
4932
5314
|
this.searchSubtitle = await this.getSearchSubtitle(this.subtitle);
|
|
5315
|
+
if (!this.buttonLink && this.model && this.route)
|
|
5316
|
+
this.enableCreationByModelRoute = true;
|
|
4933
5317
|
}
|
|
4934
5318
|
/**
|
|
4935
5319
|
* @description Handles click events on the action button.
|
|
@@ -5001,7 +5385,7 @@ let EmptyStateComponent = class EmptyStateComponent extends NgxDecafComponentDir
|
|
|
5001
5385
|
return this.sanitizer.bypassSecurityTrustHtml(result);
|
|
5002
5386
|
}
|
|
5003
5387
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5004
|
-
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" }] }); }
|
|
5005
5389
|
};
|
|
5006
5390
|
EmptyStateComponent = __decorate([
|
|
5007
5391
|
Dynamic(),
|
|
@@ -5012,8 +5396,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
5012
5396
|
args: [{ selector: 'ngx-decaf-empty-state', standalone: true, imports: [
|
|
5013
5397
|
IonCard,
|
|
5014
5398
|
IonCardContent,
|
|
5015
|
-
IonIcon
|
|
5016
|
-
|
|
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"] }]
|
|
5017
5403
|
}], ctorParameters: () => [], propDecorators: { title: [{
|
|
5018
5404
|
type: Input
|
|
5019
5405
|
}], titleColor: [{
|
|
@@ -5244,11 +5630,6 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
|
|
|
5244
5630
|
return child;
|
|
5245
5631
|
});
|
|
5246
5632
|
}
|
|
5247
|
-
// if(this.model) {
|
|
5248
|
-
// this._repository = getModelRepository(this.model);
|
|
5249
|
-
// console.log(this._repository);
|
|
5250
|
-
// }
|
|
5251
|
-
// console.log(this._repository);
|
|
5252
5633
|
this.initialized = true;
|
|
5253
5634
|
}
|
|
5254
5635
|
/**
|
|
@@ -5346,13 +5727,8 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
|
|
|
5346
5727
|
async handleCreateItem(event) {
|
|
5347
5728
|
if (event && event instanceof CustomEvent)
|
|
5348
5729
|
event.stopImmediatePropagation();
|
|
5349
|
-
// if(this.updatingItem)
|
|
5350
|
-
// return this.handleUpdateItem(this.updatingItem.index, true);
|
|
5351
5730
|
const action = this.updatingItem ? OperationKeys.UPDATE : OperationKeys.CREATE;
|
|
5352
5731
|
const formGroup = this.activeFormGroup;
|
|
5353
|
-
// currentGroup.updateValueAndValidity();
|
|
5354
|
-
// console.log((currentGroup.parent as FormArray).value);
|
|
5355
|
-
const parent = formGroup.parent;
|
|
5356
5732
|
const isValid = NgxDecafFormService.validateFields(formGroup);
|
|
5357
5733
|
// must pass correct pk here
|
|
5358
5734
|
const isUnique = NgxDecafFormService.isUniqueOnGroup(formGroup, action, action === OperationKeys.UPDATE ? this.updatingItem?.index : undefined);
|
|
@@ -5371,68 +5747,13 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
|
|
|
5371
5747
|
value?.[this.pk] || undefined : value;
|
|
5372
5748
|
}
|
|
5373
5749
|
}
|
|
5374
|
-
// windowEventEmitter(EventConstants.FIELDSET_ADD_GROUP, {
|
|
5375
|
-
// formGroup: this.updatingItem ? this.updatingItem : this.formGroup
|
|
5376
|
-
// });
|
|
5377
|
-
// const formParent = this.formGroup as FormArray;
|
|
5378
|
-
// const index = formParent.length - 1;
|
|
5379
|
-
// const formGroup = formParent.at(index) as FormGroup;
|
|
5380
|
-
// console.log(formGroup.errors);
|
|
5381
|
-
// const isValid = NgxDecafFormService.validateFields(this.formGroup as FormGroup);
|
|
5382
|
-
// const isUnique = NgxDecafFormService.isUniqueOnGroup(formGroup, index, OperationKeys.CREATE);
|
|
5383
|
-
// const value = formGroup.value;
|
|
5384
|
-
// console.log(isValid, isUnique);
|
|
5385
|
-
// this.changeDetectorRef.detectChanges();
|
|
5386
|
-
// if(!Object.keys(this.mapper).length)
|
|
5387
|
-
// this.mapper = this.getMapper(value as KeyValue);
|
|
5388
|
-
// if(isValid && isUnique) {
|
|
5389
|
-
// this.isUniqueError = undefined;
|
|
5390
|
-
// this.buttonLabel = this.translateService.instant(this.locale + '.add');
|
|
5391
|
-
// this.setValue();
|
|
5392
|
-
// // const fb = NgxDecafFormService.addGroupToParent((this.formGroup as FormArray).root as FormGroup, this.childOf as string, formParent.length).parent as FormArray;
|
|
5393
|
-
// } else {
|
|
5394
|
-
// this.isUniqueError = typeof value === 'object' ? (value as KeyValue)?.[this.pk] || undefined : value;
|
|
5395
|
-
// }
|
|
5396
|
-
// console.log(this.formGroup);
|
|
5397
|
-
// if(event && event instanceof CustomEvent) {
|
|
5398
|
-
// event.stopImmediatePropagation();
|
|
5399
|
-
// const {formGroup, value, isValid} = event.detail;
|
|
5400
|
-
// this.formGroup = formGroup as FormArray;
|
|
5401
|
-
// if(!this.mapper)
|
|
5402
|
-
// this.mapper = this.getMapper(value as KeyValue);
|
|
5403
|
-
// if(isValid ){
|
|
5404
|
-
// this.isUniqueError = undefined;
|
|
5405
|
-
// this.buttonLabel = this.translateService.instant(this.locale + '.add');
|
|
5406
|
-
// this.setValue();
|
|
5407
|
-
// } else {
|
|
5408
|
-
// this.isUniqueError = (value as KeyValue)?.[this.pk] || undefined;
|
|
5409
|
-
// }
|
|
5410
|
-
// } else {
|
|
5411
|
-
// windowEventEmitter(EventConstants.FIELDSET_ADD_GROUP, {
|
|
5412
|
-
// component: this.component.nativeElement,
|
|
5413
|
-
// index: this.updatingItem ? this.updatingItem.index : this.value?.length,
|
|
5414
|
-
// parent: this.childOf,
|
|
5415
|
-
// operation: !this.updatingItem ? OperationKeys.CREATE : OperationKeys.UPDATE
|
|
5416
|
-
// });
|
|
5417
|
-
// }
|
|
5418
5750
|
}
|
|
5419
|
-
handleUpdateItem(index
|
|
5751
|
+
handleUpdateItem(index) {
|
|
5420
5752
|
const formGroup = this.getFormArrayIndex(index);
|
|
5421
5753
|
if (formGroup) {
|
|
5422
5754
|
this.updatingItem = Object.assign({}, formGroup.value || {}, { index });
|
|
5423
5755
|
this.activeFormGroupIndex = index;
|
|
5424
5756
|
}
|
|
5425
|
-
// this.changeDetectorRef.detectChanges();
|
|
5426
|
-
// const item = this.formGroup.controls.find(control => `${control.get(this.pk)?.value}`.toLowerCase() === cleanSpaces(`${value}`, true)) as FormControl;
|
|
5427
|
-
// if(item) {
|
|
5428
|
-
// this.buttonLabel = this.translateService.instant(this.locale + '.update');
|
|
5429
|
-
// this.updatingItem = Object.assign({}, item.value || {}, {index});
|
|
5430
|
-
// windowEventEmitter(EventConstants.FIELDSET_UPDATE_GROUP, {
|
|
5431
|
-
// parent: this.childOf,
|
|
5432
|
-
// component: this.component.nativeElement,
|
|
5433
|
-
// index: index
|
|
5434
|
-
// });
|
|
5435
|
-
// }
|
|
5436
5757
|
}
|
|
5437
5758
|
/**
|
|
5438
5759
|
* @description Cancels the update mode and resets the UI state.
|
|
@@ -5477,23 +5798,6 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
|
|
|
5477
5798
|
this.setValue();
|
|
5478
5799
|
if (this.activeFormGroupIndex > 0)
|
|
5479
5800
|
this.activeFormGroupIndex = this.activeFormGroupIndex - 1;
|
|
5480
|
-
// if(event && event instanceof CustomEvent) {
|
|
5481
|
-
// event.stopImmediatePropagation();
|
|
5482
|
-
// return this.setValue();
|
|
5483
|
-
// }
|
|
5484
|
-
// const formArray = this.formGroup as FormArray;
|
|
5485
|
-
// const arrayLength = formArray.length;
|
|
5486
|
-
// for (let index = arrayLength - 1; index >= 0; index--) {
|
|
5487
|
-
// const group = formArray.at(index) as FormGroup;
|
|
5488
|
-
// if (cleanSpaces(group.get(this.pk)?.value) === cleanSpaces(value as string)) {
|
|
5489
|
-
// windowEventEmitter(EventConstants.FIELDSET_REMOVE_GROUP, {
|
|
5490
|
-
// parent: this.childOf,
|
|
5491
|
-
// component: this.component.nativeElement,
|
|
5492
|
-
// index,
|
|
5493
|
-
// formGroup: group
|
|
5494
|
-
// });
|
|
5495
|
-
// }
|
|
5496
|
-
// }
|
|
5497
5801
|
}
|
|
5498
5802
|
/**
|
|
5499
5803
|
* @description Handles reordering of items within the fieldset list.
|
|
@@ -5620,16 +5924,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
|
|
|
5620
5924
|
index: index + 1
|
|
5621
5925
|
};
|
|
5622
5926
|
});
|
|
5623
|
-
// const inputContainers = this.component.nativeElement.querySelectorAll('.dcf-input-item');
|
|
5624
|
-
// inputContainers.forEach((container: HTMLElement) => {
|
|
5625
|
-
// const input = container.querySelector('input, ion-input, ion-textarea, textarea') as HTMLInputElement | null;
|
|
5626
|
-
// if(input)
|
|
5627
|
-
// input.value = '';
|
|
5628
|
-
// })
|
|
5629
5927
|
this.updatingItem = undefined;
|
|
5630
|
-
// console.log(this.isUniqueError);
|
|
5631
|
-
// console.log(this.mapper);
|
|
5632
|
-
// console.log(this.items);
|
|
5633
5928
|
}
|
|
5634
5929
|
/**
|
|
5635
5930
|
* @description Automatically configures the field mapping based on the value structure.
|
|
@@ -5661,7 +5956,7 @@ let FieldsetComponent = class FieldsetComponent extends NgxFormDirective {
|
|
|
5661
5956
|
return this.mapper;
|
|
5662
5957
|
}
|
|
5663
5958
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: FieldsetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5664
|
-
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" }] }); }
|
|
5665
5960
|
};
|
|
5666
5961
|
FieldsetComponent = __decorate([
|
|
5667
5962
|
Dynamic(),
|
|
@@ -5671,7 +5966,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
5671
5966
|
type: Component,
|
|
5672
5967
|
args: [{ standalone: true, selector: 'ngx-decaf-fieldset', schemas: [], imports: [
|
|
5673
5968
|
TranslatePipe,
|
|
5674
|
-
ComponentRendererComponent,
|
|
5675
5969
|
ReactiveFormsModule,
|
|
5676
5970
|
IonAccordionGroup,
|
|
5677
5971
|
IonAccordion,
|
|
@@ -5683,7 +5977,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
5683
5977
|
IonReorderGroup,
|
|
5684
5978
|
IonButton,
|
|
5685
5979
|
IonIcon,
|
|
5686
|
-
|
|
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"] }]
|
|
5687
5982
|
}], ctorParameters: () => [], propDecorators: { accordionComponent: [{
|
|
5688
5983
|
type: ViewChild,
|
|
5689
5984
|
args: ['accordionComponent', { static: false }]
|
|
@@ -7452,39 +7747,22 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
|
|
|
7452
7747
|
*/
|
|
7453
7748
|
this.disableSort = false;
|
|
7454
7749
|
/**
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
* title: 'empty.title',
|
|
7472
|
-
* subtitle: 'empty.subtitle',
|
|
7473
|
-
* showButton: false,
|
|
7474
|
-
* icon: 'alert-circle-outline',
|
|
7475
|
-
* buttonText: 'locale.empty.button',
|
|
7476
|
-
* link: ''
|
|
7477
|
-
* }
|
|
7478
|
-
* @memberOf ListComponent
|
|
7479
|
-
*/
|
|
7480
|
-
this.empty = {
|
|
7481
|
-
title: 'empty.title',
|
|
7482
|
-
subtitle: 'empty.subtitle',
|
|
7483
|
-
showButton: false,
|
|
7484
|
-
icon: 'alert-circle-outline',
|
|
7485
|
-
buttonText: 'locale.empty.button',
|
|
7486
|
-
link: ''
|
|
7487
|
-
};
|
|
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 = {};
|
|
7488
7766
|
/**
|
|
7489
7767
|
* @description The current page number in paginated mode.
|
|
7490
7768
|
* @summary Tracks which page is currently being displayed when the component
|
|
@@ -7516,6 +7794,7 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
|
|
|
7516
7794
|
* @memberOf ListComponent
|
|
7517
7795
|
*/
|
|
7518
7796
|
this.skeletonData = new Array(2);
|
|
7797
|
+
this.searching = false;
|
|
7519
7798
|
/**
|
|
7520
7799
|
* @description The last page number that was displayed.
|
|
7521
7800
|
* @summary Keeps track of the previously displayed page number, which is useful
|
|
@@ -7608,9 +7887,10 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
|
|
|
7608
7887
|
this.disableSort = stringToBoolean(this.disableSort);
|
|
7609
7888
|
if (typeof this.item?.['tag'] === 'boolean' && this.item?.['tag'] === true)
|
|
7610
7889
|
this.item['tag'] = ComponentsTagNames.LIST_ITEM;
|
|
7890
|
+
this.empty = Object.assign({}, DefaultListEmptyOptions, this.empty);
|
|
7611
7891
|
await this.refresh();
|
|
7612
|
-
if
|
|
7613
|
-
|
|
7892
|
+
// if(this.operations.includes(OperationKeys.CREATE) && this.route)
|
|
7893
|
+
// this.empty.link = `${this.route}/${OperationKeys.CREATE}`;
|
|
7614
7894
|
if (!this.initialized)
|
|
7615
7895
|
return this.parseProps(this);
|
|
7616
7896
|
this.initialized = true;
|
|
@@ -7781,6 +8061,7 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
|
|
|
7781
8061
|
* @memberOf ListComponent
|
|
7782
8062
|
*/
|
|
7783
8063
|
async handleSearch(value) {
|
|
8064
|
+
this.searching = value !== undefined;
|
|
7784
8065
|
if (this.type === ListComponentsTypes.INFINITE) {
|
|
7785
8066
|
this.loadMoreData = false;
|
|
7786
8067
|
if (value === undefined) {
|
|
@@ -8072,8 +8353,10 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
|
|
|
8072
8353
|
if (!this.indexes)
|
|
8073
8354
|
this.indexes = (Object.values(this.mapper) || [this.pk]);
|
|
8074
8355
|
const condition = this.parseConditions(this.searchValue);
|
|
8356
|
+
this.changeDetectorRef.detectChanges();
|
|
8075
8357
|
request = await this.parseResult(await repo.query(condition, (this.sortBy || this.pk), this.sortDirection));
|
|
8076
8358
|
data = [];
|
|
8359
|
+
this.changeDetectorRef.detectChanges();
|
|
8077
8360
|
}
|
|
8078
8361
|
data = this.type === ListComponentsTypes.INFINITE ? [...(data).concat(request)] : [...request];
|
|
8079
8362
|
}
|
|
@@ -8310,8 +8593,14 @@ let ListComponent = class ListComponent extends NgxDecafComponentDirective {
|
|
|
8310
8593
|
return accum;
|
|
8311
8594
|
}, []);
|
|
8312
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
|
+
}
|
|
8313
8602
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: ListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8314
|
-
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" }] }); }
|
|
8315
8604
|
};
|
|
8316
8605
|
ListComponent = __decorate([
|
|
8317
8606
|
Dynamic(),
|
|
@@ -8338,7 +8627,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
8338
8627
|
EmptyStateComponent,
|
|
8339
8628
|
FilterComponent,
|
|
8340
8629
|
ComponentRendererComponent
|
|
8341
|
-
], 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"] }]
|
|
8342
8631
|
}], ctorParameters: () => [], propDecorators: { type: [{
|
|
8343
8632
|
type: Input
|
|
8344
8633
|
}], showSearchbar: [{
|
|
@@ -8375,8 +8664,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
8375
8664
|
type: Input
|
|
8376
8665
|
}], disableSort: [{
|
|
8377
8666
|
type: Input
|
|
8378
|
-
}], emptyIcon: [{
|
|
8379
|
-
type: Input
|
|
8380
8667
|
}], empty: [{
|
|
8381
8668
|
type: Input
|
|
8382
8669
|
}], refreshEvent: [{
|
|
@@ -8891,17 +9178,6 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponent
|
|
|
8891
9178
|
* @memberOf SteppedFormComponent
|
|
8892
9179
|
*/
|
|
8893
9180
|
this.pagesArray = [];
|
|
8894
|
-
/**
|
|
8895
|
-
* @description Angular Location service.
|
|
8896
|
-
* @summary Injected service that provides access to the browser's URL and history.
|
|
8897
|
-
* This service is used for interacting with the browser's history API, allowing
|
|
8898
|
-
* for back navigation and URL manipulation outside of Angular's router.
|
|
8899
|
-
*
|
|
8900
|
-
* @private
|
|
8901
|
-
* @type {Location}
|
|
8902
|
-
* @memberOf CrudFormComponent
|
|
8903
|
-
*/
|
|
8904
|
-
this.location = inject(Location);
|
|
8905
9181
|
/**
|
|
8906
9182
|
* @description Event emitter for form submission.
|
|
8907
9183
|
* @summary Emits events when the form is submitted, typically on the last page
|
|
@@ -8937,12 +9213,16 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponent
|
|
|
8937
9213
|
* @memberOf SteppedFormComponent
|
|
8938
9214
|
*/
|
|
8939
9215
|
async ngOnInit() {
|
|
8940
|
-
console.log(this);
|
|
8941
9216
|
if (!this.locale)
|
|
8942
9217
|
this.locale = getLocaleContext("SteppedFormComponent");
|
|
8943
9218
|
this.activePage = this.startPage;
|
|
8944
|
-
if (
|
|
8945
|
-
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
|
+
}
|
|
8946
9226
|
this.pages = this.pageTitles.length;
|
|
8947
9227
|
if (this.paginated) {
|
|
8948
9228
|
this.children = [...this.children.map((c) => {
|
|
@@ -8968,6 +9248,7 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponent
|
|
|
8968
9248
|
});
|
|
8969
9249
|
this.activeFormGroup = this.formGroup;
|
|
8970
9250
|
}
|
|
9251
|
+
this.initialized = true;
|
|
8971
9252
|
}
|
|
8972
9253
|
/**
|
|
8973
9254
|
* @description Cleanup method called when the component is destroyed.
|
|
@@ -9086,9 +9367,7 @@ let SteppedFormComponent = class SteppedFormComponent extends NgxParentComponent
|
|
|
9086
9367
|
this.timerSubscription = timer(10).subscribe(() => this.activeChildren = this.children.filter(c => c.props?.['page'] === page));
|
|
9087
9368
|
}
|
|
9088
9369
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: SteppedFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9089
|
-
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" },
|
|
9090
|
-
// LayoutComponent,
|
|
9091
|
-
ComponentRendererComponent, selector: "ngx-decaf-component-renderer", inputs: ["tag", "globals", "children", "projectable", "model", "parentComponent", "parent"], outputs: ["listenEvent"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
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" }] }); }
|
|
9092
9371
|
};
|
|
9093
9372
|
SteppedFormComponent = __decorate([
|
|
9094
9373
|
Dynamic(),
|
|
@@ -9102,9 +9381,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
9102
9381
|
IonSkeletonText,
|
|
9103
9382
|
IonText,
|
|
9104
9383
|
IonButton,
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
], 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"] }]
|
|
9108
9386
|
}], ctorParameters: () => [], propDecorators: { children: [{
|
|
9109
9387
|
type: Input
|
|
9110
9388
|
}], paginated: [{
|
|
@@ -9278,5 +9556,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
|
|
|
9278
9556
|
* Generated bundle index. Do not edit.
|
|
9279
9557
|
*/
|
|
9280
9558
|
|
|
9281
|
-
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 };
|
|
9282
9560
|
//# sourceMappingURL=decaf-ts-for-angular.mjs.map
|