@ng-forge/dynamic-forms 0.5.1 → 0.5.2
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/ng-forge-dynamic-forms-integration.mjs +416 -23
- package/fesm2022/ng-forge-dynamic-forms-integration.mjs.map +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-BWFdMPyw.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-9JM7tFkl.mjs} +9313 -7122
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-9JM7tFkl.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-RN1hmG69.mjs → ng-forge-dynamic-forms-page-field.component-Bm1KS0M6.mjs} +9 -20
- package/fesm2022/ng-forge-dynamic-forms-page-field.component-Bm1KS0M6.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-text-field.component-DIVyioMX.mjs → ng-forge-dynamic-forms-text-field.component-DmJwXtzI.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-text-field.component-DIVyioMX.mjs.map → ng-forge-dynamic-forms-text-field.component-DmJwXtzI.mjs.map} +1 -1
- package/fesm2022/ng-forge-dynamic-forms.mjs +1 -1
- package/package.json +1 -1
- package/types/ng-forge-dynamic-forms-integration.d.ts +234 -17
- package/types/ng-forge-dynamic-forms.d.ts +1066 -509
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-BWFdMPyw.mjs.map +0 -1
- package/fesm2022/ng-forge-dynamic-forms-page-field.component-RN1hmG69.mjs.map +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as rxjs from 'rxjs';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
|
+
import * as _angular_core from '@angular/core';
|
|
4
|
+
import { Signal, Injector, WritableSignal, InjectionToken, Type, ResourceRef, Provider, EnvironmentProviders, PipeTransform } from '@angular/core';
|
|
3
5
|
import * as _angular_forms_signals from '@angular/forms/signals';
|
|
4
6
|
import { FieldTree, FieldContext, ValidationError as ValidationError$1, TreeValidationResult, SchemaPath, SchemaPathTree } from '@angular/forms/signals';
|
|
5
7
|
import * as _angular_forms from '@angular/forms';
|
|
6
8
|
import * as _ng_forge_dynamic_forms from '@ng-forge/dynamic-forms';
|
|
7
|
-
import * as _angular_core from '@angular/core';
|
|
8
|
-
import { Signal, Injector, WritableSignal, InjectionToken, Type, ResourceRef, OnDestroy, InputSignal, Provider, EnvironmentProviders, PipeTransform } from '@angular/core';
|
|
9
9
|
import { FormSchema } from '@ng-forge/dynamic-forms/schema';
|
|
10
10
|
|
|
11
11
|
type WithInputSignals<T> = {
|
|
@@ -578,51 +578,91 @@ type GroupAllowedChildren = LeafFieldTypes | RowField;
|
|
|
578
578
|
*/
|
|
579
579
|
type ArrayAllowedChildren = LeafFieldTypes | RowField | GroupField;
|
|
580
580
|
|
|
581
|
+
/**
|
|
582
|
+
* An array item template is an array of allowed children that defines one OBJECT array item's fields.
|
|
583
|
+
* Used for object arrays where each item is `{ key1: value1, key2: value2, ... }`.
|
|
584
|
+
*/
|
|
585
|
+
type ArrayItemTemplate$1 = readonly ArrayAllowedChildren[];
|
|
586
|
+
/**
|
|
587
|
+
* An array item definition can be either:
|
|
588
|
+
* - A single field (ArrayAllowedChildren) for PRIMITIVE array items - extracts field value directly
|
|
589
|
+
* - An array of fields (ArrayItemTemplate) for OBJECT array items - merges fields into object
|
|
590
|
+
*
|
|
591
|
+
* This allows support for:
|
|
592
|
+
* - Primitive arrays: `['tag1', 'tag2']`
|
|
593
|
+
* - Object arrays: `[{ name: 'Alice', email: '...' }]`
|
|
594
|
+
* - Heterogeneous arrays: `[{ value: 'x' }, 'y']` (mixed primitives and objects)
|
|
595
|
+
*/
|
|
596
|
+
type ArrayItemDefinition = ArrayAllowedChildren | ArrayItemTemplate$1;
|
|
581
597
|
/**
|
|
582
598
|
* Array field interface for creating dynamic field collections that map to array values.
|
|
583
599
|
*
|
|
584
600
|
* Key concepts:
|
|
585
|
-
* - The `fields` array defines
|
|
586
|
-
* -
|
|
587
|
-
*
|
|
588
|
-
*
|
|
601
|
+
* - The outer `fields` array defines INITIAL ITEMS (each element is one array item to render)
|
|
602
|
+
* - Each element can be either:
|
|
603
|
+
* - A single FieldDef (primitive item) - the field's value is extracted directly
|
|
604
|
+
* - An array of FieldDefs (object item) - fields are merged into an object
|
|
605
|
+
* - Items can have different field configurations (heterogeneous arrays supported)
|
|
606
|
+
* - Empty `fields: []` means no initial items - user adds via buttons with explicit templates
|
|
607
|
+
* - Initial values are declared via `value` property on each field definition
|
|
589
608
|
*
|
|
590
609
|
* @example
|
|
591
|
-
* // Primitive array
|
|
610
|
+
* // Primitive array: ['angular', 'typescript']
|
|
592
611
|
* {
|
|
593
612
|
* key: 'tags',
|
|
594
613
|
* type: 'array',
|
|
595
|
-
* fields: [
|
|
614
|
+
* fields: [
|
|
615
|
+
* { key: 'tag', type: 'input', value: 'angular' }, // Single field = primitive
|
|
616
|
+
* { key: 'tag', type: 'input', value: 'typescript' },
|
|
617
|
+
* ]
|
|
596
618
|
* }
|
|
597
|
-
* // Creates: { tags: ['tag1', 'tag2', 'tag3'] }
|
|
598
619
|
*
|
|
599
620
|
* @example
|
|
600
|
-
* // Object array
|
|
621
|
+
* // Object array: [{ name: 'Alice', email: '...' }]
|
|
601
622
|
* {
|
|
602
623
|
* key: 'contacts',
|
|
603
624
|
* type: 'array',
|
|
604
|
-
* fields: [
|
|
605
|
-
*
|
|
606
|
-
*
|
|
607
|
-
* { key: '
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
625
|
+
* fields: [
|
|
626
|
+
* [ // Array = object
|
|
627
|
+
* { key: 'name', type: 'input', value: 'Alice' },
|
|
628
|
+
* { key: 'email', type: 'input', value: 'alice@example.com' }
|
|
629
|
+
* ],
|
|
630
|
+
* ]
|
|
631
|
+
* }
|
|
632
|
+
*
|
|
633
|
+
* @example
|
|
634
|
+
* // Heterogeneous array: [{ label: 'Structured' }, 'Simple']
|
|
635
|
+
* {
|
|
636
|
+
* key: 'items',
|
|
637
|
+
* type: 'array',
|
|
638
|
+
* fields: [
|
|
639
|
+
* [{ key: 'label', type: 'input', value: 'Structured' }], // Object item
|
|
640
|
+
* { key: 'value', type: 'input', value: 'Simple' }, // Primitive item
|
|
641
|
+
* ]
|
|
642
|
+
* }
|
|
643
|
+
*
|
|
644
|
+
* @example
|
|
645
|
+
* // Empty array (add items via buttons)
|
|
646
|
+
* {
|
|
647
|
+
* key: 'tags',
|
|
648
|
+
* type: 'array',
|
|
649
|
+
* fields: [] // No initial items - user adds via button with template
|
|
611
650
|
* }
|
|
612
|
-
* // Creates: { contacts: [{name: '', email: ''}, {name: '', email: ''}] }
|
|
613
651
|
*
|
|
614
652
|
* Nesting constraints: Arrays can contain rows, leaf fields, or groups (for object arrays),
|
|
615
653
|
* but NOT pages or other arrays. Runtime validation enforces these rules.
|
|
616
654
|
*
|
|
617
655
|
* Note: Arrays are container fields and do not support `meta` since they have no native form element.
|
|
618
656
|
*/
|
|
619
|
-
interface ArrayField<TFields extends readonly
|
|
657
|
+
interface ArrayField<TFields extends readonly ArrayItemDefinition[] = readonly ArrayItemDefinition[]> extends FieldDef<never> {
|
|
620
658
|
type: 'array';
|
|
621
659
|
/**
|
|
622
|
-
*
|
|
623
|
-
*
|
|
624
|
-
* -
|
|
625
|
-
* -
|
|
660
|
+
* Array of item definitions. Each element defines one array item:
|
|
661
|
+
* - Single FieldDef = primitive item (field's value is extracted directly)
|
|
662
|
+
* - Array of FieldDefs = object item (fields are merged into an object)
|
|
663
|
+
* - Empty array `[]` = no initial items (add via buttons with explicit templates)
|
|
664
|
+
* - Items can have different configurations (heterogeneous arrays supported)
|
|
665
|
+
* - Initial values are set via `value` property on each field definition
|
|
626
666
|
*/
|
|
627
667
|
readonly fields: TFields;
|
|
628
668
|
/** Array fields do not have a label property **/
|
|
@@ -631,7 +671,9 @@ interface ArrayField<TFields extends readonly ArrayAllowedChildren[] = readonly
|
|
|
631
671
|
readonly meta?: never;
|
|
632
672
|
}
|
|
633
673
|
/**
|
|
634
|
-
* Type guard for ArrayField with proper type narrowing
|
|
674
|
+
* Type guard for ArrayField with proper type narrowing.
|
|
675
|
+
* Validates that the field is an array type with a fields property that is an array.
|
|
676
|
+
* Fields can contain either single FieldDefs (primitive items) or arrays of FieldDefs (object items).
|
|
635
677
|
*/
|
|
636
678
|
declare function isArrayField(field: FieldDef<any>): field is ArrayField;
|
|
637
679
|
|
|
@@ -1110,15 +1152,196 @@ interface DebouncedDerivationLogicConfig extends BaseDerivationLogicConfig {
|
|
|
1110
1152
|
* @public
|
|
1111
1153
|
*/
|
|
1112
1154
|
type DerivationLogicConfig = OnChangeDerivationLogicConfig | DebouncedDerivationLogicConfig;
|
|
1155
|
+
/**
|
|
1156
|
+
* Base configuration for property derivation logic.
|
|
1157
|
+
*
|
|
1158
|
+
* Property derivations compute values for field properties (like `minDate`, `options`,
|
|
1159
|
+
* `label`, `placeholder`) based on form values and external data. Unlike value derivations
|
|
1160
|
+
* which set the field's value, property derivations update component input properties.
|
|
1161
|
+
*
|
|
1162
|
+
* All property derivations are self-targeting: the logic is placed on the field whose
|
|
1163
|
+
* property should be derived.
|
|
1164
|
+
*
|
|
1165
|
+
* @internal
|
|
1166
|
+
*/
|
|
1167
|
+
interface BasePropertyDerivationLogicConfig {
|
|
1168
|
+
/**
|
|
1169
|
+
* Logic type identifier for property derivation.
|
|
1170
|
+
*/
|
|
1171
|
+
type: 'propertyDerivation';
|
|
1172
|
+
/**
|
|
1173
|
+
* The target property to set on the field component.
|
|
1174
|
+
*
|
|
1175
|
+
* **Depth limit (max 2 levels):** Only simple and single-dot-nested paths are
|
|
1176
|
+
* supported. Paths with 2+ dots (e.g., `'a.b.c'`) will throw a `DynamicFormError`
|
|
1177
|
+
* at runtime. This is an architectural constraint of the override merging strategy.
|
|
1178
|
+
*
|
|
1179
|
+
* Supported formats:
|
|
1180
|
+
* - Simple: `'minDate'`, `'options'`, `'label'`, `'placeholder'`
|
|
1181
|
+
* - Nested (1 dot): `'props.appearance'`, `'meta.autocomplete'`
|
|
1182
|
+
*
|
|
1183
|
+
* **Note:** There is no compile-time validation that the property name matches
|
|
1184
|
+
* an actual input on the field component. Typos will silently write to the
|
|
1185
|
+
* override store with no visible effect. A dev-mode warning is emitted when
|
|
1186
|
+
* the override key doesn't match any existing input property.
|
|
1187
|
+
*
|
|
1188
|
+
* @example
|
|
1189
|
+
* ```typescript
|
|
1190
|
+
* targetProperty: 'minDate' // ✅ Simple property
|
|
1191
|
+
* targetProperty: 'options' // ✅ Simple property
|
|
1192
|
+
* targetProperty: 'props.appearance' // ✅ Single-nested property
|
|
1193
|
+
* targetProperty: 'a.b.c' // ❌ Throws DynamicFormError (too deep)
|
|
1194
|
+
* ```
|
|
1195
|
+
*/
|
|
1196
|
+
targetProperty: string;
|
|
1197
|
+
/**
|
|
1198
|
+
* Optional name for this derivation for debugging purposes.
|
|
1199
|
+
*
|
|
1200
|
+
* When provided, this name appears in property derivation debug logs.
|
|
1201
|
+
*/
|
|
1202
|
+
debugName?: string;
|
|
1203
|
+
/**
|
|
1204
|
+
* Condition that determines when this property derivation applies.
|
|
1205
|
+
*
|
|
1206
|
+
* Defaults to `true` (always apply).
|
|
1207
|
+
*
|
|
1208
|
+
* Note: FormStateCondition is not supported for property derivations.
|
|
1209
|
+
*/
|
|
1210
|
+
condition?: ConditionalExpression | boolean;
|
|
1211
|
+
/**
|
|
1212
|
+
* Static value to set on the target property.
|
|
1213
|
+
*
|
|
1214
|
+
* Mutually exclusive with `expression` and `functionName`.
|
|
1215
|
+
*/
|
|
1216
|
+
value?: unknown;
|
|
1217
|
+
/**
|
|
1218
|
+
* JavaScript expression to evaluate for the derived property value.
|
|
1219
|
+
*
|
|
1220
|
+
* Has access to `formValue` object containing all form values.
|
|
1221
|
+
* For array fields, `formValue` is scoped to the current array item.
|
|
1222
|
+
*
|
|
1223
|
+
* Mutually exclusive with `value` and `functionName`.
|
|
1224
|
+
*
|
|
1225
|
+
* @example
|
|
1226
|
+
* ```typescript
|
|
1227
|
+
* expression: 'formValue.startDate'
|
|
1228
|
+
* expression: 'formValue.quantity > 10 ? "bulk" : "standard"'
|
|
1229
|
+
* ```
|
|
1230
|
+
*/
|
|
1231
|
+
expression?: string;
|
|
1232
|
+
/**
|
|
1233
|
+
* Name of a registered custom property derivation function.
|
|
1234
|
+
*
|
|
1235
|
+
* Register functions in `customFnConfig.propertyDerivations`.
|
|
1236
|
+
* Mutually exclusive with `value` and `expression`.
|
|
1237
|
+
*/
|
|
1238
|
+
functionName?: string;
|
|
1239
|
+
/**
|
|
1240
|
+
* Explicit field dependencies for property derivations.
|
|
1241
|
+
*
|
|
1242
|
+
* When using `functionName`, you can optionally specify which fields
|
|
1243
|
+
* the function depends on. If not provided with `functionName`, defaults
|
|
1244
|
+
* to all fields ('*').
|
|
1245
|
+
* For `expression`, dependencies are automatically extracted.
|
|
1246
|
+
* For `value`, no dependencies are needed (static value).
|
|
1247
|
+
*/
|
|
1248
|
+
dependsOn?: string[];
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Property derivation that evaluates immediately on change (default).
|
|
1252
|
+
*
|
|
1253
|
+
* @internal
|
|
1254
|
+
*/
|
|
1255
|
+
interface OnChangePropertyDerivationLogicConfig extends BasePropertyDerivationLogicConfig {
|
|
1256
|
+
/**
|
|
1257
|
+
* Trigger for immediate evaluation.
|
|
1258
|
+
* @default 'onChange'
|
|
1259
|
+
*/
|
|
1260
|
+
trigger?: 'onChange';
|
|
1261
|
+
/** Not allowed for onChange trigger */
|
|
1262
|
+
debounceMs?: never;
|
|
1263
|
+
}
|
|
1264
|
+
/**
|
|
1265
|
+
* Property derivation that evaluates after a debounce period.
|
|
1266
|
+
*
|
|
1267
|
+
* @internal
|
|
1268
|
+
*/
|
|
1269
|
+
interface DebouncedPropertyDerivationLogicConfig extends BasePropertyDerivationLogicConfig {
|
|
1270
|
+
/**
|
|
1271
|
+
* Trigger for debounced evaluation.
|
|
1272
|
+
*/
|
|
1273
|
+
trigger: 'debounced';
|
|
1274
|
+
/**
|
|
1275
|
+
* Debounce duration in milliseconds.
|
|
1276
|
+
* @default 500
|
|
1277
|
+
*/
|
|
1278
|
+
debounceMs?: number;
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Configuration for property derivation logic.
|
|
1282
|
+
*
|
|
1283
|
+
* Enables reactive derivation of field properties (like `minDate`, `options`,
|
|
1284
|
+
* `label`, `placeholder`) based on form values and external data.
|
|
1285
|
+
*
|
|
1286
|
+
* Property derivations are self-targeting: the logic is placed on the field
|
|
1287
|
+
* whose property should be derived.
|
|
1288
|
+
*
|
|
1289
|
+
* @example
|
|
1290
|
+
* ```typescript
|
|
1291
|
+
* // Derive endDate's minDate from startDate value
|
|
1292
|
+
* {
|
|
1293
|
+
* key: 'endDate',
|
|
1294
|
+
* type: 'datepicker',
|
|
1295
|
+
* logic: [{
|
|
1296
|
+
* type: 'propertyDerivation',
|
|
1297
|
+
* targetProperty: 'minDate',
|
|
1298
|
+
* expression: 'formValue.startDate'
|
|
1299
|
+
* }]
|
|
1300
|
+
* }
|
|
1301
|
+
*
|
|
1302
|
+
* // Derive options from another field's value
|
|
1303
|
+
* {
|
|
1304
|
+
* key: 'city',
|
|
1305
|
+
* type: 'select',
|
|
1306
|
+
* logic: [{
|
|
1307
|
+
* type: 'propertyDerivation',
|
|
1308
|
+
* targetProperty: 'options',
|
|
1309
|
+
* functionName: 'getCitiesForCountry',
|
|
1310
|
+
* dependsOn: ['country']
|
|
1311
|
+
* }]
|
|
1312
|
+
* }
|
|
1313
|
+
*
|
|
1314
|
+
* // Derive label conditionally
|
|
1315
|
+
* {
|
|
1316
|
+
* key: 'phone',
|
|
1317
|
+
* type: 'input',
|
|
1318
|
+
* logic: [{
|
|
1319
|
+
* type: 'propertyDerivation',
|
|
1320
|
+
* targetProperty: 'label',
|
|
1321
|
+
* value: 'Mobile Phone',
|
|
1322
|
+
* condition: {
|
|
1323
|
+
* type: 'fieldValue',
|
|
1324
|
+
* fieldPath: 'contactType',
|
|
1325
|
+
* operator: 'equals',
|
|
1326
|
+
* value: 'mobile'
|
|
1327
|
+
* }
|
|
1328
|
+
* }]
|
|
1329
|
+
* }
|
|
1330
|
+
* ```
|
|
1331
|
+
*
|
|
1332
|
+
* @public
|
|
1333
|
+
*/
|
|
1334
|
+
type PropertyDerivationLogicConfig = OnChangePropertyDerivationLogicConfig | DebouncedPropertyDerivationLogicConfig;
|
|
1113
1335
|
/**
|
|
1114
1336
|
* Union type for all logic configurations.
|
|
1115
1337
|
*
|
|
1116
1338
|
* - `StateLogicConfig`: For field state changes (hidden, readonly, disabled, required)
|
|
1117
1339
|
* - `DerivationLogicConfig`: For value derivation
|
|
1340
|
+
* - `PropertyDerivationLogicConfig`: For property derivation
|
|
1118
1341
|
*
|
|
1119
1342
|
* @public
|
|
1120
1343
|
*/
|
|
1121
|
-
type LogicConfig = StateLogicConfig | DerivationLogicConfig;
|
|
1344
|
+
type LogicConfig = StateLogicConfig | DerivationLogicConfig | PropertyDerivationLogicConfig;
|
|
1122
1345
|
/**
|
|
1123
1346
|
* Log level for derivation debug output.
|
|
1124
1347
|
*
|
|
@@ -1138,6 +1361,237 @@ type DerivationLogLevel = 'none' | 'summary' | 'verbose';
|
|
|
1138
1361
|
* @public
|
|
1139
1362
|
*/
|
|
1140
1363
|
declare function isFormStateCondition(condition: StateLogicConfig['condition'] | DerivationLogicConfig['condition']): condition is FormStateCondition;
|
|
1364
|
+
/**
|
|
1365
|
+
* Type guard to check if a logic config is a PropertyDerivationLogicConfig.
|
|
1366
|
+
*
|
|
1367
|
+
* @param config - The logic config to check
|
|
1368
|
+
* @returns true if the config is for property derivation
|
|
1369
|
+
*
|
|
1370
|
+
* @public
|
|
1371
|
+
*/
|
|
1372
|
+
declare function isPropertyDerivationLogicConfig(config: LogicConfig): config is PropertyDerivationLogicConfig;
|
|
1373
|
+
|
|
1374
|
+
/**
|
|
1375
|
+
* Interface for dynamic forms logger implementations.
|
|
1376
|
+
* Allows custom logging integrations (Sentry, DataDog, etc.)
|
|
1377
|
+
*/
|
|
1378
|
+
interface Logger {
|
|
1379
|
+
/**
|
|
1380
|
+
* Log a debug message.
|
|
1381
|
+
* Use for detailed diagnostic information during development.
|
|
1382
|
+
*/
|
|
1383
|
+
debug(message: string, ...args: unknown[]): void;
|
|
1384
|
+
/**
|
|
1385
|
+
* Log an info message.
|
|
1386
|
+
* Use for general operational information.
|
|
1387
|
+
*/
|
|
1388
|
+
info(message: string, ...args: unknown[]): void;
|
|
1389
|
+
/**
|
|
1390
|
+
* Log a warning message.
|
|
1391
|
+
* Use for potentially problematic situations that don't prevent operation.
|
|
1392
|
+
*/
|
|
1393
|
+
warn(message: string, ...args: unknown[]): void;
|
|
1394
|
+
/**
|
|
1395
|
+
* Log an error message.
|
|
1396
|
+
* Use for error conditions that may affect functionality.
|
|
1397
|
+
*/
|
|
1398
|
+
error(message: string, ...args: unknown[]): void;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
/**
|
|
1402
|
+
* Context for resolving button disabled state.
|
|
1403
|
+
*
|
|
1404
|
+
* @public
|
|
1405
|
+
*/
|
|
1406
|
+
interface ButtonLogicContext {
|
|
1407
|
+
/** The form's FieldTree instance (supports both string and number keys for array indices) */
|
|
1408
|
+
form: FieldTree<unknown, string | number>;
|
|
1409
|
+
/** Form-level options */
|
|
1410
|
+
formOptions?: FormOptions;
|
|
1411
|
+
/** Field-level logic array (if provided) */
|
|
1412
|
+
fieldLogic?: LogicConfig[];
|
|
1413
|
+
/** Explicit disabled state from field definition */
|
|
1414
|
+
explicitlyDisabled?: boolean;
|
|
1415
|
+
/** Current page validity signal (for paged forms) */
|
|
1416
|
+
currentPageValid?: Signal<boolean>;
|
|
1417
|
+
/** Current form value for evaluating conditional expressions */
|
|
1418
|
+
formValue?: unknown;
|
|
1419
|
+
/** Optional logger for diagnostic output. Falls back to no-op logger if not provided. */
|
|
1420
|
+
logger?: Logger;
|
|
1421
|
+
}
|
|
1422
|
+
/**
|
|
1423
|
+
* Allowed logic types for non-form-bound elements (buttons, text fields, etc.).
|
|
1424
|
+
* These elements only support hidden and disabled states - not readonly or required
|
|
1425
|
+
* since they don't participate in form validation.
|
|
1426
|
+
*
|
|
1427
|
+
* @public
|
|
1428
|
+
*/
|
|
1429
|
+
type NonFieldLogicType = 'hidden' | 'disabled';
|
|
1430
|
+
/**
|
|
1431
|
+
* Logic config restricted to types valid for non-form-bound elements.
|
|
1432
|
+
* This is a subset of LogicConfig that only includes hidden and disabled types.
|
|
1433
|
+
*
|
|
1434
|
+
* @public
|
|
1435
|
+
*/
|
|
1436
|
+
type NonFieldLogicConfig = LogicConfig & {
|
|
1437
|
+
type: NonFieldLogicType;
|
|
1438
|
+
};
|
|
1439
|
+
/**
|
|
1440
|
+
* Context for resolving state (hidden/disabled) for non-form-bound elements.
|
|
1441
|
+
*
|
|
1442
|
+
* This is a generalized context that can be used by any field mapper (buttons, text fields,
|
|
1443
|
+
* or any non-form-bound elements) to evaluate logic from a `logic` array.
|
|
1444
|
+
*
|
|
1445
|
+
* Note: While this context accepts the full `LogicConfig[]` for flexibility, the resolver
|
|
1446
|
+
* functions only process hidden and disabled types. Other logic types (readonly, required,
|
|
1447
|
+
* derivation) are ignored for non-form-bound elements.
|
|
1448
|
+
*
|
|
1449
|
+
* @public
|
|
1450
|
+
*/
|
|
1451
|
+
interface NonFieldLogicContext {
|
|
1452
|
+
/** The form's FieldTree instance (supports both string and number keys for array indices) */
|
|
1453
|
+
form: FieldTree<unknown, string | number>;
|
|
1454
|
+
/**
|
|
1455
|
+
* Field-level logic array containing conditions.
|
|
1456
|
+
* Accepts full LogicConfig[] for compatibility, but only hidden and disabled types are processed.
|
|
1457
|
+
*/
|
|
1458
|
+
fieldLogic?: LogicConfig[];
|
|
1459
|
+
/** Explicit state from field definition (e.g., `hidden: true` or `disabled: true`) */
|
|
1460
|
+
explicitValue?: boolean;
|
|
1461
|
+
/** Current form value for evaluating conditional expressions */
|
|
1462
|
+
formValue?: unknown;
|
|
1463
|
+
/** Optional logger for diagnostic output. Falls back to no-op logger if not provided. */
|
|
1464
|
+
logger?: Logger;
|
|
1465
|
+
}
|
|
1466
|
+
/**
|
|
1467
|
+
* Resolves the disabled state for a submit button.
|
|
1468
|
+
*
|
|
1469
|
+
* The disabled state is determined by (in order of precedence):
|
|
1470
|
+
* 1. Explicit `disabled: true` on the field definition
|
|
1471
|
+
* 2. Field-level `logic` array (if present, overrides form-level defaults)
|
|
1472
|
+
* 3. Form-level `options.submitButton` defaults
|
|
1473
|
+
*
|
|
1474
|
+
* @param ctx - The button logic context
|
|
1475
|
+
* @returns A computed signal that returns true when the button should be disabled
|
|
1476
|
+
*
|
|
1477
|
+
* @example
|
|
1478
|
+
* ```typescript
|
|
1479
|
+
* const disabled = resolveSubmitButtonDisabled({
|
|
1480
|
+
* form: formInstance,
|
|
1481
|
+
* formOptions: config.options,
|
|
1482
|
+
* fieldLogic: buttonField.logic,
|
|
1483
|
+
* explicitlyDisabled: buttonField.disabled,
|
|
1484
|
+
* });
|
|
1485
|
+
*
|
|
1486
|
+
* // Use in template
|
|
1487
|
+
* <button [disabled]="disabled()">Submit</button>
|
|
1488
|
+
* ```
|
|
1489
|
+
*
|
|
1490
|
+
* @public
|
|
1491
|
+
*/
|
|
1492
|
+
declare function resolveSubmitButtonDisabled(ctx: ButtonLogicContext): Signal<boolean>;
|
|
1493
|
+
/**
|
|
1494
|
+
* Resolves the disabled state for a next page button.
|
|
1495
|
+
*
|
|
1496
|
+
* The disabled state is determined by (in order of precedence):
|
|
1497
|
+
* 1. Explicit `disabled: true` on the field definition
|
|
1498
|
+
* 2. Field-level `logic` array (if present, overrides form-level defaults)
|
|
1499
|
+
* 3. Form-level `options.nextButton` defaults
|
|
1500
|
+
*
|
|
1501
|
+
* @param ctx - The button logic context
|
|
1502
|
+
* @returns A computed signal that returns true when the button should be disabled
|
|
1503
|
+
*
|
|
1504
|
+
* @example
|
|
1505
|
+
* ```typescript
|
|
1506
|
+
* const disabled = resolveNextButtonDisabled({
|
|
1507
|
+
* form: formInstance,
|
|
1508
|
+
* formOptions: config.options,
|
|
1509
|
+
* fieldLogic: buttonField.logic,
|
|
1510
|
+
* explicitlyDisabled: buttonField.disabled,
|
|
1511
|
+
* currentPageValid: pageOrchestrator.currentPageValid,
|
|
1512
|
+
* });
|
|
1513
|
+
* ```
|
|
1514
|
+
*
|
|
1515
|
+
* @public
|
|
1516
|
+
*/
|
|
1517
|
+
declare function resolveNextButtonDisabled(ctx: ButtonLogicContext): Signal<boolean>;
|
|
1518
|
+
/**
|
|
1519
|
+
* Resolves the hidden state for non-form-bound elements (buttons, text fields, etc.).
|
|
1520
|
+
*
|
|
1521
|
+
* This is a generalized function that can be used by any field mapper (buttons, text fields,
|
|
1522
|
+
* or any non-form-bound elements) to evaluate hidden logic. It's particularly useful for
|
|
1523
|
+
* elements that don't have a FieldTree but still need conditional visibility.
|
|
1524
|
+
*
|
|
1525
|
+
* The hidden state is determined by (in order of precedence):
|
|
1526
|
+
* 1. Explicit `hidden: true` on the field definition
|
|
1527
|
+
* 2. Field-level `logic` array with `type: 'hidden'` conditions
|
|
1528
|
+
*
|
|
1529
|
+
* @param ctx - The context containing form, logic array, and explicit hidden state
|
|
1530
|
+
* @returns A computed signal that returns true when the element should be hidden
|
|
1531
|
+
*
|
|
1532
|
+
* @example
|
|
1533
|
+
* ```typescript
|
|
1534
|
+
* // In an array button mapper
|
|
1535
|
+
* const hiddenSignal = resolveNonFieldHidden({
|
|
1536
|
+
* form: rootFormRegistry.getRootForm()!,
|
|
1537
|
+
* fieldLogic: buttonField.logic,
|
|
1538
|
+
* explicitValue: buttonField.hidden,
|
|
1539
|
+
* formValue: rootFormRegistry.getFormValue(),
|
|
1540
|
+
* });
|
|
1541
|
+
*
|
|
1542
|
+
* return computed(() => ({
|
|
1543
|
+
* ...baseInputs,
|
|
1544
|
+
* hidden: hiddenSignal(),
|
|
1545
|
+
* }));
|
|
1546
|
+
* ```
|
|
1547
|
+
*
|
|
1548
|
+
* @example
|
|
1549
|
+
* ```typescript
|
|
1550
|
+
* // In a text field mapper
|
|
1551
|
+
* const hiddenSignal = resolveNonFieldHidden({
|
|
1552
|
+
* form: rootFormRegistry.getRootForm()!,
|
|
1553
|
+
* fieldLogic: textField.logic,
|
|
1554
|
+
* explicitValue: textField.hidden,
|
|
1555
|
+
* formValue: rootFormRegistry.getFormValue(),
|
|
1556
|
+
* });
|
|
1557
|
+
* ```
|
|
1558
|
+
*
|
|
1559
|
+
* @public
|
|
1560
|
+
*/
|
|
1561
|
+
declare function resolveNonFieldHidden(ctx: NonFieldLogicContext): Signal<boolean>;
|
|
1562
|
+
/**
|
|
1563
|
+
* Resolves the disabled state for non-form-bound elements (buttons, text fields, etc.).
|
|
1564
|
+
*
|
|
1565
|
+
* This is a generalized function that can be used by any field mapper to evaluate
|
|
1566
|
+
* disabled logic. It handles elements that don't have form-level disabled defaults
|
|
1567
|
+
* (unlike submit/next buttons which have form-level config).
|
|
1568
|
+
*
|
|
1569
|
+
* The disabled state is determined by (in order of precedence):
|
|
1570
|
+
* 1. Explicit `disabled: true` on the field definition
|
|
1571
|
+
* 2. Field-level `logic` array with `type: 'disabled'` conditions
|
|
1572
|
+
*
|
|
1573
|
+
* @param ctx - The context containing form, logic array, and explicit disabled state
|
|
1574
|
+
* @returns A computed signal that returns true when the element should be disabled
|
|
1575
|
+
*
|
|
1576
|
+
* @example
|
|
1577
|
+
* ```typescript
|
|
1578
|
+
* // In an array button mapper
|
|
1579
|
+
* const disabledSignal = resolveNonFieldDisabled({
|
|
1580
|
+
* form: rootFormRegistry.getRootForm()!,
|
|
1581
|
+
* fieldLogic: buttonField.logic,
|
|
1582
|
+
* explicitValue: buttonField.disabled,
|
|
1583
|
+
* formValue: rootFormRegistry.getFormValue(),
|
|
1584
|
+
* });
|
|
1585
|
+
*
|
|
1586
|
+
* return computed(() => ({
|
|
1587
|
+
* ...baseInputs,
|
|
1588
|
+
* disabled: disabledSignal(),
|
|
1589
|
+
* }));
|
|
1590
|
+
* ```
|
|
1591
|
+
*
|
|
1592
|
+
* @public
|
|
1593
|
+
*/
|
|
1594
|
+
declare function resolveNonFieldDisabled(ctx: NonFieldLogicContext): Signal<boolean>;
|
|
1141
1595
|
|
|
1142
1596
|
/**
|
|
1143
1597
|
* Text element type for rendering different HTML text elements
|
|
@@ -1155,8 +1609,12 @@ type TextProps = {
|
|
|
1155
1609
|
*/
|
|
1156
1610
|
interface TextField extends FieldDef<TextProps> {
|
|
1157
1611
|
type: 'text';
|
|
1158
|
-
/**
|
|
1159
|
-
|
|
1612
|
+
/**
|
|
1613
|
+
* Logic rules for conditional visibility.
|
|
1614
|
+
* Text fields only support 'hidden' logic type since they are display-only
|
|
1615
|
+
* and don't participate in form validation (no disabled/readonly/required).
|
|
1616
|
+
*/
|
|
1617
|
+
readonly logic?: NonFieldLogicConfig[];
|
|
1160
1618
|
}
|
|
1161
1619
|
|
|
1162
1620
|
/**
|
|
@@ -1773,33 +2231,6 @@ interface HttpCustomValidator<TValue = unknown, TResult = unknown> {
|
|
|
1773
2231
|
readonly onError?: (error: unknown, ctx: FieldContext<TValue>) => ValidationError$1 | ValidationError$1[] | null;
|
|
1774
2232
|
}
|
|
1775
2233
|
|
|
1776
|
-
/**
|
|
1777
|
-
* Interface for dynamic forms logger implementations.
|
|
1778
|
-
* Allows custom logging integrations (Sentry, DataDog, etc.)
|
|
1779
|
-
*/
|
|
1780
|
-
interface Logger {
|
|
1781
|
-
/**
|
|
1782
|
-
* Log a debug message.
|
|
1783
|
-
* Use for detailed diagnostic information during development.
|
|
1784
|
-
*/
|
|
1785
|
-
debug(message: string, ...args: unknown[]): void;
|
|
1786
|
-
/**
|
|
1787
|
-
* Log an info message.
|
|
1788
|
-
* Use for general operational information.
|
|
1789
|
-
*/
|
|
1790
|
-
info(message: string, ...args: unknown[]): void;
|
|
1791
|
-
/**
|
|
1792
|
-
* Log a warning message.
|
|
1793
|
-
* Use for potentially problematic situations that don't prevent operation.
|
|
1794
|
-
*/
|
|
1795
|
-
warn(message: string, ...args: unknown[]): void;
|
|
1796
|
-
/**
|
|
1797
|
-
* Log an error message.
|
|
1798
|
-
* Use for error conditions that may affect functionality.
|
|
1799
|
-
*/
|
|
1800
|
-
error(message: string, ...args: unknown[]): void;
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
2234
|
interface EvaluationContext<TValue = unknown> {
|
|
1804
2235
|
/** Current field value */
|
|
1805
2236
|
fieldValue: TValue;
|
|
@@ -2421,6 +2852,46 @@ interface CustomFnConfig {
|
|
|
2421
2852
|
* ```
|
|
2422
2853
|
*/
|
|
2423
2854
|
derivations?: Record<string, CustomFunction>;
|
|
2855
|
+
/**
|
|
2856
|
+
* Custom property derivation functions for reactive property updates.
|
|
2857
|
+
*
|
|
2858
|
+
* These functions compute derived values for field properties (like `minDate`,
|
|
2859
|
+
* `options`, `label`, `placeholder`) and are called when a
|
|
2860
|
+
* `PropertyDerivationLogicConfig` references them by `functionName`.
|
|
2861
|
+
*
|
|
2862
|
+
* Property derivation functions:
|
|
2863
|
+
* - Receive an `EvaluationContext` with access to `formValue`
|
|
2864
|
+
* - Return the value to set on the target property
|
|
2865
|
+
* - Are called reactively when dependencies change
|
|
2866
|
+
*
|
|
2867
|
+
* @example
|
|
2868
|
+
* ```typescript
|
|
2869
|
+
* propertyDerivations: {
|
|
2870
|
+
* getCitiesForCountry: (context) => {
|
|
2871
|
+
* const countryCities: Record<string, Array<{ label: string; value: string }>> = {
|
|
2872
|
+
* 'USA': [{ label: 'New York', value: 'ny' }, { label: 'LA', value: 'la' }],
|
|
2873
|
+
* 'Germany': [{ label: 'Berlin', value: 'berlin' }, { label: 'Munich', value: 'munich' }],
|
|
2874
|
+
* };
|
|
2875
|
+
* return countryCities[context.formValue.country as string] ?? [];
|
|
2876
|
+
* },
|
|
2877
|
+
* }
|
|
2878
|
+
* ```
|
|
2879
|
+
*
|
|
2880
|
+
* Field configuration using a property derivation function:
|
|
2881
|
+
* ```typescript
|
|
2882
|
+
* {
|
|
2883
|
+
* key: 'city',
|
|
2884
|
+
* type: 'select',
|
|
2885
|
+
* logic: [{
|
|
2886
|
+
* type: 'propertyDerivation',
|
|
2887
|
+
* targetProperty: 'options',
|
|
2888
|
+
* functionName: 'getCitiesForCountry',
|
|
2889
|
+
* dependsOn: ['country']
|
|
2890
|
+
* }]
|
|
2891
|
+
* }
|
|
2892
|
+
* ```
|
|
2893
|
+
*/
|
|
2894
|
+
propertyDerivations?: Record<string, CustomFunction>;
|
|
2424
2895
|
/**
|
|
2425
2896
|
* Custom validators using Angular's public FieldContext API
|
|
2426
2897
|
*
|
|
@@ -2767,146 +3238,14 @@ interface FormModeDetectionResult {
|
|
|
2767
3238
|
}
|
|
2768
3239
|
|
|
2769
3240
|
/**
|
|
2770
|
-
*
|
|
2771
|
-
* Container fields have a 'fields' property and don't contribute values directly.
|
|
2772
|
-
* This overload works with RegisteredFieldTypes for full type narrowing.
|
|
2773
|
-
*/
|
|
2774
|
-
declare function isContainerField(field: RegisteredFieldTypes): field is ContainerFieldTypes;
|
|
2775
|
-
/**
|
|
2776
|
-
* Type guard to check if a field is a container field (page, row, group, or array).
|
|
2777
|
-
* This overload works with any FieldDef for looser type checking.
|
|
2778
|
-
*/
|
|
2779
|
-
declare function isContainerField(field: FieldDef<unknown>): boolean;
|
|
2780
|
-
/**
|
|
2781
|
-
* Type guard to check if a field is a leaf field (value or display field)
|
|
2782
|
-
* Leaf fields don't have children and either contribute values or display content
|
|
2783
|
-
*/
|
|
2784
|
-
declare function isLeafField(field: RegisteredFieldTypes): field is LeafFieldTypes;
|
|
2785
|
-
/**
|
|
2786
|
-
* Type guard to check if a field has a value property (value-bearing field)
|
|
2787
|
-
* These fields contribute to the form value output
|
|
2788
|
-
* Note: Using `unknown` in the Extract condition to match any value type
|
|
2789
|
-
*/
|
|
2790
|
-
declare function isValueBearingField(field: RegisteredFieldTypes): field is Extract<RegisteredFieldTypes, {
|
|
2791
|
-
value: unknown;
|
|
2792
|
-
}>;
|
|
2793
|
-
/**
|
|
2794
|
-
* Type guard to check if a field is excluded from form values (display-only field)
|
|
2795
|
-
* Currently this includes text fields and any other fields without a value property
|
|
2796
|
-
*/
|
|
2797
|
-
declare function isDisplayOnlyField(field: RegisteredFieldTypes): boolean;
|
|
2798
|
-
|
|
2799
|
-
/**
|
|
2800
|
-
* Helper types for creating type-safe field configurations with proper nesting constraints
|
|
2801
|
-
*/
|
|
2802
|
-
|
|
2803
|
-
/**
|
|
2804
|
-
* Type helper for accessing nested field paths safely
|
|
2805
|
-
* This allows accessing child paths while maintaining some type safety
|
|
2806
|
-
*/
|
|
2807
|
-
type FieldPathAccess<TValue> = {
|
|
2808
|
-
[K in keyof TValue]: SchemaPath<TValue[K]> | SchemaPathTree<TValue[K]>;
|
|
2809
|
-
};
|
|
2810
|
-
|
|
2811
|
-
/**
|
|
2812
|
-
* Result of processing all pending derivations.
|
|
2813
|
-
*
|
|
2814
|
-
* @public
|
|
2815
|
-
*/
|
|
2816
|
-
interface DerivationProcessingResult {
|
|
2817
|
-
/** Number of derivations successfully applied */
|
|
2818
|
-
appliedCount: number;
|
|
2819
|
-
/** Number of derivations skipped (condition not met or value unchanged) */
|
|
2820
|
-
skippedCount: number;
|
|
2821
|
-
/** Number of derivations that failed with errors */
|
|
2822
|
-
errorCount: number;
|
|
2823
|
-
/**
|
|
2824
|
-
* Number of derivations that encountered warnings (e.g., missing target field).
|
|
2825
|
-
*
|
|
2826
|
-
* These are not counted as errors because they may be intentional (conditional fields)
|
|
2827
|
-
* but indicate potential configuration issues if unexpected.
|
|
2828
|
-
*/
|
|
2829
|
-
warnCount: number;
|
|
2830
|
-
/** Total iterations performed */
|
|
2831
|
-
iterations: number;
|
|
2832
|
-
/** Whether max iterations was reached (potential loop) */
|
|
2833
|
-
maxIterationsReached: boolean;
|
|
2834
|
-
}
|
|
2835
|
-
|
|
2836
|
-
/**
|
|
2837
|
-
* Information about a single derivation evaluation for logging.
|
|
3241
|
+
* Error from async field component loading.
|
|
2838
3242
|
*
|
|
2839
3243
|
* @public
|
|
2840
3244
|
*/
|
|
2841
|
-
interface
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
fieldKey: string;
|
|
2846
|
-
/** Result of the derivation evaluation */
|
|
2847
|
-
result: 'applied' | 'skipped' | 'error';
|
|
2848
|
-
/** Reason for skipping (if result is 'skipped') */
|
|
2849
|
-
skipReason?: 'condition-false' | 'value-unchanged' | 'already-applied' | 'target-not-found';
|
|
2850
|
-
/** The new value that was set (if result is 'applied') */
|
|
2851
|
-
newValue?: unknown;
|
|
2852
|
-
/** The previous value before the derivation (if result is 'applied') */
|
|
2853
|
-
previousValue?: unknown;
|
|
2854
|
-
/** Error message (if result is 'error') */
|
|
2855
|
-
error?: string;
|
|
2856
|
-
/** Duration in milliseconds (optional, for performance tracking) */
|
|
2857
|
-
durationMs?: number;
|
|
2858
|
-
}
|
|
2859
|
-
|
|
2860
|
-
/**
|
|
2861
|
-
* Service interface for derivation logging.
|
|
2862
|
-
*
|
|
2863
|
-
* Provides methods to log derivation processing events at different verbosity levels.
|
|
2864
|
-
* Use `DERIVATION_LOGGER` injection token to get an instance.
|
|
2865
|
-
*
|
|
2866
|
-
* @public
|
|
2867
|
-
*/
|
|
2868
|
-
interface DerivationLogger {
|
|
2869
|
-
/**
|
|
2870
|
-
* Logs the start of a derivation processing cycle.
|
|
2871
|
-
* Only logs when config level is 'verbose'.
|
|
2872
|
-
*/
|
|
2873
|
-
cycleStart(trigger: 'onChange' | 'debounced', entryCount: number): void;
|
|
2874
|
-
/**
|
|
2875
|
-
* Logs the start of a derivation iteration within a cycle.
|
|
2876
|
-
* Only logs when config level is 'verbose'.
|
|
2877
|
-
*/
|
|
2878
|
-
iteration(iterationNumber: number): void;
|
|
2879
|
-
/**
|
|
2880
|
-
* Logs a single derivation evaluation result.
|
|
2881
|
-
* Only logs when config level is 'verbose'.
|
|
2882
|
-
*/
|
|
2883
|
-
evaluation(entry: DerivationLogEntry): void;
|
|
2884
|
-
/**
|
|
2885
|
-
* Logs a summary of derivation processing results.
|
|
2886
|
-
* Logs when config level is 'summary' or 'verbose' and something interesting happened.
|
|
2887
|
-
*/
|
|
2888
|
-
summary(result: DerivationProcessingResult, trigger: 'onChange' | 'debounced'): void;
|
|
2889
|
-
/**
|
|
2890
|
-
* Logs when max iterations are reached (always logged as warning).
|
|
2891
|
-
*/
|
|
2892
|
-
maxIterationsReached(result: DerivationProcessingResult, trigger: 'onChange' | 'debounced'): void;
|
|
2893
|
-
}
|
|
2894
|
-
|
|
2895
|
-
/**
|
|
2896
|
-
* Minimal configuration for creating a DerivationOrchestrator.
|
|
2897
|
-
* Only includes form-specific signals that cannot be injected.
|
|
2898
|
-
*
|
|
2899
|
-
* @internal
|
|
2900
|
-
*/
|
|
2901
|
-
interface DerivationOrchestratorConfig {
|
|
2902
|
-
/** Signal containing the flattened schema fields */
|
|
2903
|
-
schemaFields: Signal<FieldDef<unknown>[] | undefined>;
|
|
2904
|
-
/** Signal containing the current form value */
|
|
2905
|
-
formValue: Signal<Record<string, unknown>>;
|
|
2906
|
-
/** Signal containing the form accessor */
|
|
2907
|
-
form: Signal<FieldTree<unknown>>;
|
|
2908
|
-
/** Signal containing the derivation logger */
|
|
2909
|
-
derivationLogger: Signal<DerivationLogger>;
|
|
3245
|
+
interface FieldLoadingError {
|
|
3246
|
+
readonly fieldType: string;
|
|
3247
|
+
readonly fieldKey: string;
|
|
3248
|
+
readonly error: Error;
|
|
2910
3249
|
}
|
|
2911
3250
|
|
|
2912
3251
|
/**
|
|
@@ -3072,108 +3411,85 @@ declare class PageNavigationStateChangeEvent implements FormEvent {
|
|
|
3072
3411
|
}
|
|
3073
3412
|
|
|
3074
3413
|
/**
|
|
3075
|
-
* Dynamic form component
|
|
3076
|
-
*
|
|
3077
|
-
* This is the main entry point for the dynamic form system. It handles form state management,
|
|
3078
|
-
* validation, field rendering, and event coordination using Angular's signal-based reactive forms.
|
|
3079
|
-
*
|
|
3080
|
-
* @typeParam TFields - Array of registered field types available for this form
|
|
3081
|
-
* @typeParam TModel - The strongly-typed interface for form values
|
|
3414
|
+
* Dynamic form component — renders a form based on configuration.
|
|
3415
|
+
* Delegates state management to `FormStateManager`.
|
|
3082
3416
|
*
|
|
3083
3417
|
* @example
|
|
3084
3418
|
*```html
|
|
3085
|
-
* <form
|
|
3086
|
-
* [dynamic-form]="formConfig"
|
|
3087
|
-
* [(value)]="formData"
|
|
3088
|
-
* (submitted)="handleSubmit($event)"
|
|
3089
|
-
* (validityChange)="handleValidityChange($event)">
|
|
3090
|
-
* </form>
|
|
3419
|
+
* <form [dynamic-form]="formConfig" [(value)]="formData" (submitted)="handleSubmit($event)"></form>
|
|
3091
3420
|
* ```
|
|
3092
3421
|
*/
|
|
3093
|
-
declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFieldTypes[], TModel extends Record<string, unknown> = InferFormValue$1<TFields> & Record<string, unknown>>
|
|
3094
|
-
private readonly destroyRef;
|
|
3095
|
-
private readonly fieldRegistry;
|
|
3096
|
-
private readonly injector;
|
|
3097
|
-
private readonly eventBus;
|
|
3098
|
-
private readonly rootFormRegistry;
|
|
3099
|
-
private readonly functionRegistry;
|
|
3100
|
-
private readonly schemaRegistry;
|
|
3101
|
-
private readonly logger;
|
|
3102
|
-
private readonly derivationLogConfig;
|
|
3422
|
+
declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFieldTypes[], TModel extends Record<string, unknown> = InferFormValue$1<TFields> & Record<string, unknown>> {
|
|
3103
3423
|
/** Form configuration defining the structure, validation, and behavior. */
|
|
3104
|
-
config: InputSignal<FormConfig<TFields>>;
|
|
3424
|
+
config: _angular_core.InputSignal<FormConfig<TFields, InferFormValue$1<TFields extends readonly RegisteredFieldTypes[] ? TFields : RegisteredFieldTypes[]>, Record<string, unknown>, unknown>>;
|
|
3105
3425
|
/** Runtime form options that override config options when provided. */
|
|
3106
|
-
formOptions: InputSignal<FormOptions | undefined>;
|
|
3426
|
+
formOptions: _angular_core.InputSignal<FormOptions | undefined>;
|
|
3107
3427
|
/** Form values for two-way data binding. */
|
|
3108
3428
|
value: _angular_core.ModelSignal<Partial<TModel> | undefined>;
|
|
3109
|
-
private
|
|
3110
|
-
private
|
|
3111
|
-
private
|
|
3112
|
-
private
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3429
|
+
private destroyRef;
|
|
3430
|
+
private injector;
|
|
3431
|
+
private eventBus;
|
|
3432
|
+
private logger;
|
|
3433
|
+
/**
|
|
3434
|
+
* Connect input signals to the shared deps holder BEFORE injecting FormStateManager.
|
|
3435
|
+
* Field initializers run in declaration order, so this runs after inputs are created
|
|
3436
|
+
* but before stateManager is injected. FormStateManager reads from these signals
|
|
3437
|
+
* in computeds/effects, which are all lazy and evaluated after construction.
|
|
3438
|
+
*/
|
|
3439
|
+
private readonly _connectStateDeps;
|
|
3440
|
+
/** State manager that owns all form state. */
|
|
3441
|
+
private stateManager;
|
|
3442
|
+
private componentId;
|
|
3443
|
+
/** The currently active config used for form rendering */
|
|
3444
|
+
activeConfig: Signal<FormConfig<TFields, InferFormValue$1<TFields extends readonly RegisteredFieldTypes[] ? TFields : RegisteredFieldTypes[]>, Record<string, unknown>, unknown> | undefined>;
|
|
3445
|
+
/** Current render phase: 'render' = showing form, 'teardown' = hiding old components */
|
|
3446
|
+
renderPhase: Signal<"teardown" | "render">;
|
|
3447
|
+
/** Computed form mode detection with validation */
|
|
3448
|
+
formModeDetection: Signal<_ng_forge_dynamic_forms.FormModeDetectionResult>;
|
|
3449
|
+
/** Page field definitions for paged forms */
|
|
3450
|
+
pageFieldDefinitions: Signal<_ng_forge_dynamic_forms.PageField<_ng_forge_dynamic_forms.PageAllowedChildren[]>[]>;
|
|
3451
|
+
/** Effective form options (merged from config and input) */
|
|
3452
|
+
effectiveFormOptions: Signal<{
|
|
3118
3453
|
disabled?: boolean;
|
|
3119
3454
|
maxDerivationIterations?: number;
|
|
3120
3455
|
submitButton?: _ng_forge_dynamic_forms.SubmitButtonOptions;
|
|
3121
3456
|
nextButton?: _ng_forge_dynamic_forms.NextButtonOptions;
|
|
3122
3457
|
emitFormValueOnEvents?: boolean;
|
|
3123
3458
|
}>;
|
|
3124
|
-
/**
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
/**
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
readonly invalid: Signal<boolean>;
|
|
3155
|
-
/** Whether any form field has been modified. */
|
|
3156
|
-
readonly dirty: Signal<boolean>;
|
|
3157
|
-
/** Whether any form field has been touched (blurred). */
|
|
3158
|
-
readonly touched: Signal<boolean>;
|
|
3159
|
-
/** Current validation errors from all fields. */
|
|
3160
|
-
readonly errors: Signal<_angular_forms_signals.ValidationError.WithField[]>;
|
|
3161
|
-
/** Whether the form is disabled (from options or form state). */
|
|
3162
|
-
readonly disabled: Signal<boolean>;
|
|
3163
|
-
/** Whether the form is currently submitting. */
|
|
3164
|
-
readonly submitting: Signal<boolean>;
|
|
3165
|
-
/**
|
|
3166
|
-
* Configuration for the derivation orchestrator.
|
|
3167
|
-
* Bundles the form-specific signals needed by the orchestrator.
|
|
3168
|
-
*
|
|
3169
|
-
* @internal Used by DERIVATION_ORCHESTRATOR provider.
|
|
3170
|
-
*/
|
|
3171
|
-
readonly derivationOrchestratorConfig: DerivationOrchestratorConfig;
|
|
3172
|
-
readonly initialized$: rxjs.Observable<boolean>;
|
|
3459
|
+
/** Field signal context for injection into child components */
|
|
3460
|
+
fieldSignalContext: Signal<_ng_forge_dynamic_forms.FieldSignalContext<TModel>>;
|
|
3461
|
+
/** Default values computed from field definitions */
|
|
3462
|
+
defaultValues: WritableSignal<TModel>;
|
|
3463
|
+
/** The Angular Signal Form instance */
|
|
3464
|
+
form: Signal<FieldTree<TModel, string | number>>;
|
|
3465
|
+
/** Current form values (reactive) */
|
|
3466
|
+
formValue: Signal<TModel | (TModel extends infer T ? T extends TModel ? T extends _angular_forms.AbstractControl<unknown, infer TValue extends unknown, any> ? TValue : never : never : never)>;
|
|
3467
|
+
/** Whether the form is currently valid */
|
|
3468
|
+
valid: Signal<boolean>;
|
|
3469
|
+
/** Whether the form is currently invalid */
|
|
3470
|
+
invalid: Signal<boolean>;
|
|
3471
|
+
/** Whether any form field has been modified */
|
|
3472
|
+
dirty: Signal<boolean>;
|
|
3473
|
+
/** Whether any form field has been touched (blurred) */
|
|
3474
|
+
touched: Signal<boolean>;
|
|
3475
|
+
/** Current validation errors from all fields */
|
|
3476
|
+
errors: Signal<_angular_forms_signals.ValidationError.WithField[]>;
|
|
3477
|
+
/** Whether the form is disabled (from options or form state) */
|
|
3478
|
+
disabled: Signal<boolean>;
|
|
3479
|
+
/** Whether the form is currently submitting */
|
|
3480
|
+
submitting: Signal<boolean>;
|
|
3481
|
+
/** Collects errors from async field component loading for error boundary patterns */
|
|
3482
|
+
fieldLoadingErrors: WritableSignal<FieldLoadingError[]>;
|
|
3483
|
+
/** Whether to render the form template */
|
|
3484
|
+
shouldRender: Signal<boolean>;
|
|
3485
|
+
/** Resolved fields ready for rendering */
|
|
3486
|
+
protected resolvedFields: Signal<ResolvedField[]>;
|
|
3487
|
+
private totalComponentsCount;
|
|
3488
|
+
initialized$: rxjs.Observable<boolean>;
|
|
3173
3489
|
/** Emits when form validity changes. */
|
|
3174
|
-
|
|
3490
|
+
validityChange: _angular_core.OutputRef<boolean>;
|
|
3175
3491
|
/** Emits when form dirty state changes. */
|
|
3176
|
-
|
|
3492
|
+
dirtyChange: _angular_core.OutputRef<boolean>;
|
|
3177
3493
|
/**
|
|
3178
3494
|
* Emits form values when submitted (via SubmitEvent) and form is valid.
|
|
3179
3495
|
*
|
|
@@ -3183,23 +3499,22 @@ declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFie
|
|
|
3183
3499
|
*
|
|
3184
3500
|
* Note: Does not emit when `submission.action` is configured - use one or the other.
|
|
3185
3501
|
*/
|
|
3186
|
-
|
|
3502
|
+
submitted: _angular_core.OutputRef<Partial<TModel>>;
|
|
3187
3503
|
/** Emits when form is reset to default values. */
|
|
3188
|
-
|
|
3504
|
+
reset: _angular_core.OutputRef<FormResetEvent>;
|
|
3189
3505
|
/** Emits when form is cleared to empty state. */
|
|
3190
|
-
|
|
3506
|
+
cleared: _angular_core.OutputRef<FormClearEvent>;
|
|
3191
3507
|
/** Emits all form events for custom event handling. */
|
|
3192
|
-
|
|
3508
|
+
events: _angular_core.OutputRef<_ng_forge_dynamic_forms.FormEvent>;
|
|
3193
3509
|
/**
|
|
3194
3510
|
* Emits when all form components are initialized and ready for interaction.
|
|
3195
3511
|
* Useful for E2E testing to ensure the form is fully rendered before interaction.
|
|
3196
3512
|
*/
|
|
3197
|
-
|
|
3513
|
+
initialized: _angular_core.OutputRef<boolean>;
|
|
3198
3514
|
/** Emits when the current page changes in paged forms. */
|
|
3199
|
-
|
|
3515
|
+
onPageChange: _angular_core.OutputRef<PageChangeEvent>;
|
|
3200
3516
|
/** Emits when page navigation state changes (canGoNext, canGoPrevious, etc.). */
|
|
3201
|
-
|
|
3202
|
-
protected readonly resolvedFields: Signal<ResolvedField[]>;
|
|
3517
|
+
onPageNavigationStateChange: _angular_core.OutputRef<PageNavigationStateChangeEvent>;
|
|
3203
3518
|
constructor();
|
|
3204
3519
|
/**
|
|
3205
3520
|
* Handles native form submission triggered by:
|
|
@@ -3215,12 +3530,6 @@ declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFie
|
|
|
3215
3530
|
protected onNativeSubmit(event: Event): void;
|
|
3216
3531
|
private setupEffects;
|
|
3217
3532
|
private setupEventHandlers;
|
|
3218
|
-
private registerValidatorsFromConfig;
|
|
3219
|
-
private createFormSetupFromConfig;
|
|
3220
|
-
private createEmptyFormSetup;
|
|
3221
|
-
private onFormReset;
|
|
3222
|
-
private onFormClear;
|
|
3223
|
-
ngOnDestroy(): void;
|
|
3224
3533
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DynamicForm<any, any>, never>;
|
|
3225
3534
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DynamicForm<any, any>, "form[dynamic-form]", never, { "config": { "alias": "dynamic-form"; "required": true; "isSignal": true; }; "formOptions": { "alias": "formOptions"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "validityChange": "validityChange"; "dirtyChange": "dirtyChange"; "submitted": "submitted"; "reset": "reset"; "cleared": "cleared"; "events": "events"; "initialized": "initialized"; "onPageChange": "onPageChange"; "onPageNavigationStateChange": "onPageNavigationStateChange"; }, never, never, true, never>;
|
|
3226
3535
|
}
|
|
@@ -3239,6 +3548,48 @@ interface DynamicFormFeature<TKind extends string = string> {
|
|
|
3239
3548
|
ɵproviders: Provider[];
|
|
3240
3549
|
}
|
|
3241
3550
|
|
|
3551
|
+
/**
|
|
3552
|
+
* Type guard to check if a field is a container field (page, row, group, or array)
|
|
3553
|
+
* Container fields have a 'fields' property and don't contribute values directly.
|
|
3554
|
+
* This overload works with RegisteredFieldTypes for full type narrowing.
|
|
3555
|
+
*/
|
|
3556
|
+
declare function isContainerField(field: RegisteredFieldTypes): field is ContainerFieldTypes;
|
|
3557
|
+
/**
|
|
3558
|
+
* Type guard to check if a field is a container field (page, row, group, or array).
|
|
3559
|
+
* This overload works with any FieldDef for looser type checking.
|
|
3560
|
+
*/
|
|
3561
|
+
declare function isContainerField(field: FieldDef<unknown>): boolean;
|
|
3562
|
+
/**
|
|
3563
|
+
* Type guard to check if a field is a leaf field (value or display field)
|
|
3564
|
+
* Leaf fields don't have children and either contribute values or display content
|
|
3565
|
+
*/
|
|
3566
|
+
declare function isLeafField(field: RegisteredFieldTypes): field is LeafFieldTypes;
|
|
3567
|
+
/**
|
|
3568
|
+
* Type guard to check if a field has a value property (value-bearing field)
|
|
3569
|
+
* These fields contribute to the form value output
|
|
3570
|
+
* Note: Using `unknown` in the Extract condition to match any value type
|
|
3571
|
+
*/
|
|
3572
|
+
declare function isValueBearingField(field: RegisteredFieldTypes): field is Extract<RegisteredFieldTypes, {
|
|
3573
|
+
value: unknown;
|
|
3574
|
+
}>;
|
|
3575
|
+
/**
|
|
3576
|
+
* Type guard to check if a field is excluded from form values (display-only field)
|
|
3577
|
+
* Currently this includes text fields and any other fields without a value property
|
|
3578
|
+
*/
|
|
3579
|
+
declare function isDisplayOnlyField(field: RegisteredFieldTypes): boolean;
|
|
3580
|
+
|
|
3581
|
+
/**
|
|
3582
|
+
* Helper types for creating type-safe field configurations with proper nesting constraints
|
|
3583
|
+
*/
|
|
3584
|
+
|
|
3585
|
+
/**
|
|
3586
|
+
* Type helper for accessing nested field paths safely
|
|
3587
|
+
* This allows accessing child paths while maintaining some type safety
|
|
3588
|
+
*/
|
|
3589
|
+
type FieldPathAccess<TValue> = {
|
|
3590
|
+
[K in keyof TValue]: SchemaPath<TValue[K]> | SchemaPathTree<TValue[K]>;
|
|
3591
|
+
};
|
|
3592
|
+
|
|
3242
3593
|
/**
|
|
3243
3594
|
* Extract FieldDef type from FieldTypeDefinition
|
|
3244
3595
|
*/
|
|
@@ -3643,80 +3994,6 @@ declare const DEFAULT_VALIDATION_MESSAGES: InjectionToken<Signal<ValidationMessa
|
|
|
3643
3994
|
*/
|
|
3644
3995
|
declare const FORM_OPTIONS: InjectionToken<Signal<FormOptions | undefined>>;
|
|
3645
3996
|
|
|
3646
|
-
/**
|
|
3647
|
-
* Context for resolving button disabled state.
|
|
3648
|
-
*
|
|
3649
|
-
* @public
|
|
3650
|
-
*/
|
|
3651
|
-
interface ButtonLogicContext {
|
|
3652
|
-
/** The form's FieldTree instance (supports both string and number keys for array indices) */
|
|
3653
|
-
form: FieldTree<unknown, string | number>;
|
|
3654
|
-
/** Form-level options */
|
|
3655
|
-
formOptions?: FormOptions;
|
|
3656
|
-
/** Field-level logic array (if provided) */
|
|
3657
|
-
fieldLogic?: LogicConfig[];
|
|
3658
|
-
/** Explicit disabled state from field definition */
|
|
3659
|
-
explicitlyDisabled?: boolean;
|
|
3660
|
-
/** Current page validity signal (for paged forms) */
|
|
3661
|
-
currentPageValid?: Signal<boolean>;
|
|
3662
|
-
/** Current form value for evaluating conditional expressions */
|
|
3663
|
-
formValue?: unknown;
|
|
3664
|
-
/** Optional logger for diagnostic output. Falls back to no-op logger if not provided. */
|
|
3665
|
-
logger?: Logger;
|
|
3666
|
-
}
|
|
3667
|
-
/**
|
|
3668
|
-
* Resolves the disabled state for a submit button.
|
|
3669
|
-
*
|
|
3670
|
-
* The disabled state is determined by (in order of precedence):
|
|
3671
|
-
* 1. Explicit `disabled: true` on the field definition
|
|
3672
|
-
* 2. Field-level `logic` array (if present, overrides form-level defaults)
|
|
3673
|
-
* 3. Form-level `options.submitButton` defaults
|
|
3674
|
-
*
|
|
3675
|
-
* @param ctx - The button logic context
|
|
3676
|
-
* @returns A computed signal that returns true when the button should be disabled
|
|
3677
|
-
*
|
|
3678
|
-
* @example
|
|
3679
|
-
* ```typescript
|
|
3680
|
-
* const disabled = resolveSubmitButtonDisabled({
|
|
3681
|
-
* form: formInstance,
|
|
3682
|
-
* formOptions: config.options,
|
|
3683
|
-
* fieldLogic: buttonField.logic,
|
|
3684
|
-
* explicitlyDisabled: buttonField.disabled,
|
|
3685
|
-
* });
|
|
3686
|
-
*
|
|
3687
|
-
* // Use in template
|
|
3688
|
-
* <button [disabled]="disabled()">Submit</button>
|
|
3689
|
-
* ```
|
|
3690
|
-
*
|
|
3691
|
-
* @public
|
|
3692
|
-
*/
|
|
3693
|
-
declare function resolveSubmitButtonDisabled(ctx: ButtonLogicContext): Signal<boolean>;
|
|
3694
|
-
/**
|
|
3695
|
-
* Resolves the disabled state for a next page button.
|
|
3696
|
-
*
|
|
3697
|
-
* The disabled state is determined by (in order of precedence):
|
|
3698
|
-
* 1. Explicit `disabled: true` on the field definition
|
|
3699
|
-
* 2. Field-level `logic` array (if present, overrides form-level defaults)
|
|
3700
|
-
* 3. Form-level `options.nextButton` defaults
|
|
3701
|
-
*
|
|
3702
|
-
* @param ctx - The button logic context
|
|
3703
|
-
* @returns A computed signal that returns true when the button should be disabled
|
|
3704
|
-
*
|
|
3705
|
-
* @example
|
|
3706
|
-
* ```typescript
|
|
3707
|
-
* const disabled = resolveNextButtonDisabled({
|
|
3708
|
-
* form: formInstance,
|
|
3709
|
-
* formOptions: config.options,
|
|
3710
|
-
* fieldLogic: buttonField.logic,
|
|
3711
|
-
* explicitlyDisabled: buttonField.disabled,
|
|
3712
|
-
* currentPageValid: pageOrchestrator.currentPageValid,
|
|
3713
|
-
* });
|
|
3714
|
-
* ```
|
|
3715
|
-
*
|
|
3716
|
-
* @public
|
|
3717
|
-
*/
|
|
3718
|
-
declare function resolveNextButtonDisabled(ctx: ButtonLogicContext): Signal<boolean>;
|
|
3719
|
-
|
|
3720
3997
|
interface FieldWithValidation {
|
|
3721
3998
|
readonly required?: boolean;
|
|
3722
3999
|
readonly email?: boolean;
|
|
@@ -3815,77 +4092,375 @@ declare class PreviousPageEvent implements FormEvent {
|
|
|
3815
4092
|
}
|
|
3816
4093
|
|
|
3817
4094
|
/**
|
|
3818
|
-
*
|
|
4095
|
+
* Template type for OBJECT array items: array of field configurations.
|
|
4096
|
+
* Each field's value is merged into the item object.
|
|
4097
|
+
*/
|
|
4098
|
+
type ArrayItemTemplate = ArrayAllowedChildren[];
|
|
4099
|
+
/**
|
|
4100
|
+
* Template type for array items that can be either:
|
|
4101
|
+
* - A single field (ArrayAllowedChildren) for PRIMITIVE items - extracts field value directly
|
|
4102
|
+
* - An array of fields (ArrayItemTemplate) for OBJECT items - merges fields into object
|
|
4103
|
+
*
|
|
4104
|
+
* Examples:
|
|
4105
|
+
* - Primitive: `{ key: 'tag', type: 'input', value: 'angular' }` → 'angular'
|
|
4106
|
+
* - Object: `[{ key: 'name', type: 'input' }, { key: 'email', type: 'input' }]` → { name: '', email: '' }
|
|
4107
|
+
*/
|
|
4108
|
+
type ArrayItemDefinitionTemplate = ArrayAllowedChildren | ArrayItemTemplate;
|
|
4109
|
+
/**
|
|
4110
|
+
* Event dispatched to append a new item at the END of an array field.
|
|
4111
|
+
*
|
|
4112
|
+
* This is the most common array operation - adding items to the end.
|
|
4113
|
+
* For other positions, use {@link PrependArrayItemEvent} or {@link InsertArrayItemEvent}.
|
|
4114
|
+
*
|
|
4115
|
+
* @example
|
|
4116
|
+
* ```typescript
|
|
4117
|
+
* // Object item: append { name, email } object
|
|
4118
|
+
* eventBus.dispatch(arrayEvent('contacts').append([
|
|
4119
|
+
* { key: 'name', type: 'input', label: 'Name' },
|
|
4120
|
+
* { key: 'email', type: 'input', label: 'Email' }
|
|
4121
|
+
* ]));
|
|
4122
|
+
*
|
|
4123
|
+
* // Primitive item: append single value
|
|
4124
|
+
* eventBus.dispatch(arrayEvent('tags').append(
|
|
4125
|
+
* { key: 'tag', type: 'input', label: 'Tag' }
|
|
4126
|
+
* ));
|
|
4127
|
+
* ```
|
|
4128
|
+
*
|
|
4129
|
+
* @typeParam TTemplate - The type of the template (single field or array of fields)
|
|
4130
|
+
*/
|
|
4131
|
+
declare class AppendArrayItemEvent<TTemplate extends ArrayItemDefinitionTemplate = ArrayItemDefinitionTemplate> implements FormEvent {
|
|
4132
|
+
/** The key of the array field to append an item to */
|
|
4133
|
+
readonly arrayKey: string;
|
|
4134
|
+
/**
|
|
4135
|
+
* Template for the new array item. REQUIRED.
|
|
4136
|
+
* - Single field (FieldDef): Creates a primitive item (field's value is extracted directly)
|
|
4137
|
+
* - Array of fields (FieldDef[]): Creates an object item (fields merged into object)
|
|
4138
|
+
*/
|
|
4139
|
+
readonly template: TTemplate;
|
|
4140
|
+
readonly type: "append-array-item";
|
|
4141
|
+
constructor(
|
|
4142
|
+
/** The key of the array field to append an item to */
|
|
4143
|
+
arrayKey: string,
|
|
4144
|
+
/**
|
|
4145
|
+
* Template for the new array item. REQUIRED.
|
|
4146
|
+
* - Single field (FieldDef): Creates a primitive item (field's value is extracted directly)
|
|
4147
|
+
* - Array of fields (FieldDef[]): Creates an object item (fields merged into object)
|
|
4148
|
+
*/
|
|
4149
|
+
template: TTemplate);
|
|
4150
|
+
}
|
|
4151
|
+
|
|
4152
|
+
/**
|
|
4153
|
+
* Event dispatched to prepend a new item at the BEGINNING of an array field.
|
|
3819
4154
|
*
|
|
3820
|
-
*
|
|
3821
|
-
*
|
|
3822
|
-
* based on the provided field template, or uses the array's own template if not provided.
|
|
4155
|
+
* Use this when new items should appear at the start of the list.
|
|
4156
|
+
* For appending to the end, use {@link AppendArrayItemEvent}.
|
|
3823
4157
|
*
|
|
3824
4158
|
* @example
|
|
3825
4159
|
* ```typescript
|
|
3826
|
-
* //
|
|
3827
|
-
* eventBus.dispatch(
|
|
4160
|
+
* // Object item: prepend { name } object
|
|
4161
|
+
* eventBus.dispatch(arrayEvent('contacts').prepend([
|
|
4162
|
+
* { key: 'name', type: 'input', label: 'Name' }
|
|
4163
|
+
* ]));
|
|
4164
|
+
*
|
|
4165
|
+
* // Primitive item: prepend single value
|
|
4166
|
+
* eventBus.dispatch(arrayEvent('tags').prepend(
|
|
4167
|
+
* { key: 'tag', type: 'input', label: 'Tag' }
|
|
4168
|
+
* ));
|
|
4169
|
+
* ```
|
|
4170
|
+
*
|
|
4171
|
+
* @typeParam TTemplate - The type of the template (single field or array of fields)
|
|
4172
|
+
*/
|
|
4173
|
+
declare class PrependArrayItemEvent<TTemplate extends ArrayItemDefinitionTemplate = ArrayItemDefinitionTemplate> implements FormEvent {
|
|
4174
|
+
/** The key of the array field to prepend an item to */
|
|
4175
|
+
readonly arrayKey: string;
|
|
4176
|
+
/**
|
|
4177
|
+
* Template for the new array item. REQUIRED.
|
|
4178
|
+
* - Single field (FieldDef): Creates a primitive item (field's value is extracted directly)
|
|
4179
|
+
* - Array of fields (FieldDef[]): Creates an object item (fields merged into object)
|
|
4180
|
+
*/
|
|
4181
|
+
readonly template: TTemplate;
|
|
4182
|
+
readonly type: "prepend-array-item";
|
|
4183
|
+
constructor(
|
|
4184
|
+
/** The key of the array field to prepend an item to */
|
|
4185
|
+
arrayKey: string,
|
|
4186
|
+
/**
|
|
4187
|
+
* Template for the new array item. REQUIRED.
|
|
4188
|
+
* - Single field (FieldDef): Creates a primitive item (field's value is extracted directly)
|
|
4189
|
+
* - Array of fields (FieldDef[]): Creates an object item (fields merged into object)
|
|
4190
|
+
*/
|
|
4191
|
+
template: TTemplate);
|
|
4192
|
+
}
|
|
4193
|
+
|
|
4194
|
+
/**
|
|
4195
|
+
* Event dispatched to insert a new item at a SPECIFIC INDEX in an array field.
|
|
3828
4196
|
*
|
|
3829
|
-
*
|
|
3830
|
-
*
|
|
3831
|
-
* eventBus.dispatch(AddArrayItemEvent, 'contacts', fieldTemplate);
|
|
4197
|
+
* Use this when you need precise control over where the new item appears.
|
|
4198
|
+
* For simpler operations, use {@link AppendArrayItemEvent} or {@link PrependArrayItemEvent}.
|
|
3832
4199
|
*
|
|
3833
|
-
*
|
|
3834
|
-
*
|
|
4200
|
+
* @example
|
|
4201
|
+
* ```typescript
|
|
4202
|
+
* // Object item: insert { name } object at index 2
|
|
4203
|
+
* eventBus.dispatch(arrayEvent('contacts').insertAt(2, [
|
|
4204
|
+
* { key: 'name', type: 'input', label: 'Name' }
|
|
4205
|
+
* ]));
|
|
4206
|
+
*
|
|
4207
|
+
* // Primitive item: insert single value at index 2
|
|
4208
|
+
* eventBus.dispatch(arrayEvent('tags').insertAt(2,
|
|
4209
|
+
* { key: 'tag', type: 'input', label: 'Tag' }
|
|
4210
|
+
* ));
|
|
3835
4211
|
* ```
|
|
4212
|
+
*
|
|
4213
|
+
* @typeParam TTemplate - The type of the template (single field or array of fields)
|
|
3836
4214
|
*/
|
|
3837
|
-
declare class
|
|
3838
|
-
/** The key of the array field to
|
|
4215
|
+
declare class InsertArrayItemEvent<TTemplate extends ArrayItemDefinitionTemplate = ArrayItemDefinitionTemplate> implements FormEvent {
|
|
4216
|
+
/** The key of the array field to insert an item into */
|
|
3839
4217
|
readonly arrayKey: string;
|
|
4218
|
+
/** The index at which to insert the new item */
|
|
4219
|
+
readonly index: number;
|
|
3840
4220
|
/**
|
|
3841
|
-
*
|
|
3842
|
-
*
|
|
4221
|
+
* Template for the new array item. REQUIRED.
|
|
4222
|
+
* - Single field (FieldDef): Creates a primitive item (field's value is extracted directly)
|
|
4223
|
+
* - Array of fields (FieldDef[]): Creates an object item (fields merged into object)
|
|
3843
4224
|
*/
|
|
3844
|
-
readonly
|
|
3845
|
-
|
|
3846
|
-
readonly index?: number | undefined;
|
|
3847
|
-
readonly type: "add-array-item";
|
|
4225
|
+
readonly template: TTemplate;
|
|
4226
|
+
readonly type: "insert-array-item";
|
|
3848
4227
|
constructor(
|
|
3849
|
-
/** The key of the array field to
|
|
4228
|
+
/** The key of the array field to insert an item into */
|
|
3850
4229
|
arrayKey: string,
|
|
4230
|
+
/** The index at which to insert the new item */
|
|
4231
|
+
index: number,
|
|
3851
4232
|
/**
|
|
3852
|
-
*
|
|
3853
|
-
*
|
|
4233
|
+
* Template for the new array item. REQUIRED.
|
|
4234
|
+
* - Single field (FieldDef): Creates a primitive item (field's value is extracted directly)
|
|
4235
|
+
* - Array of fields (FieldDef[]): Creates an object item (fields merged into object)
|
|
3854
4236
|
*/
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
4237
|
+
template: TTemplate);
|
|
4238
|
+
}
|
|
4239
|
+
|
|
4240
|
+
/**
|
|
4241
|
+
* Event dispatched to remove the LAST item from an array field.
|
|
4242
|
+
*
|
|
4243
|
+
* Equivalent to JavaScript's `Array.pop()` - removes from the end.
|
|
4244
|
+
* For removing from the beginning, use {@link ShiftArrayItemEvent}.
|
|
4245
|
+
* For removing at a specific index, use {@link RemoveAtIndexEvent}.
|
|
4246
|
+
*
|
|
4247
|
+
* @example
|
|
4248
|
+
* ```typescript
|
|
4249
|
+
* // Use the builder API (recommended)
|
|
4250
|
+
* eventBus.dispatch(arrayEvent('contacts').pop());
|
|
4251
|
+
*
|
|
4252
|
+
* // Or instantiate directly
|
|
4253
|
+
* eventBus.dispatch(new PopArrayItemEvent('contacts'));
|
|
4254
|
+
* ```
|
|
4255
|
+
*/
|
|
4256
|
+
declare class PopArrayItemEvent implements FormEvent {
|
|
4257
|
+
/** The key of the array field to remove the last item from */
|
|
4258
|
+
readonly arrayKey: string;
|
|
4259
|
+
readonly type: "pop-array-item";
|
|
4260
|
+
constructor(
|
|
4261
|
+
/** The key of the array field to remove the last item from */
|
|
4262
|
+
arrayKey: string);
|
|
4263
|
+
}
|
|
4264
|
+
|
|
4265
|
+
/**
|
|
4266
|
+
* Event dispatched to remove the FIRST item from an array field.
|
|
4267
|
+
*
|
|
4268
|
+
* Equivalent to JavaScript's `Array.shift()` - removes from the beginning.
|
|
4269
|
+
* For removing from the end, use {@link PopArrayItemEvent}.
|
|
4270
|
+
* For removing at a specific index, use {@link RemoveAtIndexEvent}.
|
|
4271
|
+
*
|
|
4272
|
+
* @example
|
|
4273
|
+
* ```typescript
|
|
4274
|
+
* // Use the builder API (recommended)
|
|
4275
|
+
* eventBus.dispatch(arrayEvent('contacts').shift());
|
|
4276
|
+
*
|
|
4277
|
+
* // Or instantiate directly
|
|
4278
|
+
* eventBus.dispatch(new ShiftArrayItemEvent('contacts'));
|
|
4279
|
+
* ```
|
|
4280
|
+
*/
|
|
4281
|
+
declare class ShiftArrayItemEvent implements FormEvent {
|
|
4282
|
+
/** The key of the array field to remove the first item from */
|
|
4283
|
+
readonly arrayKey: string;
|
|
4284
|
+
readonly type: "shift-array-item";
|
|
4285
|
+
constructor(
|
|
4286
|
+
/** The key of the array field to remove the first item from */
|
|
4287
|
+
arrayKey: string);
|
|
3858
4288
|
}
|
|
3859
4289
|
|
|
3860
4290
|
/**
|
|
3861
|
-
* Event dispatched to remove an item from an array field.
|
|
4291
|
+
* Event dispatched to remove an item at a SPECIFIC INDEX from an array field.
|
|
3862
4292
|
*
|
|
3863
|
-
*
|
|
3864
|
-
*
|
|
3865
|
-
* at the specified index.
|
|
4293
|
+
* Use this when you need precise control over which item to remove.
|
|
4294
|
+
* For simpler operations, use {@link PopArrayItemEvent} or {@link ShiftArrayItemEvent}.
|
|
3866
4295
|
*
|
|
3867
4296
|
* @example
|
|
3868
4297
|
* ```typescript
|
|
3869
|
-
* //
|
|
3870
|
-
* eventBus.dispatch(
|
|
4298
|
+
* // Use the builder API (recommended)
|
|
4299
|
+
* eventBus.dispatch(arrayEvent('contacts').removeAt(2));
|
|
3871
4300
|
*
|
|
3872
|
-
* //
|
|
3873
|
-
* eventBus.dispatch(
|
|
4301
|
+
* // Or instantiate directly
|
|
4302
|
+
* eventBus.dispatch(new RemoveAtIndexEvent('contacts', 2));
|
|
3874
4303
|
* ```
|
|
3875
4304
|
*/
|
|
3876
|
-
declare class
|
|
4305
|
+
declare class RemoveAtIndexEvent implements FormEvent {
|
|
3877
4306
|
/** The key of the array field to remove an item from */
|
|
3878
4307
|
readonly arrayKey: string;
|
|
3879
|
-
/**
|
|
3880
|
-
readonly index
|
|
3881
|
-
readonly type: "remove-
|
|
4308
|
+
/** The index of the item to remove */
|
|
4309
|
+
readonly index: number;
|
|
4310
|
+
readonly type: "remove-at-index";
|
|
3882
4311
|
constructor(
|
|
3883
4312
|
/** The key of the array field to remove an item from */
|
|
3884
4313
|
arrayKey: string,
|
|
3885
|
-
/**
|
|
3886
|
-
index
|
|
4314
|
+
/** The index of the item to remove */
|
|
4315
|
+
index: number);
|
|
3887
4316
|
}
|
|
3888
4317
|
|
|
4318
|
+
/**
|
|
4319
|
+
* Builder for array manipulation events.
|
|
4320
|
+
*
|
|
4321
|
+
* Provides a fluent, discoverable API for array operations.
|
|
4322
|
+
* Type `arrayEvent('key').` in your IDE to see all available operations.
|
|
4323
|
+
*
|
|
4324
|
+
* **BREAKING CHANGE**: Template is now required for add operations.
|
|
4325
|
+
*
|
|
4326
|
+
* Supports both primitive and object array items:
|
|
4327
|
+
* - Primitive: Pass a single field definition → extracts field value directly
|
|
4328
|
+
* - Object: Pass an array of field definitions → merges fields into object
|
|
4329
|
+
*
|
|
4330
|
+
* @example
|
|
4331
|
+
* ```typescript
|
|
4332
|
+
* import { arrayEvent } from '@ng-forge/dynamic-forms';
|
|
4333
|
+
*
|
|
4334
|
+
* // Object item: append { name, email } object
|
|
4335
|
+
* eventBus.dispatch(arrayEvent('contacts').append([
|
|
4336
|
+
* { key: 'name', type: 'input', label: 'Name' },
|
|
4337
|
+
* { key: 'email', type: 'input', label: 'Email' }
|
|
4338
|
+
* ]));
|
|
4339
|
+
*
|
|
4340
|
+
* // Primitive item: append single value
|
|
4341
|
+
* eventBus.dispatch(arrayEvent('tags').append(
|
|
4342
|
+
* { key: 'tag', type: 'input', label: 'Tag' }
|
|
4343
|
+
* ));
|
|
4344
|
+
*
|
|
4345
|
+
* // Removing items (no template needed)
|
|
4346
|
+
* eventBus.dispatch(arrayEvent('contacts').pop()); // Remove last
|
|
4347
|
+
* eventBus.dispatch(arrayEvent('contacts').shift()); // Remove first
|
|
4348
|
+
* eventBus.dispatch(arrayEvent('contacts').removeAt(2)); // Remove at index
|
|
4349
|
+
* ```
|
|
4350
|
+
*
|
|
4351
|
+
* @param arrayKey - The key of the array field to operate on
|
|
4352
|
+
* @returns An object with methods for all 6 array operations
|
|
4353
|
+
*/
|
|
4354
|
+
declare function arrayEvent(arrayKey: string): {
|
|
4355
|
+
/**
|
|
4356
|
+
* Append a new item at the END of the array.
|
|
4357
|
+
* This is the most common operation for adding items.
|
|
4358
|
+
*
|
|
4359
|
+
* @param template - Template for the new item (REQUIRED)
|
|
4360
|
+
* - Single field: Creates a primitive item (field's value is extracted directly)
|
|
4361
|
+
* - Array of fields: Creates an object item (fields merged into object)
|
|
4362
|
+
* @returns An AppendArrayItemEvent to dispatch
|
|
4363
|
+
*
|
|
4364
|
+
* @example
|
|
4365
|
+
* ```typescript
|
|
4366
|
+
* // Object item
|
|
4367
|
+
* eventBus.dispatch(arrayEvent('contacts').append([
|
|
4368
|
+
* { key: 'name', type: 'input', label: 'Name' }
|
|
4369
|
+
* ]));
|
|
4370
|
+
*
|
|
4371
|
+
* // Primitive item
|
|
4372
|
+
* eventBus.dispatch(arrayEvent('tags').append(
|
|
4373
|
+
* { key: 'tag', type: 'input', label: 'Tag' }
|
|
4374
|
+
* ));
|
|
4375
|
+
* ```
|
|
4376
|
+
*/
|
|
4377
|
+
append: <T extends ArrayItemDefinitionTemplate>(template: T) => AppendArrayItemEvent<T>;
|
|
4378
|
+
/**
|
|
4379
|
+
* Prepend a new item at the BEGINNING of the array.
|
|
4380
|
+
* Use when new items should appear at the start.
|
|
4381
|
+
*
|
|
4382
|
+
* @param template - Template for the new item (REQUIRED)
|
|
4383
|
+
* - Single field: Creates a primitive item (field's value is extracted directly)
|
|
4384
|
+
* - Array of fields: Creates an object item (fields merged into object)
|
|
4385
|
+
* @returns A PrependArrayItemEvent to dispatch
|
|
4386
|
+
*
|
|
4387
|
+
* @example
|
|
4388
|
+
* ```typescript
|
|
4389
|
+
* // Object item
|
|
4390
|
+
* eventBus.dispatch(arrayEvent('contacts').prepend([
|
|
4391
|
+
* { key: 'name', type: 'input', label: 'Name' }
|
|
4392
|
+
* ]));
|
|
4393
|
+
*
|
|
4394
|
+
* // Primitive item
|
|
4395
|
+
* eventBus.dispatch(arrayEvent('tags').prepend(
|
|
4396
|
+
* { key: 'tag', type: 'input', label: 'Tag' }
|
|
4397
|
+
* ));
|
|
4398
|
+
* ```
|
|
4399
|
+
*/
|
|
4400
|
+
prepend: <T extends ArrayItemDefinitionTemplate>(template: T) => PrependArrayItemEvent<T>;
|
|
4401
|
+
/**
|
|
4402
|
+
* Insert a new item at a SPECIFIC INDEX in the array.
|
|
4403
|
+
* Use when you need precise control over item placement.
|
|
4404
|
+
*
|
|
4405
|
+
* @param index - The position at which to insert the new item
|
|
4406
|
+
* @param template - Template for the new item (REQUIRED)
|
|
4407
|
+
* - Single field: Creates a primitive item (field's value is extracted directly)
|
|
4408
|
+
* - Array of fields: Creates an object item (fields merged into object)
|
|
4409
|
+
* @returns An InsertArrayItemEvent to dispatch
|
|
4410
|
+
*
|
|
4411
|
+
* @example
|
|
4412
|
+
* ```typescript
|
|
4413
|
+
* // Object item at index 2
|
|
4414
|
+
* eventBus.dispatch(arrayEvent('contacts').insertAt(2, [
|
|
4415
|
+
* { key: 'name', type: 'input', label: 'Name' }
|
|
4416
|
+
* ]));
|
|
4417
|
+
*
|
|
4418
|
+
* // Primitive item at index 2
|
|
4419
|
+
* eventBus.dispatch(arrayEvent('tags').insertAt(2,
|
|
4420
|
+
* { key: 'tag', type: 'input', label: 'Tag' }
|
|
4421
|
+
* ));
|
|
4422
|
+
* ```
|
|
4423
|
+
*/
|
|
4424
|
+
insertAt: <T extends ArrayItemDefinitionTemplate>(index: number, template: T) => InsertArrayItemEvent<T>;
|
|
4425
|
+
/**
|
|
4426
|
+
* Remove the LAST item from the array.
|
|
4427
|
+
* Equivalent to JavaScript's `Array.pop()`.
|
|
4428
|
+
*
|
|
4429
|
+
* @returns A PopArrayItemEvent to dispatch
|
|
4430
|
+
*
|
|
4431
|
+
* @example
|
|
4432
|
+
* ```typescript
|
|
4433
|
+
* eventBus.dispatch(arrayEvent('contacts').pop());
|
|
4434
|
+
* ```
|
|
4435
|
+
*/
|
|
4436
|
+
pop: () => PopArrayItemEvent;
|
|
4437
|
+
/**
|
|
4438
|
+
* Remove the FIRST item from the array.
|
|
4439
|
+
* Equivalent to JavaScript's `Array.shift()`.
|
|
4440
|
+
*
|
|
4441
|
+
* @returns A ShiftArrayItemEvent to dispatch
|
|
4442
|
+
*
|
|
4443
|
+
* @example
|
|
4444
|
+
* ```typescript
|
|
4445
|
+
* eventBus.dispatch(arrayEvent('contacts').shift());
|
|
4446
|
+
* ```
|
|
4447
|
+
*/
|
|
4448
|
+
shift: () => ShiftArrayItemEvent;
|
|
4449
|
+
/**
|
|
4450
|
+
* Remove an item at a SPECIFIC INDEX from the array.
|
|
4451
|
+
* Use when you need to remove a specific item by position.
|
|
4452
|
+
*
|
|
4453
|
+
* @param index - The position of the item to remove
|
|
4454
|
+
* @returns A RemoveAtIndexEvent to dispatch
|
|
4455
|
+
*
|
|
4456
|
+
* @example
|
|
4457
|
+
* ```typescript
|
|
4458
|
+
* eventBus.dispatch(arrayEvent('contacts').removeAt(2));
|
|
4459
|
+
* ```
|
|
4460
|
+
*/
|
|
4461
|
+
removeAt: (index: number) => RemoveAtIndexEvent;
|
|
4462
|
+
};
|
|
4463
|
+
|
|
3889
4464
|
/**
|
|
3890
4465
|
* Event bus service for form-wide event communication.
|
|
3891
4466
|
*
|
|
@@ -3984,6 +4559,8 @@ interface TokenContext {
|
|
|
3984
4559
|
arrayKey?: string;
|
|
3985
4560
|
/** Current form value for complex indexing */
|
|
3986
4561
|
formValue?: unknown;
|
|
4562
|
+
/** Template for array item creation */
|
|
4563
|
+
template?: unknown;
|
|
3987
4564
|
}
|
|
3988
4565
|
/**
|
|
3989
4566
|
* Resolves special tokens in event arguments to their actual values
|
|
@@ -3992,6 +4569,7 @@ interface TokenContext {
|
|
|
3992
4569
|
* - $key: The current field key
|
|
3993
4570
|
* - $index: The array index (if inside an array field)
|
|
3994
4571
|
* - $arrayKey: The parent array field key (if inside an array field)
|
|
4572
|
+
* - $template: The template for array item creation
|
|
3995
4573
|
* - formValue: Reference to the current form value for indexing
|
|
3996
4574
|
*
|
|
3997
4575
|
* @param args - Array of arguments that may contain tokens
|
|
@@ -4005,6 +4583,10 @@ interface TokenContext {
|
|
|
4005
4583
|
* @example
|
|
4006
4584
|
* resolveTokens(['$key', 'static'], { key: 'myField' })
|
|
4007
4585
|
* // Returns: ['myField', 'static']
|
|
4586
|
+
*
|
|
4587
|
+
* @example
|
|
4588
|
+
* resolveTokens(['$arrayKey', '$template'], { arrayKey: 'contacts', template: [{ key: 'name', type: 'input' }] })
|
|
4589
|
+
* // Returns: ['contacts', [{ key: 'name', type: 'input' }]]
|
|
4008
4590
|
*/
|
|
4009
4591
|
declare function resolveTokens(args: readonly (string | number | boolean | null | undefined)[], context: TokenContext): (string | number | boolean | null | undefined | unknown)[];
|
|
4010
4592
|
|
|
@@ -4221,8 +4803,14 @@ declare function pageFieldMapper(fieldDef: PageField): Signal<Record<string, unk
|
|
|
4221
4803
|
* Maps a text field definition to component inputs.
|
|
4222
4804
|
*
|
|
4223
4805
|
* Text fields are display-only fields that don't participate in the form schema.
|
|
4224
|
-
* This mapper handles the `logic` configuration by
|
|
4225
|
-
*
|
|
4806
|
+
* This mapper handles the `logic` configuration by using the non-field-hidden resolver
|
|
4807
|
+
* to evaluate conditions against the form value from RootFormRegistryService.
|
|
4808
|
+
*
|
|
4809
|
+
* Hidden state is resolved using the non-field-hidden resolver which considers:
|
|
4810
|
+
* 1. Explicit `hidden: true` on the field definition
|
|
4811
|
+
* 2. Field-level `logic` array with `type: 'hidden'` conditions
|
|
4812
|
+
*
|
|
4813
|
+
* Note: Text fields don't support disabled logic since they are display-only.
|
|
4226
4814
|
*
|
|
4227
4815
|
* @param fieldDef The text field definition
|
|
4228
4816
|
* @returns Signal containing Record of input names to values for ngComponentOutlet
|
|
@@ -4343,9 +4931,7 @@ declare class GroupFieldComponent<TModel extends Record<string, unknown> = Recor
|
|
|
4343
4931
|
private readonly injector;
|
|
4344
4932
|
private readonly eventBus;
|
|
4345
4933
|
private readonly logger;
|
|
4346
|
-
private readonly
|
|
4347
|
-
private readonly memoizedKeyBy;
|
|
4348
|
-
private readonly memoizedDefaultValues;
|
|
4934
|
+
private readonly fieldProcessors;
|
|
4349
4935
|
field: _angular_core.InputSignal<GroupField<readonly _ng_forge_dynamic_forms.GroupAllowedChildren[]>>;
|
|
4350
4936
|
key: _angular_core.InputSignal<string>;
|
|
4351
4937
|
className: _angular_core.InputSignal<string | undefined>;
|
|
@@ -4353,6 +4939,11 @@ declare class GroupFieldComponent<TModel extends Record<string, unknown> = Recor
|
|
|
4353
4939
|
private readonly rawFieldRegistry;
|
|
4354
4940
|
private readonly formSetup;
|
|
4355
4941
|
readonly defaultValues: _angular_core.WritableSignal<Record<string, unknown>>;
|
|
4942
|
+
/**
|
|
4943
|
+
* Entity computed from parent value, group key, and defaults.
|
|
4944
|
+
* Uses deep equality check to prevent unnecessary updates when
|
|
4945
|
+
* object spread creates new references with identical values.
|
|
4946
|
+
*/
|
|
4356
4947
|
private readonly entity;
|
|
4357
4948
|
private readonly form;
|
|
4358
4949
|
readonly formValue: _angular_core.Signal<{}>;
|
|
@@ -4363,6 +4954,7 @@ declare class GroupFieldComponent<TModel extends Record<string, unknown> = Recor
|
|
|
4363
4954
|
readonly errors: _angular_core.Signal<_angular_forms_signals.ValidationError.WithField[]>;
|
|
4364
4955
|
readonly disabled: _angular_core.Signal<boolean>;
|
|
4365
4956
|
private readonly nestedFieldTree;
|
|
4957
|
+
private readonly groupFieldSignalContext;
|
|
4366
4958
|
private readonly groupInjector;
|
|
4367
4959
|
readonly validityChange: _angular_core.OutputRef<boolean>;
|
|
4368
4960
|
readonly dirtyChange: _angular_core.OutputRef<boolean>;
|
|
@@ -4376,13 +4968,9 @@ declare class GroupFieldComponent<TModel extends Record<string, unknown> = Recor
|
|
|
4376
4968
|
}
|
|
4377
4969
|
|
|
4378
4970
|
/**
|
|
4379
|
-
*
|
|
4380
|
-
* Each item has a stable unique ID and a linkedSignal-based index that
|
|
4381
|
-
* automatically updates when items are added/removed.
|
|
4971
|
+
* A single field within a resolved array item.
|
|
4382
4972
|
*/
|
|
4383
|
-
interface
|
|
4384
|
-
/** Unique identifier for this item (stable across position changes). */
|
|
4385
|
-
id: string;
|
|
4973
|
+
interface ResolvedArrayItemField {
|
|
4386
4974
|
/** The loaded component type. */
|
|
4387
4975
|
component: Type<unknown>;
|
|
4388
4976
|
/** Injector providing ARRAY_CONTEXT and FIELD_SIGNAL_CONTEXT. */
|
|
@@ -4390,13 +4978,26 @@ interface ResolvedArrayItem {
|
|
|
4390
4978
|
/** Inputs signal for ngComponentOutlet - evaluated in template for reactivity. */
|
|
4391
4979
|
inputs: Signal<Record<string, unknown>>;
|
|
4392
4980
|
}
|
|
4981
|
+
/**
|
|
4982
|
+
* Resolved array item ready for declarative rendering with ngComponentOutlet.
|
|
4983
|
+
* Each item has a stable unique ID and a linkedSignal-based index that
|
|
4984
|
+
* automatically updates when items are added/removed.
|
|
4985
|
+
* Supports multiple fields per array item (e.g., name + email without a wrapper).
|
|
4986
|
+
*/
|
|
4987
|
+
interface ResolvedArrayItem {
|
|
4988
|
+
/** Unique identifier for this item (stable across position changes). */
|
|
4989
|
+
id: string;
|
|
4990
|
+
/** All fields to render for this array item. */
|
|
4991
|
+
fields: ResolvedArrayItemField[];
|
|
4992
|
+
}
|
|
4393
4993
|
|
|
4394
4994
|
/**
|
|
4395
4995
|
* Container component for rendering dynamic arrays of fields.
|
|
4396
4996
|
*
|
|
4397
|
-
* Supports add/remove operations via
|
|
4997
|
+
* Supports add/remove operations via the arrayEvent() builder API.
|
|
4398
4998
|
* Uses differential updates to optimize rendering - only recreates items when necessary.
|
|
4399
4999
|
* Each item gets a scoped injector with ARRAY_CONTEXT for position-aware operations.
|
|
5000
|
+
* Supports multiple sibling fields per array item (e.g., name + email without a wrapper).
|
|
4400
5001
|
*/
|
|
4401
5002
|
declare class ArrayFieldComponent<TModel extends Record<string, unknown> = Record<string, unknown>> {
|
|
4402
5003
|
private readonly destroyRef;
|
|
@@ -4405,25 +5006,62 @@ declare class ArrayFieldComponent<TModel extends Record<string, unknown> = Recor
|
|
|
4405
5006
|
private readonly parentInjector;
|
|
4406
5007
|
private readonly eventBus;
|
|
4407
5008
|
private readonly logger;
|
|
4408
|
-
|
|
5009
|
+
private readonly templateRegistry;
|
|
5010
|
+
private readonly generateItemId;
|
|
5011
|
+
field: _angular_core.InputSignal<ArrayField<readonly ArrayItemDefinition[]>>;
|
|
4409
5012
|
key: _angular_core.InputSignal<string>;
|
|
4410
5013
|
className: _angular_core.InputSignal<string | undefined>;
|
|
4411
5014
|
readonly hostClasses: _angular_core.Signal<string>;
|
|
4412
5015
|
private readonly rawFieldRegistry;
|
|
4413
|
-
|
|
5016
|
+
/**
|
|
5017
|
+
* Gets the item templates (field definitions) for the array.
|
|
5018
|
+
* Each element can be either:
|
|
5019
|
+
* - A single FieldDef (primitive item) - normalized to [FieldDef]
|
|
5020
|
+
* - An array of FieldDefs (object item) - used as-is
|
|
5021
|
+
*
|
|
5022
|
+
* Returns normalized templates where all items are arrays for consistent handling.
|
|
5023
|
+
*/
|
|
5024
|
+
private readonly itemTemplates;
|
|
4414
5025
|
private readonly arrayFieldTrees;
|
|
4415
5026
|
private readonly resolvedItemsSignal;
|
|
4416
5027
|
private readonly updateVersion;
|
|
4417
|
-
|
|
4418
|
-
|
|
5028
|
+
/**
|
|
5029
|
+
* Map of item IDs to their current positions. O(1) lookup vs O(n) indexOf().
|
|
5030
|
+
* Used by child linkedSignals to reactively track their position in the array.
|
|
5031
|
+
*/
|
|
5032
|
+
private readonly itemPositionMap;
|
|
5033
|
+
/** Read-only view of resolved items for template consumption. */
|
|
5034
|
+
readonly resolvedItems: _angular_core.Signal<ResolvedArrayItem[]>;
|
|
4419
5035
|
constructor();
|
|
4420
5036
|
private setupEffects;
|
|
4421
5037
|
private setupEventHandlers;
|
|
5038
|
+
/**
|
|
5039
|
+
* Handles add operations from events (append, prepend, insert).
|
|
5040
|
+
* Creates resolved items FIRST, then updates form value.
|
|
5041
|
+
* This ensures prepend/insert work correctly - differential update sees "none"
|
|
5042
|
+
* because resolved items count already matches the new array length.
|
|
5043
|
+
*
|
|
5044
|
+
* Supports both primitive (single FieldDef) and object (FieldDef[]) templates.
|
|
5045
|
+
*/
|
|
5046
|
+
private handleAddFromEvent;
|
|
4422
5047
|
private performDifferentialUpdate;
|
|
4423
5048
|
private resolveAllItems;
|
|
4424
5049
|
private appendItems;
|
|
5050
|
+
/**
|
|
5051
|
+
* Creates an observable that resolves a single array item.
|
|
5052
|
+
*
|
|
5053
|
+
* Template resolution order:
|
|
5054
|
+
* 1. Use overrideTemplate if provided (from recreate with stored templates)
|
|
5055
|
+
* 2. Use itemTemplates[index] if within defined templates range
|
|
5056
|
+
* 3. Return undefined (item cannot be resolved without a template)
|
|
5057
|
+
*/
|
|
4425
5058
|
private createResolveItemObservable;
|
|
4426
|
-
|
|
5059
|
+
/**
|
|
5060
|
+
* Handles remove operations from events (pop, shift, removeAt).
|
|
5061
|
+
* Updates resolvedItems FIRST, then form value - this ensures differential
|
|
5062
|
+
* update sees "none" (lengths match) and avoids unnecessary recreates.
|
|
5063
|
+
* Remaining items' linkedSignal indices auto-update via itemPositionMap.
|
|
5064
|
+
*/
|
|
4427
5065
|
private removeItem;
|
|
4428
5066
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ArrayFieldComponent<any>, never>;
|
|
4429
5067
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ArrayFieldComponent<any>, "array-field", never, { "field": { "alias": "field"; "required": true; "isSignal": true; }; "key": { "alias": "key"; "required": true; "isSignal": true; }; "className": { "alias": "className"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
@@ -4501,97 +5139,16 @@ declare function omit<T extends object, K extends keyof T>(obj: T, keys: K[]): O
|
|
|
4501
5139
|
declare function interpolateParams(message: string, error: ValidationError): string;
|
|
4502
5140
|
|
|
4503
5141
|
/**
|
|
4504
|
-
* Registry service that
|
|
4505
|
-
* This provides a type-safe way to access root form values from child fields
|
|
4506
|
-
* without relying on internal Angular Forms API navigation.
|
|
4507
|
-
*
|
|
4508
|
-
* This service should be provided at the component level to ensure proper
|
|
4509
|
-
* isolation between different form instances.
|
|
5142
|
+
* Registry service that provides access to the root form and its values.
|
|
4510
5143
|
*
|
|
4511
|
-
*
|
|
4512
|
-
*
|
|
4513
|
-
* This allows logic functions to read form values during schema evaluation.
|
|
4514
|
-
* 2. registerRootForm() - Register the FieldTree AFTER form creation
|
|
4515
|
-
* This provides access to the full form structure.
|
|
4516
|
-
*
|
|
4517
|
-
* For cross-field logic to work correctly, registerFormValueSignal() should be
|
|
4518
|
-
* called BEFORE the form() call.
|
|
5144
|
+
* Constructed via factory in `provideDynamicFormDI` with signals from
|
|
5145
|
+
* `FormStateManager` — no DI injection, no Maps, no lifecycle.
|
|
4519
5146
|
*/
|
|
4520
5147
|
declare class RootFormRegistryService {
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
/**
|
|
4525
|
-
* Registers the form value signal BEFORE form creation.
|
|
4526
|
-
*
|
|
4527
|
-
* This is the recommended pattern for cross-field logic:
|
|
4528
|
-
* 1. Create the formValue signal
|
|
4529
|
-
* 2. Register it with registerFormValueSignal()
|
|
4530
|
-
* 3. Create the form with form(formValue, schema(...))
|
|
4531
|
-
*
|
|
4532
|
-
* This allows logic functions to access form values during schema evaluation.
|
|
4533
|
-
*/
|
|
4534
|
-
registerFormValueSignal(valueSignal: Signal<Record<string, unknown>>, formId?: string): void;
|
|
4535
|
-
/**
|
|
4536
|
-
* Gets the registered form value signal by id.
|
|
4537
|
-
*
|
|
4538
|
-
* This allows direct access to the source signal, which can be read
|
|
4539
|
-
* reactively to get form values.
|
|
4540
|
-
*/
|
|
4541
|
-
getFormValueSignal(formId?: string): Signal<Record<string, unknown>> | undefined;
|
|
4542
|
-
/**
|
|
4543
|
-
* Registers a root form field with an optional identifier.
|
|
4544
|
-
* If no id is provided, uses 'default' as the key.
|
|
4545
|
-
*
|
|
4546
|
-
* This triggers reactive updates for any computed signals that
|
|
4547
|
-
* depend on getRootForm().
|
|
4548
|
-
*/
|
|
4549
|
-
registerRootForm(rootField: FieldTree<unknown>, formId?: string): void;
|
|
4550
|
-
/**
|
|
4551
|
-
* Gets a registered root form field by id.
|
|
4552
|
-
*
|
|
4553
|
-
* IMPORTANT: This method reads from a signal, which means any computed
|
|
4554
|
-
* signal that calls this method will automatically re-evaluate when
|
|
4555
|
-
* the form is registered or updated.
|
|
4556
|
-
*/
|
|
4557
|
-
getRootForm(formId?: string): FieldTree<unknown> | undefined;
|
|
4558
|
-
/**
|
|
4559
|
-
* Gets the form value, preferring the direct signal if available.
|
|
4560
|
-
*
|
|
4561
|
-
* This method tries in order:
|
|
4562
|
-
* 1. Form value signal (if registered) - reads directly from source signal
|
|
4563
|
-
* 2. Root form's .value() (if registered) - reads from FieldTree
|
|
4564
|
-
* 3. Returns empty object if nothing is registered
|
|
4565
|
-
*
|
|
4566
|
-
* Reading from signals creates reactive dependencies, so computeds will
|
|
4567
|
-
* re-evaluate when form values change.
|
|
4568
|
-
*/
|
|
4569
|
-
getFormValue(formId?: string): Record<string, unknown>;
|
|
4570
|
-
/**
|
|
4571
|
-
* Registers form context (field paths and metadata) for a specific form.
|
|
4572
|
-
* This can be used to store additional context information.
|
|
4573
|
-
*/
|
|
4574
|
-
registerFormContext(context: Record<string, unknown>, formId?: string): void;
|
|
4575
|
-
/**
|
|
4576
|
-
* Gets form context by id.
|
|
4577
|
-
*/
|
|
4578
|
-
getFormContext(formId?: string): Record<string, unknown>;
|
|
4579
|
-
/**
|
|
4580
|
-
* Unregisters a form and its context.
|
|
4581
|
-
* This should be called when a form component is destroyed to prevent memory leaks.
|
|
4582
|
-
*/
|
|
4583
|
-
unregisterForm(formId?: string): void;
|
|
4584
|
-
/**
|
|
4585
|
-
* Gets all registered form IDs.
|
|
4586
|
-
*/
|
|
4587
|
-
getRegisteredFormIds(): string[];
|
|
4588
|
-
/**
|
|
4589
|
-
* Clears all registered forms. Useful for testing.
|
|
4590
|
-
*/
|
|
4591
|
-
clear(): void;
|
|
4592
|
-
static ɵfac: _angular_core.ɵɵFactoryDeclaration<RootFormRegistryService, never>;
|
|
4593
|
-
static ɵprov: _angular_core.ɵɵInjectableDeclaration<RootFormRegistryService>;
|
|
5148
|
+
readonly formValue: Signal<Record<string, unknown>>;
|
|
5149
|
+
readonly rootForm: Signal<FieldTree<Record<string, unknown>> | undefined>;
|
|
5150
|
+
constructor(formValue: Signal<Record<string, unknown>>, rootForm: Signal<FieldTree<Record<string, unknown>> | undefined>);
|
|
4594
5151
|
}
|
|
4595
5152
|
|
|
4596
|
-
export { ARRAY_CONTEXT,
|
|
4597
|
-
export type { ArrayAllowedChildren, ArrayContext, ArrayField, ArrayFieldTree, ArrayItemContext, AsyncCustomValidator, AsyncValidatorConfig, AvailableFieldTypes, BaseCheckedField, BaseValidatorConfig, BaseValueField, BuiltInValidatorConfig, ButtonLogicContext, CheckedFieldComponent, ConditionalExpression, ContainerFieldTypes, CustomFnConfig, CustomValidator, CustomValidatorConfig, DynamicFormFieldRegistry, DynamicText, EvaluationContext, ExtractField, ExtractFieldDefs, ExtractFormValue, FieldComponent, FieldDef, FieldMeta, FieldOption, FieldPathAccess, FieldRegistryContainers, FieldRegistryLeaves, FieldSignalContext, FieldTypeDefinition, FieldWithValidation, FormConfig, FormEvent, FormEventConstructor, FormMode, FormModeDetectionResult, FormOptions, FormStateCondition, GroupAllowedChildren, GroupField, HttpCustomValidator, HttpResourceRequest, HttpValidatorConfig, InferFormValue$1 as InferFormValue, LeafFieldTypes, Logger, LogicConfig, MapperFn, NarrowField, NarrowFields, NextButtonOptions, PageAllowedChildren, PageField, Prettify, RegisteredFieldTypes, RowAllowedChildren, RowField, SchemaApplicationConfig, SchemaDefinition, SubmissionActionResult, SubmissionConfig, SubmitButtonOptions, TextElementType, TextField, TextProps, TokenContext, ValidationError, ValidationMessages, ValidatorConfig, ValueFieldComponent, ValueHandlingMode, ValueType, WithInputSignals };
|
|
5153
|
+
export { ARRAY_CONTEXT, AppendArrayItemEvent, ArrayFieldComponent, BUILT_IN_FIELDS, ConsoleLogger, DEFAULT_PROPS, DEFAULT_VALIDATION_MESSAGES, DynamicForm, DynamicFormError, DynamicFormLogger, DynamicTextPipe, EventBus, FIELD_REGISTRY, FIELD_SIGNAL_CONTEXT, FORM_OPTIONS, FormClearEvent, FormResetEvent, GroupFieldComponent, InsertArrayItemEvent, NextPageEvent, NoopLogger, PageChangeEvent, PopArrayItemEvent, PrependArrayItemEvent, PreviousPageEvent, RemoveAtIndexEvent, RootFormRegistryService, RowFieldComponent, ShiftArrayItemEvent, SubmitEvent, applyMetaToElement, applyValidator, applyValidators, arrayEvent, arrayFieldMapper, baseFieldMapper, buildBaseInputs, createField, dynamicTextToObservable, field, formConfig, getArrayLength, groupFieldMapper, hasFormValue, interpolateParams, isArrayField, isCheckedField, isContainerField, isDisplayOnlyField, isEqual, isFormStateCondition, isGroupField, isLeafField, isPageField, isPropertyDerivationLogicConfig, isRowField, isValueBearingField, isValueField, omit, pageFieldMapper, provideDynamicForm, resolveNextButtonDisabled, resolveNonFieldDisabled, resolveNonFieldHidden, resolveSubmitButtonDisabled, resolveTokens, rowFieldMapper, textFieldMapper, withEventFormValue, withLoggerConfig };
|
|
5154
|
+
export type { ArrayAllowedChildren, ArrayContext, ArrayField, ArrayFieldTree, ArrayItemContext, ArrayItemDefinitionTemplate, ArrayItemTemplate, AsyncCustomValidator, AsyncValidatorConfig, AvailableFieldTypes, BaseCheckedField, BaseValidatorConfig, BaseValueField, BuiltInValidatorConfig, ButtonLogicContext, CheckedFieldComponent, ConditionalExpression, ContainerFieldTypes, CustomFnConfig, CustomValidator, CustomValidatorConfig, DynamicFormFieldRegistry, DynamicText, EvaluationContext, ExtractField, ExtractFieldDefs, ExtractFormValue, FieldComponent, FieldDef, FieldMeta, FieldOption, FieldPathAccess, FieldRegistryContainers, FieldRegistryLeaves, FieldSignalContext, FieldTypeDefinition, FieldWithValidation, FormConfig, FormEvent, FormEventConstructor, FormMode, FormModeDetectionResult, FormOptions, FormStateCondition, GroupAllowedChildren, GroupField, HttpCustomValidator, HttpResourceRequest, HttpValidatorConfig, InferFormValue$1 as InferFormValue, LeafFieldTypes, Logger, LogicConfig, MapperFn, NarrowField, NarrowFields, NextButtonOptions, NonFieldLogicConfig, NonFieldLogicContext, NonFieldLogicType, PageAllowedChildren, PageField, Prettify, PropertyDerivationLogicConfig, RegisteredFieldTypes, RowAllowedChildren, RowField, SchemaApplicationConfig, SchemaDefinition, StateLogicConfig, SubmissionActionResult, SubmissionConfig, SubmitButtonOptions, TextElementType, TextField, TextProps, TokenContext, ValidationError, ValidationMessages, ValidatorConfig, ValueFieldComponent, ValueHandlingMode, ValueType, WithInputSignals };
|