@ng-forge/dynamic-forms 1.2.0-next.3 → 1.2.0-next.4
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-array-field.component-B9OfjKPI.mjs → ng-forge-dynamic-forms-array-field.component-BLPWSurR.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-array-field.component-B9OfjKPI.mjs.map → ng-forge-dynamic-forms-array-field.component-BLPWSurR.mjs.map} +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-VJBOH393.mjs → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-jHiY95pr.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-VJBOH393.mjs.map → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-jHiY95pr.mjs.map} +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-container-field.component-o49q6akV.mjs → ng-forge-dynamic-forms-container-field.component-ug5tp6kt.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-container-field.component-o49q6akV.mjs.map → ng-forge-dynamic-forms-container-field.component-ug5tp6kt.mjs.map} +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-group-field.component-DA-FW30T.mjs → ng-forge-dynamic-forms-group-field.component-DyD00a1U.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-group-field.component-DA-FW30T.mjs.map → ng-forge-dynamic-forms-group-field.component-DyD00a1U.mjs.map} +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-CUihkwGC.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-BGRxIQ2V.mjs} +160 -140
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-BGRxIQ2V.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-P9O4eNvS.mjs → ng-forge-dynamic-forms-page-field.component-B7A2v1vN.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-P9O4eNvS.mjs.map → ng-forge-dynamic-forms-page-field.component-B7A2v1vN.mjs.map} +1 -1
- package/fesm2022/ng-forge-dynamic-forms.mjs +1 -1
- package/package.json +1 -1
- package/types/ng-forge-dynamic-forms.d.ts +36 -14
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-CUihkwGC.mjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, DestroyRef, Injector, EnvironmentInjector, viewChild, TemplateRef, ViewContainerRef, input, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
-
import { i as injectFieldRegistry, c as createFieldResolutionPipe, r as resolveWrappers, a as isSameWrapperChain, b as createWrapperChainController, D as DfFieldOutlet } from './ng-forge-dynamic-forms-ng-forge-dynamic-forms-
|
|
3
|
+
import { i as injectFieldRegistry, c as createFieldResolutionPipe, r as resolveWrappers, a as isSameWrapperChain, b as createWrapperChainController, D as DfFieldOutlet } from './ng-forge-dynamic-forms-ng-forge-dynamic-forms-BGRxIQ2V.mjs';
|
|
4
4
|
import { EventBus, DynamicFormLogger, WRAPPER_AUTO_ASSOCIATIONS, DEFAULT_WRAPPERS, derivedFromDeferred } from '@ng-forge/dynamic-forms/internal';
|
|
5
5
|
import { c as computeContainerHostClasses, s as setupContainerInitEffect } from './ng-forge-dynamic-forms-container-utils-BZFz6ztF.mjs';
|
|
6
6
|
|
|
@@ -86,4 +86,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
86
86
|
}], ctorParameters: () => [], propDecorators: { childrenTpl: [{ type: i0.ViewChild, args: ['childrenTpl', { ...{ read: TemplateRef }, isSignal: true }] }], wrapperContainer: [{ type: i0.ViewChild, args: ['wrapperContainer', { ...{ read: ViewContainerRef }, isSignal: true }] }], field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], hidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidden", required: false }] }] } });
|
|
87
87
|
|
|
88
88
|
export { ContainerFieldComponent, ContainerFieldComponent as default };
|
|
89
|
-
//# sourceMappingURL=ng-forge-dynamic-forms-container-field.component-
|
|
89
|
+
//# sourceMappingURL=ng-forge-dynamic-forms-container-field.component-ug5tp6kt.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-forge-dynamic-forms-container-field.component-
|
|
1
|
+
{"version":3,"file":"ng-forge-dynamic-forms-container-field.component-ug5tp6kt.mjs","mappings":";;;;;;AAoDc;AACK;;AAEA;AACE;AACF;AACA;AACA;;AAGA;AACA;;;;;AAIjB;;;;AAGS;;AACA;;;;AAGQ;;AAEE;AAGf;AACA;;;AAGA;AACE;;;AAKI;;AAIP;AAIc;AAIjB;;AAGE;;;AAGE;AACD;;;AAxDgB;;;;;;;;;AAZlB;;;;AAXS;;;;;;;;;;AAcR;AACA;AACA;AACA;AACA;AACA;;AAcgD","names":[],"ignoreList":[],"sources":["../../../../packages/dynamic-forms/src/lib/fields/container/container-field.component.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n EnvironmentInjector,\n inject,\n Injector,\n input,\n TemplateRef,\n viewChild,\n ViewContainerRef,\n} from '@angular/core';\nimport { DfFieldOutlet } from '../../directives/df-field-outlet/df-field-outlet.directive';\nimport { derivedFromDeferred } from '@ng-forge/dynamic-forms/internal';\nimport { createFieldResolutionPipe, ResolvedField } from '../../utils/resolve-field/resolve-field';\nimport { computeContainerHostClasses, setupContainerInitEffect } from '../../utils/container-utils/container-utils';\nimport { ContainerField } from '@ng-forge/dynamic-forms/internal';\nimport { injectFieldRegistry } from '../../utils/inject-field-registry/inject-field-registry';\nimport { EventBus } from '@ng-forge/dynamic-forms/internal';\nimport { FieldDef } from '@ng-forge/dynamic-forms/internal';\nimport { DynamicFormLogger } from '@ng-forge/dynamic-forms/internal';\nimport { WRAPPER_AUTO_ASSOCIATIONS } from '@ng-forge/dynamic-forms/internal';\nimport { DEFAULT_WRAPPERS } from '@ng-forge/dynamic-forms/internal';\nimport { isSameWrapperChain, resolveWrappers } from '../../utils/resolve-wrappers/resolve-wrappers';\nimport { createWrapperChainController } from '../../utils/wrapper-chain/wrapper-chain-controller';\n\n/** Layout container that wraps child fields with UI chrome. */\n@Component({\n selector: 'div[container-field]',\n imports: [DfFieldOutlet],\n template: `\n <ng-template #childrenTpl>\n @for (field of resolvedFields(); track field.key) {\n @if (!field.hidden()) {\n <ng-container *dfFieldOutlet=\"field; environmentInjector: environmentInjector\" />\n }\n }\n </ng-template>\n <ng-container #wrapperContainer></ng-container>\n `,\n styleUrl: './container-field.component.scss',\n host: {\n '[class]': 'hostClasses()',\n '[class.disabled]': 'disabled()',\n '[class.df-container-hidden]': 'hidden()',\n '[attr.aria-hidden]': 'hidden() || null',\n '[id]': '`${key()}`',\n '[attr.data-testid]': 'key()',\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class ContainerFieldComponent {\n private readonly destroyRef = inject(DestroyRef);\n private readonly fieldRegistry = injectFieldRegistry();\n private readonly injector = inject(Injector);\n protected readonly environmentInjector = inject(EnvironmentInjector);\n private readonly eventBus = inject(EventBus);\n private readonly logger = inject(DynamicFormLogger);\n private readonly wrapperAutoAssociations = inject(WRAPPER_AUTO_ASSOCIATIONS);\n private readonly defaultWrappersSignal = inject(DEFAULT_WRAPPERS, { optional: true });\n\n private readonly childrenTpl = viewChild.required('childrenTpl', { read: TemplateRef });\n private readonly wrapperContainer = viewChild.required('wrapperContainer', { read: ViewContainerRef });\n\n field = input.required<ContainerField>();\n key = input.required<string>();\n className = input<string>();\n hidden = input(false);\n\n readonly hostClasses = computed(() => computeContainerHostClasses('container', this.className()));\n readonly disabled = computed(() => this.field().disabled || false);\n\n private readonly rawFieldRegistry = computed(() => this.fieldRegistry.raw);\n private readonly fieldsSource = computed(() => (this.field().fields || []) as FieldDef<unknown>[]);\n\n protected readonly resolvedFields = derivedFromDeferred(\n this.fieldsSource,\n createFieldResolutionPipe(() => ({\n loadTypeComponent: (type: string) => this.fieldRegistry.loadTypeComponent(type),\n registry: this.rawFieldRegistry(),\n injector: this.injector,\n destroyRef: this.destroyRef,\n onError: (fieldDef: FieldDef<unknown>, error: unknown) => {\n const fieldKey = fieldDef.key || '<no key>';\n\n const containerKey = this.field().key || '<no key>';\n this.logger.error(\n `Failed to load component for field type '${fieldDef.type}' (key: ${fieldKey}) ` +\n `within container '${containerKey}'. Ensure the field type is registered in your field registry.`,\n error,\n );\n },\n })),\n { initialValue: [] as ResolvedField[], injector: this.injector },\n );\n\n private readonly wrappers = computed(() => resolveWrappers(this.field(), this.defaultWrappersSignal?.(), this.wrapperAutoAssociations), {\n equal: isSameWrapperChain,\n });\n\n constructor() {\n setupContainerInitEffect(this.resolvedFields, this.eventBus, 'container', () => this.field().key, this.injector);\n\n createWrapperChainController({\n vcr: this.wrapperContainer,\n wrappers: this.wrappers,\n renderInnermost: (slot) => slot.createEmbeddedView(this.childrenTpl()),\n });\n }\n}\n\nexport { ContainerFieldComponent };\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, DestroyRef, Injector, EnvironmentInjector, input, computed, linkedSignal, runInInjectionContext, untracked, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
-
import { i as injectFieldRegistry, C as CONTAINER_FIELD_PROCESSORS, d as createSchemaFromFields, c as createFieldResolutionPipe, D as DfFieldOutlet } from './ng-forge-dynamic-forms-ng-forge-dynamic-forms-
|
|
3
|
+
import { i as injectFieldRegistry, C as CONTAINER_FIELD_PROCESSORS, d as createSchemaFromFields, c as createFieldResolutionPipe, D as DfFieldOutlet } from './ng-forge-dynamic-forms-ng-forge-dynamic-forms-BGRxIQ2V.mjs';
|
|
4
4
|
import { outputFromObservable, toObservable } from '@angular/core/rxjs-interop';
|
|
5
5
|
import { explicitEffect } from 'ngxtension/explicit-effect';
|
|
6
6
|
import { injectFieldSignalContext, GROUP_CONTEXT, EventBus, DynamicFormLogger, isEqual, FIELD_SIGNAL_CONTEXT, derivedFromDeferred } from '@ng-forge/dynamic-forms/internal';
|
|
@@ -178,4 +178,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
178
178
|
}], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], hidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidden", required: false }] }], validityChange: [{ type: i0.Output, args: ["validityChange"] }], dirtyChange: [{ type: i0.Output, args: ["dirtyChange"] }], submitted: [{ type: i0.Output, args: ["submitted"] }] } });
|
|
179
179
|
|
|
180
180
|
export { GroupFieldComponent, GroupFieldComponent as default };
|
|
181
|
-
//# sourceMappingURL=ng-forge-dynamic-forms-group-field.component-
|
|
181
|
+
//# sourceMappingURL=ng-forge-dynamic-forms-group-field.component-DyD00a1U.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-forge-dynamic-forms-group-field.component-DA-FW30T.mjs","mappings":";;;;;;;;;AA0Dc;YAKK;;;;AAIA;AACE;AACF;AACA;YAMA;;;;;AAQjB;;;;YAOS;;;;AAIQ;AACf;AACA;AAEA;AACE;AACA;;AAEA;;AAGE;AACA;;;;;;;AAQF;AACA;AACA;AACA;;;;;;;AAOJ,IAKiB;;;AAIb;;AAEA;AACF;AAEE;AACA;AACD;AAGc;AACf;AACE;;AAGE;AACA;;AAGF;AACF;;;;;AAQO;;AACA;;AACA;;AACA;;AACA;;AACA;;AAEQ;AACf;;AAEA;;;;AAIA;;;AAGE;;AAEA;AACE;;;;AAKN,IAMiB;AACf;;;AAGE;AACF;;AAGe;;AAEf;;;AAGC;AACF;;;AAQQ;;;AAQU;AAGf;AACA;;;AAGA;AACE;;;;AAOH;YAQH;;;;;AAWE;;AAIM;;AAIJ;;;AA/Me;;;;;;AAhBlB;;;;AARS;;;;;;;AAWR;AACA;AACA;AACA;AACA;wEAIA;AACA","names":[],"ignoreList":[],"sources":["../../../../packages/dynamic-forms/src/lib/fields/group/group-field.component.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n EnvironmentInjector,\n inject,\n Injector,\n input,\n linkedSignal,\n runInInjectionContext,\n untracked,\n} from '@angular/core';\nimport { DfFieldOutlet } from '../../directives/df-field-outlet/df-field-outlet.directive';\nimport { outputFromObservable, toObservable } from '@angular/core/rxjs-interop';\nimport { explicitEffect } from 'ngxtension/explicit-effect';\nimport { derivedFromDeferred } from '@ng-forge/dynamic-forms/internal';\nimport { createFieldResolutionPipe, ResolvedField } from '../../utils/resolve-field/resolve-field';\nimport { computeContainerHostClasses, setupContainerInitEffect } from '../../utils/container-utils/container-utils';\nimport { CONTAINER_FIELD_PROCESSORS } from '../../utils/container-utils/container-field-processors';\nimport { isEqual } from '@ng-forge/dynamic-forms/internal';\nimport { DynamicFormLogger } from '@ng-forge/dynamic-forms/internal';\nimport { GroupField } from '@ng-forge/dynamic-forms/internal';\nimport { injectFieldRegistry } from '../../utils/inject-field-registry/inject-field-registry';\nimport { FieldTree, form } from '@angular/forms/signals';\nimport { FieldDef } from '@ng-forge/dynamic-forms/internal';\nimport { FieldSignalContext, GroupContext } from '@ng-forge/dynamic-forms/internal';\nimport { FIELD_SIGNAL_CONTEXT, GROUP_CONTEXT, injectFieldSignalContext } from '@ng-forge/dynamic-forms/internal';\nimport { createSchemaFromFields } from '../../core/schema-builder';\nimport { EventBus } from '@ng-forge/dynamic-forms/internal';\nimport { FormSubmitEvent } from '../../events/constants/submit.event';\n\n/** Container component for rendering nested form groups. */\n@Component({\n selector: 'fieldset[group-field]',\n imports: [DfFieldOutlet],\n template: `\n @for (field of resolvedFields(); track field.key) {\n @if (!field.hidden()) {\n <ng-container *dfFieldOutlet=\"field; environmentInjector: environmentInjector\" />\n }\n }\n `,\n styleUrl: './group-field.component.scss',\n host: {\n '[class]': 'hostClasses()',\n role: 'group',\n '[class.disabled]': 'disabled()',\n '[class.df-container-hidden]': 'hidden()',\n '[attr.aria-hidden]': 'hidden() || null',\n // The group element's own id is the plain `key()` — only its DESCENDANTS\n // compose scoped ids via GROUP_CONTEXT (e.g. children of an `address`\n // group render as `address_street`). The group selector is `#address`.\n '[id]': '`${key()}`',\n '[attr.data-testid]': 'key()',\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class GroupFieldComponent<TModel extends Record<string, unknown> = Record<string, unknown>> {\n // ─────────────────────────────────────────────────────────────────────────────\n // Dependencies\n // ─────────────────────────────────────────────────────────────────────────────\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly fieldRegistry = injectFieldRegistry();\n private readonly parentFieldSignalContext = injectFieldSignalContext<TModel>();\n private readonly parentGroupContext = inject(GROUP_CONTEXT, { optional: true });\n private readonly injector = inject(Injector);\n protected readonly environmentInjector = inject(EnvironmentInjector);\n private readonly eventBus = inject(EventBus);\n private readonly logger = inject(DynamicFormLogger);\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Memoized Functions\n // ─────────────────────────────────────────────────────────────────────────────\n\n private readonly fieldProcessors = inject(CONTAINER_FIELD_PROCESSORS);\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Inputs\n // ─────────────────────────────────────────────────────────────────────────────\n\n field = input.required<GroupField>();\n key = input.required<string>();\n className = input<string>();\n hidden = input(false);\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Computed Signals\n // ─────────────────────────────────────────────────────────────────────────────\n\n readonly hostClasses = computed(() => computeContainerHostClasses('group', this.className()));\n\n private readonly rawFieldRegistry = computed(() => this.fieldRegistry.raw);\n\n private readonly formSetup = computed(() => {\n const groupField = this.field();\n const registry = this.rawFieldRegistry();\n\n if (groupField.fields && groupField.fields.length > 0) {\n const flattenedFields = this.fieldProcessors.memoizedFlattenFields(groupField.fields, registry);\n const flattenedFieldsForRendering = this.fieldProcessors.memoizedFlattenFieldsForRendering(groupField.fields, registry);\n const fieldsById = this.fieldProcessors.memoizedKeyBy(flattenedFields);\n const defaultValues = this.fieldProcessors.memoizedDefaultValues(fieldsById, registry);\n\n return {\n fields: flattenedFieldsForRendering,\n schemaFields: flattenedFields,\n originalFields: groupField.fields,\n defaultValues,\n registry,\n };\n }\n\n return {\n fields: [],\n schemaFields: [],\n originalFields: [],\n defaultValues: {},\n registry,\n };\n });\n\n readonly defaultValues = linkedSignal(() => this.formSetup().defaultValues);\n\n /**\n * Entity computed from parent value, group key, and defaults.\n * Uses deep equality check to prevent unnecessary updates when\n * object spread creates new references with identical values.\n */\n private readonly entity = linkedSignal(\n () => {\n const parentValue = this.parentFieldSignalContext.value();\n const groupKey = this.field().key;\n const defaults = this.defaultValues();\n const groupValue = (parentValue as Record<string, unknown>)?.[groupKey] || {};\n return { ...defaults, ...groupValue };\n },\n {\n debugName: 'GroupFieldComponent.entity',\n equal: isEqual,\n },\n );\n\n private readonly form = computed(() => {\n return runInInjectionContext(this.injector, () => {\n const setup = this.formSetup();\n\n if (setup.schemaFields.length > 0) {\n const schema = createSchemaFromFields(setup.schemaFields, setup.registry);\n return untracked(() => form(this.entity, schema));\n }\n\n return untracked(() => form(this.entity));\n });\n });\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Public State Signals\n // ─────────────────────────────────────────────────────────────────────────────\n\n readonly formValue = computed(() => this.entity());\n readonly valid = computed(() => this.form()().valid());\n readonly invalid = computed(() => this.form()().invalid());\n readonly dirty = computed(() => this.form()().dirty());\n readonly touched = computed(() => this.form()().touched());\n readonly errors = computed(() => this.form()().errors());\n readonly disabled = computed(() => this.form()().disabled());\n\n private readonly nestedFieldTree = computed((): FieldTree<Record<string, unknown>> | undefined => {\n const parentForm = this.parentFieldSignalContext.form as Record<string, FieldTree<Record<string, unknown>>>;\n const groupKey = this.field().key;\n return parentForm[groupKey];\n });\n\n private readonly groupFieldSignalContext: FieldSignalContext<Record<string, unknown>> = (() => {\n const nestedFieldTree = this.nestedFieldTree;\n return {\n injector: this.injector,\n value: this.parentFieldSignalContext.value,\n defaultValues: this.defaultValues,\n get form() {\n return nestedFieldTree() ?? ({} as FieldTree<Record<string, unknown>>);\n },\n };\n })();\n\n /**\n * Group context propagated to descendants — carries the dot-separated path of\n * group ancestors so child fields can scope their DOM IDs (issue #401).\n * Reactive via `computed()`: a nested group composes its path from the parent\n * context signal + its own key, so the chain stays consistent if either changes.\n */\n private readonly groupContext: GroupContext = {\n groupPath: computed(() => {\n const ownKey = this.field().key;\n const parentPath = this.parentGroupContext?.groupPath();\n return parentPath ? `${parentPath}.${ownKey}` : ownKey;\n }),\n };\n\n private readonly groupInjector = Injector.create({\n parent: this.injector,\n providers: [\n { provide: FIELD_SIGNAL_CONTEXT, useValue: this.groupFieldSignalContext },\n { provide: GROUP_CONTEXT, useValue: this.groupContext },\n ],\n });\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Outputs\n // ─────────────────────────────────────────────────────────────────────────────\n\n readonly validityChange = outputFromObservable(toObservable(this.valid));\n readonly dirtyChange = outputFromObservable(toObservable(this.dirty));\n readonly submitted = outputFromObservable(this.eventBus.on<FormSubmitEvent>('submit'));\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Field Resolution\n // ─────────────────────────────────────────────────────────────────────────────\n\n private readonly fieldsSource = computed(() => this.formSetup().fields);\n\n protected readonly resolvedFields = derivedFromDeferred(\n this.fieldsSource,\n createFieldResolutionPipe(() => ({\n loadTypeComponent: (type: string) => this.fieldRegistry.loadTypeComponent(type),\n registry: this.rawFieldRegistry(),\n injector: this.groupInjector,\n destroyRef: this.destroyRef,\n onError: (fieldDef: FieldDef<unknown>, error: unknown) => {\n const fieldKey = fieldDef.key || '<no key>';\n this.logger.error(\n `Failed to load component for field type '${fieldDef.type}' (key: ${fieldKey}) ` +\n `within group '${this.field().key}'. Ensure the field type is registered in your field registry.`,\n error,\n );\n },\n })),\n { initialValue: [] as ResolvedField[], injector: this.injector },\n );\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Constructor\n // ─────────────────────────────────────────────────────────────────────────────\n\n constructor() {\n this.setupEffects();\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Private Methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n private setupEffects(): void {\n setupContainerInitEffect(this.resolvedFields, this.eventBus, 'group', () => this.field().key, this.injector);\n\n explicitEffect(\n [this.nestedFieldTree, this.field],\n ([tree, field]) => {\n if (!tree) {\n this.logger.warn(\n `Group field \"${field.key}\" not found in parent form. ` + `Ensure the parent form schema includes this group field.`,\n );\n }\n },\n { defer: true },\n );\n }\n}\n\nexport { GroupFieldComponent };\n"]}
|
|
1
|
+
{"version":3,"file":"ng-forge-dynamic-forms-group-field.component-DyD00a1U.mjs","mappings":";;;;;;;;;AA0Dc;YAKK;;;;AAIA;AACE;AACF;AACA;YAMA;;;;;AAQjB;;;;YAOS;;;;AAIQ;AACf;AACA;AAEA;AACE;AACA;;AAEA;;AAGE;AACA;;;;;;;AAQF;AACA;AACA;AACA;;;;;;;AAOJ,IAKiB;;;AAIb;;AAEA;AACF;AAEE;AACA;AACD;AAGc;AACf;AACE;;AAGE;AACA;;AAGF;AACF;;;;;AAQO;;AACA;;AACA;;AACA;;AACA;;AACA;;AAEQ;AACf;;AAEA;;;;AAIA;;;AAGE;;AAEA;AACE;;;;AAKN,IAMiB;AACf;;;AAGE;AACF;;AAGe;;AAEf;;;AAGC;AACF;;;AAQQ;;;AAQU;AAGf;AACA;;;AAGA;AACE;;;;AAOH;YAQH;;;;;AAWE;;AAIM;;AAIJ;;;AA/Me;;;;;;AAhBlB;;;;AARS;;;;;;;AAWR;AACA;AACA;AACA;AACA;wEAIA;AACA","names":[],"ignoreList":[],"sources":["../../../../packages/dynamic-forms/src/lib/fields/group/group-field.component.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n EnvironmentInjector,\n inject,\n Injector,\n input,\n linkedSignal,\n runInInjectionContext,\n untracked,\n} from '@angular/core';\nimport { DfFieldOutlet } from '../../directives/df-field-outlet/df-field-outlet.directive';\nimport { outputFromObservable, toObservable } from '@angular/core/rxjs-interop';\nimport { explicitEffect } from 'ngxtension/explicit-effect';\nimport { derivedFromDeferred } from '@ng-forge/dynamic-forms/internal';\nimport { createFieldResolutionPipe, ResolvedField } from '../../utils/resolve-field/resolve-field';\nimport { computeContainerHostClasses, setupContainerInitEffect } from '../../utils/container-utils/container-utils';\nimport { CONTAINER_FIELD_PROCESSORS } from '../../utils/container-utils/container-field-processors';\nimport { isEqual } from '@ng-forge/dynamic-forms/internal';\nimport { DynamicFormLogger } from '@ng-forge/dynamic-forms/internal';\nimport { GroupField } from '@ng-forge/dynamic-forms/internal';\nimport { injectFieldRegistry } from '../../utils/inject-field-registry/inject-field-registry';\nimport { FieldTree, form } from '@angular/forms/signals';\nimport { FieldDef } from '@ng-forge/dynamic-forms/internal';\nimport { FieldSignalContext, GroupContext } from '@ng-forge/dynamic-forms/internal';\nimport { FIELD_SIGNAL_CONTEXT, GROUP_CONTEXT, injectFieldSignalContext } from '@ng-forge/dynamic-forms/internal';\nimport { createSchemaFromFields } from '../../core/schema-builder';\nimport { EventBus } from '@ng-forge/dynamic-forms/internal';\nimport { FormSubmitEvent } from '../../events/constants/submit.event';\n\n/** Container component for rendering nested form groups. */\n@Component({\n selector: 'fieldset[group-field]',\n imports: [DfFieldOutlet],\n template: `\n @for (field of resolvedFields(); track field.key) {\n @if (!field.hidden()) {\n <ng-container *dfFieldOutlet=\"field; environmentInjector: environmentInjector\" />\n }\n }\n `,\n styleUrl: './group-field.component.scss',\n host: {\n '[class]': 'hostClasses()',\n role: 'group',\n '[class.disabled]': 'disabled()',\n '[class.df-container-hidden]': 'hidden()',\n '[attr.aria-hidden]': 'hidden() || null',\n // The group element's own id is the plain `key()` — only its DESCENDANTS\n // compose scoped ids via GROUP_CONTEXT (e.g. children of an `address`\n // group render as `address_street`). The group selector is `#address`.\n '[id]': '`${key()}`',\n '[attr.data-testid]': 'key()',\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class GroupFieldComponent<TModel extends Record<string, unknown> = Record<string, unknown>> {\n // ─────────────────────────────────────────────────────────────────────────────\n // Dependencies\n // ─────────────────────────────────────────────────────────────────────────────\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly fieldRegistry = injectFieldRegistry();\n private readonly parentFieldSignalContext = injectFieldSignalContext<TModel>();\n private readonly parentGroupContext = inject(GROUP_CONTEXT, { optional: true });\n private readonly injector = inject(Injector);\n protected readonly environmentInjector = inject(EnvironmentInjector);\n private readonly eventBus = inject(EventBus);\n private readonly logger = inject(DynamicFormLogger);\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Memoized Functions\n // ─────────────────────────────────────────────────────────────────────────────\n\n private readonly fieldProcessors = inject(CONTAINER_FIELD_PROCESSORS);\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Inputs\n // ─────────────────────────────────────────────────────────────────────────────\n\n field = input.required<GroupField>();\n key = input.required<string>();\n className = input<string>();\n hidden = input(false);\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Computed Signals\n // ─────────────────────────────────────────────────────────────────────────────\n\n readonly hostClasses = computed(() => computeContainerHostClasses('group', this.className()));\n\n private readonly rawFieldRegistry = computed(() => this.fieldRegistry.raw);\n\n private readonly formSetup = computed(() => {\n const groupField = this.field();\n const registry = this.rawFieldRegistry();\n\n if (groupField.fields && groupField.fields.length > 0) {\n const flattenedFields = this.fieldProcessors.memoizedFlattenFields(groupField.fields, registry);\n const flattenedFieldsForRendering = this.fieldProcessors.memoizedFlattenFieldsForRendering(groupField.fields, registry);\n const fieldsById = this.fieldProcessors.memoizedKeyBy(flattenedFields);\n const defaultValues = this.fieldProcessors.memoizedDefaultValues(fieldsById, registry);\n\n return {\n fields: flattenedFieldsForRendering,\n schemaFields: flattenedFields,\n originalFields: groupField.fields,\n defaultValues,\n registry,\n };\n }\n\n return {\n fields: [],\n schemaFields: [],\n originalFields: [],\n defaultValues: {},\n registry,\n };\n });\n\n readonly defaultValues = linkedSignal(() => this.formSetup().defaultValues);\n\n /**\n * Entity computed from parent value, group key, and defaults.\n * Uses deep equality check to prevent unnecessary updates when\n * object spread creates new references with identical values.\n */\n private readonly entity = linkedSignal(\n () => {\n const parentValue = this.parentFieldSignalContext.value();\n const groupKey = this.field().key;\n const defaults = this.defaultValues();\n const groupValue = (parentValue as Record<string, unknown>)?.[groupKey] || {};\n return { ...defaults, ...groupValue };\n },\n {\n debugName: 'GroupFieldComponent.entity',\n equal: isEqual,\n },\n );\n\n private readonly form = computed(() => {\n return runInInjectionContext(this.injector, () => {\n const setup = this.formSetup();\n\n if (setup.schemaFields.length > 0) {\n const schema = createSchemaFromFields(setup.schemaFields, setup.registry);\n return untracked(() => form(this.entity, schema));\n }\n\n return untracked(() => form(this.entity));\n });\n });\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Public State Signals\n // ─────────────────────────────────────────────────────────────────────────────\n\n readonly formValue = computed(() => this.entity());\n readonly valid = computed(() => this.form()().valid());\n readonly invalid = computed(() => this.form()().invalid());\n readonly dirty = computed(() => this.form()().dirty());\n readonly touched = computed(() => this.form()().touched());\n readonly errors = computed(() => this.form()().errors());\n readonly disabled = computed(() => this.form()().disabled());\n\n private readonly nestedFieldTree = computed((): FieldTree<Record<string, unknown>> | undefined => {\n const parentForm = this.parentFieldSignalContext.form as Record<string, FieldTree<Record<string, unknown>>>;\n const groupKey = this.field().key;\n return parentForm[groupKey];\n });\n\n private readonly groupFieldSignalContext: FieldSignalContext<Record<string, unknown>> = (() => {\n const nestedFieldTree = this.nestedFieldTree;\n return {\n injector: this.injector,\n value: this.parentFieldSignalContext.value,\n defaultValues: this.defaultValues,\n get form() {\n return nestedFieldTree() ?? ({} as FieldTree<Record<string, unknown>>);\n },\n };\n })();\n\n /**\n * Group context propagated to descendants — carries the dot-separated path of\n * group ancestors so child fields can scope their DOM IDs (issue #401).\n * Reactive via `computed()`: a nested group composes its path from the parent\n * context signal + its own key, so the chain stays consistent if either changes.\n */\n private readonly groupContext: GroupContext = {\n groupPath: computed(() => {\n const ownKey = this.field().key;\n const parentPath = this.parentGroupContext?.groupPath();\n return parentPath ? `${parentPath}.${ownKey}` : ownKey;\n }),\n };\n\n private readonly groupInjector = Injector.create({\n parent: this.injector,\n providers: [\n { provide: FIELD_SIGNAL_CONTEXT, useValue: this.groupFieldSignalContext },\n { provide: GROUP_CONTEXT, useValue: this.groupContext },\n ],\n });\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Outputs\n // ─────────────────────────────────────────────────────────────────────────────\n\n readonly validityChange = outputFromObservable(toObservable(this.valid));\n readonly dirtyChange = outputFromObservable(toObservable(this.dirty));\n readonly submitted = outputFromObservable(this.eventBus.on<FormSubmitEvent>('submit'));\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Field Resolution\n // ─────────────────────────────────────────────────────────────────────────────\n\n private readonly fieldsSource = computed(() => this.formSetup().fields);\n\n protected readonly resolvedFields = derivedFromDeferred(\n this.fieldsSource,\n createFieldResolutionPipe(() => ({\n loadTypeComponent: (type: string) => this.fieldRegistry.loadTypeComponent(type),\n registry: this.rawFieldRegistry(),\n injector: this.groupInjector,\n destroyRef: this.destroyRef,\n onError: (fieldDef: FieldDef<unknown>, error: unknown) => {\n const fieldKey = fieldDef.key || '<no key>';\n this.logger.error(\n `Failed to load component for field type '${fieldDef.type}' (key: ${fieldKey}) ` +\n `within group '${this.field().key}'. Ensure the field type is registered in your field registry.`,\n error,\n );\n },\n })),\n { initialValue: [] as ResolvedField[], injector: this.injector },\n );\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Constructor\n // ─────────────────────────────────────────────────────────────────────────────\n\n constructor() {\n this.setupEffects();\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Private Methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n private setupEffects(): void {\n setupContainerInitEffect(this.resolvedFields, this.eventBus, 'group', () => this.field().key, this.injector);\n\n explicitEffect(\n [this.nestedFieldTree, this.field],\n ([tree, field]) => {\n if (!tree) {\n this.logger.warn(\n `Group field \"${field.key}\" not found in parent form. ` + `Ensure the parent form schema includes this group field.`,\n );\n }\n },\n { defer: true },\n );\n }\n}\n\nexport { GroupFieldComponent };\n"]}
|
|
@@ -437,10 +437,6 @@ class FormSubmitEvent {
|
|
|
437
437
|
type = 'submit';
|
|
438
438
|
}
|
|
439
439
|
|
|
440
|
-
class NextPageEvent {
|
|
441
|
-
type = 'next-page';
|
|
442
|
-
}
|
|
443
|
-
|
|
444
440
|
class PageChangeEvent {
|
|
445
441
|
currentPageIndex;
|
|
446
442
|
totalPages;
|
|
@@ -456,105 +452,9 @@ class PageChangeEvent {
|
|
|
456
452
|
}
|
|
457
453
|
}
|
|
458
454
|
|
|
459
|
-
class
|
|
460
|
-
type = 'previous-page';
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
class FormResetEvent {
|
|
464
|
-
type = 'form-reset';
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
class FormClearEvent {
|
|
468
|
-
type = 'form-clear';
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
class AppendArrayItemEvent {
|
|
472
|
-
arrayKey;
|
|
473
|
-
template;
|
|
474
|
-
type = 'append-array-item';
|
|
475
|
-
constructor(
|
|
476
|
-
arrayKey,
|
|
477
|
-
template) {
|
|
478
|
-
this.arrayKey = arrayKey;
|
|
479
|
-
this.template = template;
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
class PrependArrayItemEvent {
|
|
484
|
-
arrayKey;
|
|
485
|
-
template;
|
|
486
|
-
type = 'prepend-array-item';
|
|
487
|
-
constructor(
|
|
488
|
-
arrayKey,
|
|
489
|
-
template) {
|
|
490
|
-
this.arrayKey = arrayKey;
|
|
491
|
-
this.template = template;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
class InsertArrayItemEvent {
|
|
496
|
-
arrayKey;
|
|
497
|
-
index;
|
|
498
|
-
template;
|
|
499
|
-
type = 'insert-array-item';
|
|
500
|
-
constructor(
|
|
501
|
-
arrayKey,
|
|
502
|
-
index,
|
|
503
|
-
template) {
|
|
504
|
-
this.arrayKey = arrayKey;
|
|
505
|
-
this.index = index;
|
|
506
|
-
this.template = template;
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
class PopArrayItemEvent {
|
|
511
|
-
arrayKey;
|
|
512
|
-
type = 'pop-array-item';
|
|
513
|
-
constructor(
|
|
514
|
-
arrayKey) {
|
|
515
|
-
this.arrayKey = arrayKey;
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
class ShiftArrayItemEvent {
|
|
520
|
-
arrayKey;
|
|
521
|
-
type = 'shift-array-item';
|
|
522
|
-
constructor(
|
|
523
|
-
arrayKey) {
|
|
524
|
-
this.arrayKey = arrayKey;
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
class MoveArrayItemEvent {
|
|
529
|
-
arrayKey;
|
|
530
|
-
fromIndex;
|
|
531
|
-
toIndex;
|
|
532
|
-
type = 'move-array-item';
|
|
533
|
-
constructor(
|
|
534
|
-
arrayKey,
|
|
535
|
-
fromIndex,
|
|
536
|
-
toIndex) {
|
|
537
|
-
this.arrayKey = arrayKey;
|
|
538
|
-
this.fromIndex = fromIndex;
|
|
539
|
-
this.toIndex = toIndex;
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
class RemoveAtIndexEvent {
|
|
544
|
-
arrayKey;
|
|
545
|
-
index;
|
|
546
|
-
type = 'remove-at-index';
|
|
547
|
-
constructor(
|
|
548
|
-
arrayKey,
|
|
549
|
-
index) {
|
|
550
|
-
this.arrayKey = arrayKey;
|
|
551
|
-
this.index = index;
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
class PageNavigationStateChangeEvent {
|
|
455
|
+
class PagerStateEvent {
|
|
556
456
|
state;
|
|
557
|
-
type = '
|
|
457
|
+
type = 'pager-state';
|
|
558
458
|
constructor(state) {
|
|
559
459
|
this.state = state;
|
|
560
460
|
}
|
|
@@ -615,20 +515,18 @@ class PageOrchestratorComponent {
|
|
|
615
515
|
totalPages,
|
|
616
516
|
isFirstPage: isFirstVisiblePage,
|
|
617
517
|
isLastPage: isLastVisiblePage,
|
|
618
|
-
navigationDisabled: false,
|
|
619
518
|
};
|
|
620
519
|
}, /* @ts-ignore */
|
|
621
520
|
...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
|
|
622
|
-
currentPageValid = computed(() =>
|
|
623
|
-
|
|
521
|
+
currentPageValid = computed(() => this.isPageValid(this.currentPageIndex()), /* @ts-ignore */
|
|
522
|
+
...(ngDevMode ? [{ debugName: "currentPageValid" }] : /* istanbul ignore next */ []));
|
|
523
|
+
isPageValid(pageIndex) {
|
|
624
524
|
const pages = this.pageFields();
|
|
625
525
|
const form = this.form();
|
|
626
|
-
|
|
526
|
+
if (pageIndex < 0 || pageIndex >= pages.length) {
|
|
627
527
|
return true;
|
|
628
528
|
}
|
|
629
|
-
|
|
630
|
-
const pageFields = currentPage.fields || [];
|
|
631
|
-
const leafKeys = collectLeafFieldKeys(pageFields);
|
|
529
|
+
const leafKeys = collectLeafFieldKeys(pages[pageIndex].fields || []);
|
|
632
530
|
for (const fieldKey of leafKeys) {
|
|
633
531
|
const field = form[fieldKey];
|
|
634
532
|
if (field && typeof field === 'function') {
|
|
@@ -639,8 +537,7 @@ class PageOrchestratorComponent {
|
|
|
639
537
|
}
|
|
640
538
|
}
|
|
641
539
|
return true;
|
|
642
|
-
}
|
|
643
|
-
...(ngDevMode ? [{ debugName: "currentPageValid" }] : /* istanbul ignore next */ []));
|
|
540
|
+
}
|
|
644
541
|
extendedFieldSignalContext = computed(() => ({
|
|
645
542
|
...this.fieldSignalContext(),
|
|
646
543
|
currentPageValid: this.currentPageValid,
|
|
@@ -661,7 +558,7 @@ class PageOrchestratorComponent {
|
|
|
661
558
|
if (currentVisiblePosition === -1 && visibleIndices.length > 0) {
|
|
662
559
|
const nearest = this.findNearestVisiblePage(state.currentPageIndex, visibleIndices);
|
|
663
560
|
if (nearest !== -1) {
|
|
664
|
-
this.
|
|
561
|
+
this.executePageChange(nearest);
|
|
665
562
|
}
|
|
666
563
|
}
|
|
667
564
|
});
|
|
@@ -683,13 +580,6 @@ class PageOrchestratorComponent {
|
|
|
683
580
|
newPageIndex: currentState.currentPageIndex,
|
|
684
581
|
error: 'Already on the last visible page',
|
|
685
582
|
};
|
|
686
|
-
}
|
|
687
|
-
if (currentState.navigationDisabled) {
|
|
688
|
-
return {
|
|
689
|
-
success: false,
|
|
690
|
-
newPageIndex: currentState.currentPageIndex,
|
|
691
|
-
error: 'Navigation is currently disabled',
|
|
692
|
-
};
|
|
693
583
|
}
|
|
694
584
|
const currentVisiblePosition = visibleIndices.indexOf(currentState.currentPageIndex);
|
|
695
585
|
if (currentVisiblePosition === -1 || currentVisiblePosition >= visibleIndices.length - 1) {
|
|
@@ -700,7 +590,7 @@ class PageOrchestratorComponent {
|
|
|
700
590
|
};
|
|
701
591
|
}
|
|
702
592
|
const nextVisiblePageIndex = visibleIndices[currentVisiblePosition + 1];
|
|
703
|
-
return this.
|
|
593
|
+
return this.executePageChange(nextVisiblePageIndex);
|
|
704
594
|
}
|
|
705
595
|
navigateToPreviousPage() {
|
|
706
596
|
const currentState = this.state();
|
|
@@ -711,13 +601,6 @@ class PageOrchestratorComponent {
|
|
|
711
601
|
newPageIndex: currentState.currentPageIndex,
|
|
712
602
|
error: 'Already on the first visible page',
|
|
713
603
|
};
|
|
714
|
-
}
|
|
715
|
-
if (currentState.navigationDisabled) {
|
|
716
|
-
return {
|
|
717
|
-
success: false,
|
|
718
|
-
newPageIndex: currentState.currentPageIndex,
|
|
719
|
-
error: 'Navigation is currently disabled',
|
|
720
|
-
};
|
|
721
604
|
}
|
|
722
605
|
const currentVisiblePosition = visibleIndices.indexOf(currentState.currentPageIndex);
|
|
723
606
|
if (currentVisiblePosition <= 0) {
|
|
@@ -728,9 +611,31 @@ class PageOrchestratorComponent {
|
|
|
728
611
|
};
|
|
729
612
|
}
|
|
730
613
|
const prevVisiblePageIndex = visibleIndices[currentVisiblePosition - 1];
|
|
731
|
-
return this.
|
|
614
|
+
return this.executePageChange(prevVisiblePageIndex);
|
|
732
615
|
}
|
|
733
616
|
navigateToPage(pageIndex) {
|
|
617
|
+
const currentIndex = this.state().currentPageIndex;
|
|
618
|
+
const visibleIndices = this.visiblePageIndices();
|
|
619
|
+
if (pageIndex <= currentIndex || !visibleIndices.includes(pageIndex)) {
|
|
620
|
+
return this.executePageChange(pageIndex);
|
|
621
|
+
}
|
|
622
|
+
const disableWhenPageInvalid = this.formOptions?.()?.nextButton?.disableWhenPageInvalid ?? true;
|
|
623
|
+
if (!disableWhenPageInvalid) {
|
|
624
|
+
return this.executePageChange(pageIndex);
|
|
625
|
+
}
|
|
626
|
+
const crossedPages = visibleIndices.filter((index) => index >= currentIndex && index < pageIndex);
|
|
627
|
+
const firstInvalidPage = crossedPages.find((index) => !this.isPageValid(index));
|
|
628
|
+
if (firstInvalidPage === undefined) {
|
|
629
|
+
return this.executePageChange(pageIndex);
|
|
630
|
+
}
|
|
631
|
+
this.executePageChange(firstInvalidPage);
|
|
632
|
+
return {
|
|
633
|
+
success: false,
|
|
634
|
+
newPageIndex: firstInvalidPage,
|
|
635
|
+
error: `Cannot navigate to page ${pageIndex}: page ${firstInvalidPage} has invalid fields`,
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
executePageChange(pageIndex) {
|
|
734
639
|
const currentState = this.state();
|
|
735
640
|
const totalPages = currentState.totalPages;
|
|
736
641
|
if (pageIndex < 0 || pageIndex >= totalPages) {
|
|
@@ -787,7 +692,13 @@ class PageOrchestratorComponent {
|
|
|
787
692
|
.subscribe(() => {
|
|
788
693
|
this.navigateToPreviousPage();
|
|
789
694
|
});
|
|
790
|
-
|
|
695
|
+
this.eventBus
|
|
696
|
+
.on('go-to-page')
|
|
697
|
+
.pipe(takeUntilDestroyed())
|
|
698
|
+
.subscribe((event) => {
|
|
699
|
+
this.navigateToPage(event.pageIndex);
|
|
700
|
+
});
|
|
701
|
+
explicitEffect([this.state], ([state]) => this.eventBus.dispatch(PagerStateEvent, state));
|
|
791
702
|
}
|
|
792
703
|
evaluatePageHidden(page) {
|
|
793
704
|
if (!page.logic || page.logic.length === 0) {
|
|
@@ -863,10 +774,10 @@ class PageOrchestratorComponent {
|
|
|
863
774
|
}
|
|
864
775
|
}
|
|
865
776
|
`, isInline: true, styles: [":host{display:block;position:relative;width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [/* @ts-ignore */
|
|
866
|
-
import('./ng-forge-dynamic-forms-page-field.component-
|
|
777
|
+
import('./ng-forge-dynamic-forms-page-field.component-B7A2v1vN.mjs').then(m => m.default)]] });
|
|
867
778
|
}
|
|
868
779
|
i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "22.0.1", ngImport: i0, type: PageOrchestratorComponent, resolveDeferredDeps: () => [/* @ts-ignore */
|
|
869
|
-
import('./ng-forge-dynamic-forms-page-field.component-
|
|
780
|
+
import('./ng-forge-dynamic-forms-page-field.component-B7A2v1vN.mjs').then(m => m.default)], resolveMetadata: PageFieldComponent => ({ decorators: [{
|
|
870
781
|
type: Component,
|
|
871
782
|
args: [{ selector: 'div[page-orchestrator]', imports: [PageFieldComponent], template: `
|
|
872
783
|
@for (pageField of pageFields(); track pageField.key; let i = $index) {
|
|
@@ -3880,7 +3791,7 @@ function createDerivationRenderGate() {
|
|
|
3880
3791
|
if (!has || engine() !== 'idle')
|
|
3881
3792
|
return;
|
|
3882
3793
|
engine.set('loading');
|
|
3883
|
-
pendingTasks.run(() => import('./ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-
|
|
3794
|
+
pendingTasks.run(() => import('./ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-jHiY95pr.mjs')
|
|
3884
3795
|
.then(({ bootstrapDerivationOrchestrator }) => {
|
|
3885
3796
|
runInInjectionContext(injector, () => bootstrapDerivationOrchestrator());
|
|
3886
3797
|
engine.set('wired');
|
|
@@ -4211,7 +4122,7 @@ class DynamicForm {
|
|
|
4211
4122
|
events = outputFromObservable(this.eventBus.events$);
|
|
4212
4123
|
initialized = outputFromObservable(this.initialized$);
|
|
4213
4124
|
onPageChange = outputFromObservable(this.eventBus.on('page-change'));
|
|
4214
|
-
onPageNavigationStateChange = outputFromObservable(this.eventBus.on('
|
|
4125
|
+
onPageNavigationStateChange = outputFromObservable(this.eventBus.on('pager-state'));
|
|
4215
4126
|
constructor() {
|
|
4216
4127
|
this.dispatcher?.connect(this.eventBus);
|
|
4217
4128
|
this.destroyRef.onDestroy(() => this.dispatcher?.disconnect());
|
|
@@ -4435,28 +4346,28 @@ const DISPLAY_FIELD_TYPES_BASE = {
|
|
|
4435
4346
|
const BUILT_IN_FIELDS = [
|
|
4436
4347
|
{
|
|
4437
4348
|
name: 'row',
|
|
4438
|
-
loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-
|
|
4349
|
+
loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-ug5tp6kt.mjs'),
|
|
4439
4350
|
mapper: rowFieldMapper,
|
|
4440
4351
|
valueHandling: 'flatten',
|
|
4441
4352
|
...CONTAINER_FIELD_TYPES_BASE,
|
|
4442
4353
|
},
|
|
4443
4354
|
{
|
|
4444
4355
|
name: 'group',
|
|
4445
|
-
loadComponent: () => import('./ng-forge-dynamic-forms-group-field.component-
|
|
4356
|
+
loadComponent: () => import('./ng-forge-dynamic-forms-group-field.component-DyD00a1U.mjs'),
|
|
4446
4357
|
mapper: groupFieldMapper,
|
|
4447
4358
|
valueHandling: 'include',
|
|
4448
4359
|
...CONTAINER_FIELD_TYPES_BASE,
|
|
4449
4360
|
},
|
|
4450
4361
|
{
|
|
4451
4362
|
name: 'array',
|
|
4452
|
-
loadComponent: () => import('./ng-forge-dynamic-forms-array-field.component-
|
|
4363
|
+
loadComponent: () => import('./ng-forge-dynamic-forms-array-field.component-BLPWSurR.mjs'),
|
|
4453
4364
|
mapper: arrayFieldMapper,
|
|
4454
4365
|
valueHandling: 'include',
|
|
4455
4366
|
...CONTAINER_FIELD_TYPES_BASE,
|
|
4456
4367
|
},
|
|
4457
4368
|
{
|
|
4458
4369
|
name: 'page',
|
|
4459
|
-
loadComponent: () => import('./ng-forge-dynamic-forms-page-field.component-
|
|
4370
|
+
loadComponent: () => import('./ng-forge-dynamic-forms-page-field.component-B7A2v1vN.mjs'),
|
|
4460
4371
|
mapper: pageFieldMapper,
|
|
4461
4372
|
valueHandling: 'flatten',
|
|
4462
4373
|
...CONTAINER_FIELD_TYPES_BASE,
|
|
@@ -4474,7 +4385,7 @@ const BUILT_IN_FIELDS = [
|
|
|
4474
4385
|
},
|
|
4475
4386
|
{
|
|
4476
4387
|
name: 'container',
|
|
4477
|
-
loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-
|
|
4388
|
+
loadComponent: () => import('./ng-forge-dynamic-forms-container-field.component-ug5tp6kt.mjs'),
|
|
4478
4389
|
mapper: containerFieldMapper,
|
|
4479
4390
|
valueHandling: 'flatten',
|
|
4480
4391
|
...CONTAINER_FIELD_TYPES_BASE,
|
|
@@ -4876,6 +4787,115 @@ function sanitizeFormConfigPure(config, fieldRegistry, typeRegistry, options = {
|
|
|
4876
4787
|
return { sanitized: { ...config, fields: fields }, warnings };
|
|
4877
4788
|
}
|
|
4878
4789
|
|
|
4790
|
+
class GoToPageEvent {
|
|
4791
|
+
pageIndex;
|
|
4792
|
+
type = 'go-to-page';
|
|
4793
|
+
constructor(
|
|
4794
|
+
pageIndex) {
|
|
4795
|
+
this.pageIndex = pageIndex;
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
|
|
4799
|
+
class NextPageEvent {
|
|
4800
|
+
type = 'next-page';
|
|
4801
|
+
}
|
|
4802
|
+
|
|
4803
|
+
class PreviousPageEvent {
|
|
4804
|
+
type = 'previous-page';
|
|
4805
|
+
}
|
|
4806
|
+
|
|
4807
|
+
class FormResetEvent {
|
|
4808
|
+
type = 'form-reset';
|
|
4809
|
+
}
|
|
4810
|
+
|
|
4811
|
+
class FormClearEvent {
|
|
4812
|
+
type = 'form-clear';
|
|
4813
|
+
}
|
|
4814
|
+
|
|
4815
|
+
class AppendArrayItemEvent {
|
|
4816
|
+
arrayKey;
|
|
4817
|
+
template;
|
|
4818
|
+
type = 'append-array-item';
|
|
4819
|
+
constructor(
|
|
4820
|
+
arrayKey,
|
|
4821
|
+
template) {
|
|
4822
|
+
this.arrayKey = arrayKey;
|
|
4823
|
+
this.template = template;
|
|
4824
|
+
}
|
|
4825
|
+
}
|
|
4826
|
+
|
|
4827
|
+
class PrependArrayItemEvent {
|
|
4828
|
+
arrayKey;
|
|
4829
|
+
template;
|
|
4830
|
+
type = 'prepend-array-item';
|
|
4831
|
+
constructor(
|
|
4832
|
+
arrayKey,
|
|
4833
|
+
template) {
|
|
4834
|
+
this.arrayKey = arrayKey;
|
|
4835
|
+
this.template = template;
|
|
4836
|
+
}
|
|
4837
|
+
}
|
|
4838
|
+
|
|
4839
|
+
class InsertArrayItemEvent {
|
|
4840
|
+
arrayKey;
|
|
4841
|
+
index;
|
|
4842
|
+
template;
|
|
4843
|
+
type = 'insert-array-item';
|
|
4844
|
+
constructor(
|
|
4845
|
+
arrayKey,
|
|
4846
|
+
index,
|
|
4847
|
+
template) {
|
|
4848
|
+
this.arrayKey = arrayKey;
|
|
4849
|
+
this.index = index;
|
|
4850
|
+
this.template = template;
|
|
4851
|
+
}
|
|
4852
|
+
}
|
|
4853
|
+
|
|
4854
|
+
class PopArrayItemEvent {
|
|
4855
|
+
arrayKey;
|
|
4856
|
+
type = 'pop-array-item';
|
|
4857
|
+
constructor(
|
|
4858
|
+
arrayKey) {
|
|
4859
|
+
this.arrayKey = arrayKey;
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
|
|
4863
|
+
class ShiftArrayItemEvent {
|
|
4864
|
+
arrayKey;
|
|
4865
|
+
type = 'shift-array-item';
|
|
4866
|
+
constructor(
|
|
4867
|
+
arrayKey) {
|
|
4868
|
+
this.arrayKey = arrayKey;
|
|
4869
|
+
}
|
|
4870
|
+
}
|
|
4871
|
+
|
|
4872
|
+
class MoveArrayItemEvent {
|
|
4873
|
+
arrayKey;
|
|
4874
|
+
fromIndex;
|
|
4875
|
+
toIndex;
|
|
4876
|
+
type = 'move-array-item';
|
|
4877
|
+
constructor(
|
|
4878
|
+
arrayKey,
|
|
4879
|
+
fromIndex,
|
|
4880
|
+
toIndex) {
|
|
4881
|
+
this.arrayKey = arrayKey;
|
|
4882
|
+
this.fromIndex = fromIndex;
|
|
4883
|
+
this.toIndex = toIndex;
|
|
4884
|
+
}
|
|
4885
|
+
}
|
|
4886
|
+
|
|
4887
|
+
class RemoveAtIndexEvent {
|
|
4888
|
+
arrayKey;
|
|
4889
|
+
index;
|
|
4890
|
+
type = 'remove-at-index';
|
|
4891
|
+
constructor(
|
|
4892
|
+
arrayKey,
|
|
4893
|
+
index) {
|
|
4894
|
+
this.arrayKey = arrayKey;
|
|
4895
|
+
this.index = index;
|
|
4896
|
+
}
|
|
4897
|
+
}
|
|
4898
|
+
|
|
4879
4899
|
function arrayEvent(arrayKey) {
|
|
4880
4900
|
return {
|
|
4881
4901
|
append: (template) => new AppendArrayItemEvent(arrayKey, template),
|
|
@@ -4891,5 +4911,5 @@ function arrayEvent(arrayKey) {
|
|
|
4891
4911
|
|
|
4892
4912
|
|
|
4893
4913
|
|
|
4894
|
-
export {
|
|
4895
|
-
//# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-
|
|
4914
|
+
export { withEventFormValue as $, ArrayItemRegistryService as A, BUILT_IN_FIELDS as B, CONTAINER_FIELD_PROCESSORS as C, DfFieldOutlet as D, EventDispatcher as E, FIELD_WINDOWING as F, GoToPageEvent as G, PageChangeEvent as H, InsertArrayItemEvent as I, PagerStateEvent as J, PopArrayItemEvent as K, PrependArrayItemEvent as L, MoveArrayItemEvent as M, NextPageEvent as N, PreviousPageEvent as O, PROPERTY_OVERRIDE_STORE as P, TextAddonComponent as Q, RemoveAtIndexEvent as R, ShiftArrayItemEvent as S, TemplateAddonComponent as T, arrayEvent as U, createWrappers as V, isWrappersBundle as W, provideDynamicForm as X, sanitizeFormConfig as Y, withAddonActions as Z, withCustomAddon as _, isSameWrapperChain as a, withFieldWindowing as a0, withLegacyStatusClasses as a1, withLoggerConfig as a2, withPagePreload as a3, withValidationExecutionDefaults as a4, withValueExclusionDefaults as a5, wrapperProps as a6, createWrapperChainController as b, createFieldResolutionPipe as c, createSchemaFromFields as d, createHiddenSignal as e, createRenderReadySignal as f, getNormalizedArrayMetadata as g, getFieldDefaultValue as h, injectFieldRegistry as i, resolveFieldWindowing as j, DEV_MODE as k, DEFAULT_DEBOUNCE_MS as l, mapFieldToInputs as m, DERIVATION_WARNING_TRACKER as n, FormStateManager as o, DERIVATION_LOG_CONFIG as p, AppendArrayItemEvent as q, resolveWrappers as r, ComponentAddonComponent as s, traverseFieldsWithContext as t, ConsoleLogger as u, DfTemplate as v, DynamicForm as w, FormClearEvent as x, FormResetEvent as y, FormSubmitEvent as z };
|
|
4915
|
+
//# sourceMappingURL=ng-forge-dynamic-forms-ng-forge-dynamic-forms-BGRxIQ2V.mjs.map
|