@iapps/ng-dhis2-ui 1.4.4 → 1.4.6
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.
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { CommonModule } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { NgModule, ContentChild, Input, Directive, inject, ElementRef, ChangeDetectionStrategy, Component, EventEmitter, Output, NgZone, input, Injectable, model, computed, signal, effect, ViewChildren } from '@angular/core';
|
|
3
|
+
import { NgModule, ContentChild, Input, Directive, inject, ElementRef, ChangeDetectionStrategy, Component, EventEmitter, Output, NgZone, input, Injectable, model, computed, signal, effect, DestroyRef, ViewChildren } from '@angular/core';
|
|
4
4
|
import { useDataQuery, useConfig, useAlert, clearSensitiveCaches, DataProvider, useDataEngine, Provider } from '@dhis2/app-runtime';
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import React__default, { useState, useCallback, useRef, useEffect, createContext, useContext, useMemo, memo } from 'react';
|
|
7
7
|
import * as ReactDOM from 'react-dom/client';
|
|
8
|
-
import { from, map, catchError, of, zip, firstValueFrom, filter, take, Subject, takeUntil } from 'rxjs';
|
|
8
|
+
import { from, map, catchError, of, zip, firstValueFrom, filter, take, Subject, takeUntil, startWith, distinctUntilChanged } from 'rxjs';
|
|
9
9
|
import parse from 'html-react-parser';
|
|
10
10
|
import i18n from '@dhis2/d2-i18n';
|
|
11
11
|
import { colors, theme, spacers } from '@dhis2/ui-constants';
|
|
@@ -32,7 +32,7 @@ import { isValid, format, addDays } from 'date-fns';
|
|
|
32
32
|
import * as XLSX from 'xlsx';
|
|
33
33
|
import * as i1 from '@angular/forms';
|
|
34
34
|
import { FormControl, Validators, UntypedFormControl, UntypedFormGroup, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
|
35
|
-
import { toObservable } from '@angular/core/rxjs-interop';
|
|
35
|
+
import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
36
36
|
import { useMapEvents, useMap, MapContainer, TileLayer, GeoJSON, Marker } from 'react-leaflet';
|
|
37
37
|
import moment from 'moment';
|
|
38
38
|
|
|
@@ -12326,7 +12326,7 @@ class FormUtil {
|
|
|
12326
12326
|
});
|
|
12327
12327
|
if (field.referenceKey) {
|
|
12328
12328
|
const value = dataEntities
|
|
12329
|
-
? dataEntities[field.referenceKey]
|
|
12329
|
+
? dataEntities[field.referenceKey] ?? ''
|
|
12330
12330
|
: '';
|
|
12331
12331
|
group[field.referenceKey] = field.required
|
|
12332
12332
|
? new UntypedFormControl({ value, disabled: field.disabled }, {
|
|
@@ -12354,7 +12354,7 @@ class FormUtil {
|
|
|
12354
12354
|
}
|
|
12355
12355
|
static getFieldValue(field, dataEntities) {
|
|
12356
12356
|
const fieldValue = dataEntities
|
|
12357
|
-
? dataEntities[field.id]
|
|
12357
|
+
? dataEntities[field.id] ?? dataEntities[field.key] ?? ''
|
|
12358
12358
|
: '';
|
|
12359
12359
|
return isArray(fieldValue) ? JSON.stringify(fieldValue) : fieldValue;
|
|
12360
12360
|
}
|
|
@@ -12998,6 +12998,31 @@ class FormMetaData {
|
|
|
12998
12998
|
// Use of this source code is governed by a BSD-style
|
|
12999
12999
|
// license that can be found in the LICENSE file.
|
|
13000
13000
|
|
|
13001
|
+
class FormValidationScopeUtil {
|
|
13002
|
+
static resolve(field, config, sections, actions) {
|
|
13003
|
+
const keys = [field.id, field.key, field.code].filter((key) => typeof key === 'string' && key.length > 0);
|
|
13004
|
+
const isMatch = (key) => typeof key === 'string' && keys.includes(key);
|
|
13005
|
+
const hiddenByMetadata = !!field.hidden;
|
|
13006
|
+
const hiddenByRule = (actions ?? []).some((action) => action.actionType === 'HIDEFIELD' && isMatch(action.field));
|
|
13007
|
+
const hiddenByAssignment = !!config?.hideCustomAssignedFields &&
|
|
13008
|
+
(config.autoAssignedValues ?? []).some((assignment) => isMatch(assignment.field));
|
|
13009
|
+
// Section membership is relevant only if the TRACKER form actually uses
|
|
13010
|
+
// configured sections. The fallback template renders all sanitized fields.
|
|
13011
|
+
const hasTrackerSections = config?.formType === 'TRACKER' &&
|
|
13012
|
+
Array.isArray(sections) &&
|
|
13013
|
+
sections.length > 0;
|
|
13014
|
+
const absentFromTrackerSections = !!hasTrackerSections &&
|
|
13015
|
+
!sections.some((section) => (section?.formFields ?? []).some((sectionField) => [sectionField?.id, sectionField?.key, sectionField?.code].some(isMatch)));
|
|
13016
|
+
return {
|
|
13017
|
+
excluded: hiddenByMetadata || hiddenByRule || hiddenByAssignment || absentFromTrackerSections,
|
|
13018
|
+
hiddenByMetadata,
|
|
13019
|
+
hiddenByRule,
|
|
13020
|
+
hiddenByAssignment,
|
|
13021
|
+
absentFromTrackerSections,
|
|
13022
|
+
};
|
|
13023
|
+
}
|
|
13024
|
+
}
|
|
13025
|
+
|
|
13001
13026
|
class FormComponent {
|
|
13002
13027
|
get layoutCssClass() {
|
|
13003
13028
|
if (!this.isFormHorizontal()) {
|
|
@@ -13078,6 +13103,7 @@ class FormComponent {
|
|
|
13078
13103
|
...(ngDevMode ? [{ debugName: "configuration" }] : /* istanbul ignore next */ []));
|
|
13079
13104
|
this.formUpdate = new EventEmitter();
|
|
13080
13105
|
this.formValidityUpdate = new EventEmitter();
|
|
13106
|
+
this.destroyRef = inject(DestroyRef);
|
|
13081
13107
|
// get sanitizedFields(): IFormField<string>[] {
|
|
13082
13108
|
// return (this.fields() || []).filter((field: any) => {
|
|
13083
13109
|
// if (field.hidden) {
|
|
@@ -13116,40 +13142,11 @@ class FormComponent {
|
|
|
13116
13142
|
return map;
|
|
13117
13143
|
}, /* @ts-ignore */
|
|
13118
13144
|
...(ngDevMode ? [{ debugName: "fieldControlKeyById" }] : /* istanbul ignore next */ []));
|
|
13119
|
-
//
|
|
13120
|
-
//
|
|
13121
|
-
|
|
13122
|
-
|
|
13123
|
-
|
|
13124
|
-
// getVisibleSectionFields(section: any): IFormField<string>[] {
|
|
13125
|
-
// const rawFields: IFormField<string>[] = section?.formFields ?? [];
|
|
13126
|
-
// return rawFields.filter((field) => !this.isFieldHiddenByRules(field));
|
|
13127
|
-
// }
|
|
13128
|
-
// private isFieldHiddenByRules(field: IFormField<string>): boolean {
|
|
13129
|
-
// if (field.hidden) {
|
|
13130
|
-
// return true;
|
|
13131
|
-
// }
|
|
13132
|
-
// const type = (field as any).isDataElement
|
|
13133
|
-
// ? 'dataElement'
|
|
13134
|
-
// : 'trackedEntityAttribute';
|
|
13135
|
-
// const elementItem = (field as any)[type] || field;
|
|
13136
|
-
// if (!elementItem) return false;
|
|
13137
|
-
// const rule = (this.programRuleActions() || []).find(
|
|
13138
|
-
// (ruleAction) =>
|
|
13139
|
-
// ruleAction.field === elementItem.id &&
|
|
13140
|
-
// ruleAction.actionType === 'HIDEFIELD'
|
|
13141
|
-
// );
|
|
13142
|
-
// return !!rule;
|
|
13143
|
-
// }
|
|
13144
|
-
// 1) Precompute the hidden field ids from programRuleActions()
|
|
13145
|
-
this.hiddenFieldIds = computed(() => {
|
|
13146
|
-
const actions = this.programRuleActions() || [];
|
|
13147
|
-
return new Set(actions
|
|
13148
|
-
.filter((ruleAction) => ruleAction.actionType === 'HIDEFIELD')
|
|
13149
|
-
.map((ruleAction) => ruleAction.field)
|
|
13150
|
-
.filter((id) => !!id));
|
|
13151
|
-
}, /* @ts-ignore */
|
|
13152
|
-
...(ngDevMode ? [{ debugName: "hiddenFieldIds" }] : /* istanbul ignore next */ []));
|
|
13145
|
+
// Track only controls disabled by this component's visibility handling.
|
|
13146
|
+
// Do not re-enable controls disabled by metadata or other components.
|
|
13147
|
+
this.visibilityDisabledKeys = new Set();
|
|
13148
|
+
this.unrenderedViewDisabledKeys = new Set();
|
|
13149
|
+
this.previousShowErrorIds = new Set();
|
|
13153
13150
|
this.ruleProcessor = effect(() => {
|
|
13154
13151
|
this.#processRules(this.programRuleActions());
|
|
13155
13152
|
}, /* @ts-ignore */
|
|
@@ -13250,6 +13247,9 @@ class FormComponent {
|
|
|
13250
13247
|
return hasShowSectionAction || !hasHideSectionAction;
|
|
13251
13248
|
}
|
|
13252
13249
|
ngOnInit() {
|
|
13250
|
+
// A field can be hidden directly by metadata before program rules run.
|
|
13251
|
+
// Exclude such fields from validation without discarding their values.
|
|
13252
|
+
this.#processRules(this.programRuleActions(), true);
|
|
13253
13253
|
this.values = this.form().getRawValue();
|
|
13254
13254
|
// TODO: This is uneccesary emit at this stage of execution, since nothing has changes at initiation and potentially break some of implementation that depends formUpdate, which also is triggered when there is actual change in the form apart form initial values that came with it
|
|
13255
13255
|
this.formUpdate.emit(new FormValue(this.form(), this.fields()));
|
|
@@ -13258,26 +13258,152 @@ class FormComponent {
|
|
|
13258
13258
|
ngOnChanges(changes) {
|
|
13259
13259
|
this.values = this.form().getRawValue();
|
|
13260
13260
|
}
|
|
13261
|
-
|
|
13262
|
-
|
|
13263
|
-
|
|
13264
|
-
|
|
13265
|
-
|
|
13266
|
-
|
|
13267
|
-
|
|
13268
|
-
|
|
13269
|
-
|
|
13270
|
-
|
|
13271
|
-
|
|
13272
|
-
|
|
13273
|
-
|
|
13261
|
+
ngAfterViewInit() {
|
|
13262
|
+
// For expanded, non-collapsible TRACKER forms, the instantiated field
|
|
13263
|
+
// components are the final authority on what the user can actually edit.
|
|
13264
|
+
// Avoid this policy for collapsible sections: collapsing must never waive
|
|
13265
|
+
// mandatory fields that the user can reveal by expanding a section.
|
|
13266
|
+
if (this.programEntryFormConfig()?.formType !== 'TRACKER' ||
|
|
13267
|
+
this.collapsibleSections())
|
|
13268
|
+
return;
|
|
13269
|
+
queueMicrotask(() => this.syncActuallyRenderedFields());
|
|
13270
|
+
this.fieldComponents.changes
|
|
13271
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
13272
|
+
.subscribe(() => queueMicrotask(() => this.syncActuallyRenderedFields()));
|
|
13273
|
+
}
|
|
13274
|
+
syncActuallyRenderedFields() {
|
|
13275
|
+
if (this.destroyRef.destroyed)
|
|
13276
|
+
return;
|
|
13277
|
+
if (this.programEntryFormConfig()?.formType !== 'TRACKER' ||
|
|
13278
|
+
this.collapsibleSections())
|
|
13279
|
+
return;
|
|
13280
|
+
const renderedIds = new Set(this.fieldComponents.toArray()
|
|
13281
|
+
.map((component) => component.field()?.id)
|
|
13282
|
+
.filter((id) => typeof id === 'string'));
|
|
13283
|
+
// An empty view may be a loading/teardown transition, not an intentionally
|
|
13284
|
+
// empty form. Never disable the entire form based on this transient state.
|
|
13285
|
+
if (renderedIds.size === 0)
|
|
13286
|
+
return;
|
|
13287
|
+
const form = this.form();
|
|
13288
|
+
let changed = false;
|
|
13289
|
+
for (const field of this.fields() ?? []) {
|
|
13290
|
+
if (!field?.id)
|
|
13291
|
+
continue;
|
|
13292
|
+
const key = field.key || field.id;
|
|
13293
|
+
const controlKeys = [key, field.referenceKey].filter((item) => typeof item === 'string' && item.length > 0);
|
|
13294
|
+
const scope = FormValidationScopeUtil.resolve(field, this.programEntryFormConfig(), this.programEntryFormMetaData()?.sections, this.programRuleActions());
|
|
13295
|
+
const actuallyUnrendered = !renderedIds.has(field.id);
|
|
13296
|
+
for (const controlKey of controlKeys) {
|
|
13297
|
+
const control = form.get(controlKey);
|
|
13298
|
+
if (!control)
|
|
13299
|
+
continue;
|
|
13300
|
+
if (actuallyUnrendered) {
|
|
13301
|
+
if (control.enabled) {
|
|
13302
|
+
control.disable({ emitEvent: false });
|
|
13303
|
+
this.unrenderedViewDisabledKeys.add(controlKey);
|
|
13304
|
+
changed = true;
|
|
13274
13305
|
}
|
|
13275
|
-
break;
|
|
13276
13306
|
}
|
|
13277
|
-
|
|
13278
|
-
|
|
13307
|
+
else if (this.unrenderedViewDisabledKeys.delete(controlKey) &&
|
|
13308
|
+
!scope.excluded && !field.disabled && !field.generated &&
|
|
13309
|
+
control.disabled) {
|
|
13310
|
+
control.enable({ emitEvent: false });
|
|
13311
|
+
changed = true;
|
|
13312
|
+
}
|
|
13279
13313
|
}
|
|
13280
|
-
}
|
|
13314
|
+
}
|
|
13315
|
+
if (changed)
|
|
13316
|
+
form.updateValueAndValidity({ emitEvent: true });
|
|
13317
|
+
}
|
|
13318
|
+
#processRules(ruleActions, force = false) {
|
|
13319
|
+
// Share the same visibility/validation policy as FlatFormComponent.
|
|
13320
|
+
const config = this.programEntryFormConfig();
|
|
13321
|
+
const sections = this.programEntryFormMetaData()?.sections;
|
|
13322
|
+
const hasTrackerSections = config?.formType === 'TRACKER' && Array.isArray(sections) && sections.length > 0;
|
|
13323
|
+
// This effect can run before required inputs are set. An empty action set
|
|
13324
|
+
// needs no work until ngOnInit synchronizes metadata-hidden controls.
|
|
13325
|
+
if (!ruleActions.length &&
|
|
13326
|
+
!this.visibilityDisabledKeys.size &&
|
|
13327
|
+
!this.previousShowErrorIds.size &&
|
|
13328
|
+
!hasTrackerSections &&
|
|
13329
|
+
!config?.hideCustomAssignedFields &&
|
|
13330
|
+
!force) {
|
|
13331
|
+
return;
|
|
13332
|
+
}
|
|
13333
|
+
const form = this.form();
|
|
13334
|
+
const showErrorIds = new Set(ruleActions
|
|
13335
|
+
.filter((action) => action.actionType === 'SHOWERROR')
|
|
13336
|
+
.map((action) => action.field)
|
|
13337
|
+
.filter((id) => !!id));
|
|
13338
|
+
let statusChanged = false;
|
|
13339
|
+
let clearedField;
|
|
13340
|
+
for (const field of this.fields() ?? []) {
|
|
13341
|
+
if (!field)
|
|
13342
|
+
continue;
|
|
13343
|
+
const controlKey = field.key || field.id;
|
|
13344
|
+
const control = form.get(controlKey);
|
|
13345
|
+
if (!control)
|
|
13346
|
+
continue;
|
|
13347
|
+
const scope = FormValidationScopeUtil.resolve(field, config, sections, ruleActions);
|
|
13348
|
+
const hiddenByRule = scope.hiddenByRule;
|
|
13349
|
+
const omittedFromSections = scope.absentFromTrackerSections;
|
|
13350
|
+
const hidden = scope.excluded;
|
|
13351
|
+
const originallyDisabled = !!field.disabled || !!field.generated;
|
|
13352
|
+
if (hidden) {
|
|
13353
|
+
// Retain prior HIDEFIELD clearing semantics for editable fields.
|
|
13354
|
+
// Metadata-hidden values (e.g. auto-assigned attributes) are preserved.
|
|
13355
|
+
if (hiddenByRule &&
|
|
13356
|
+
!omittedFromSections &&
|
|
13357
|
+
!originallyDisabled &&
|
|
13358
|
+
control.value != null) {
|
|
13359
|
+
control.setValue(null, { emitEvent: false });
|
|
13360
|
+
clearedField = field;
|
|
13361
|
+
statusChanged = true;
|
|
13362
|
+
}
|
|
13363
|
+
}
|
|
13364
|
+
// Keep both the field's control and any generated reference control in
|
|
13365
|
+
// the same validation scope; preserve their raw values when hidden.
|
|
13366
|
+
const keys = [controlKey, field.referenceKey].filter((key) => typeof key === 'string' && key.length > 0);
|
|
13367
|
+
for (const key of keys) {
|
|
13368
|
+
const target = form.get(key);
|
|
13369
|
+
if (!target)
|
|
13370
|
+
continue;
|
|
13371
|
+
if (hidden) {
|
|
13372
|
+
if (target.enabled) {
|
|
13373
|
+
target.disable({ emitEvent: false });
|
|
13374
|
+
statusChanged = true;
|
|
13375
|
+
}
|
|
13376
|
+
// Also track initial exclusions already disabled by FlatFormComponent,
|
|
13377
|
+
// so visibility changes can restore them without touching metadata locks.
|
|
13378
|
+
this.visibilityDisabledKeys.add(key);
|
|
13379
|
+
}
|
|
13380
|
+
else if (this.visibilityDisabledKeys.delete(key)) {
|
|
13381
|
+
if (!originallyDisabled && target.disabled) {
|
|
13382
|
+
target.enable({ emitEvent: false });
|
|
13383
|
+
statusChanged = true;
|
|
13384
|
+
}
|
|
13385
|
+
}
|
|
13386
|
+
}
|
|
13387
|
+
// A SHOWERROR action may cease to apply without any control value change.
|
|
13388
|
+
// Remove only its custom error; keep required/pattern/min/max errors.
|
|
13389
|
+
if (this.previousShowErrorIds.has(field.id) &&
|
|
13390
|
+
!showErrorIds.has(field.id) &&
|
|
13391
|
+
control.hasError('customError')) {
|
|
13392
|
+
const remainingErrors = { ...(control.errors ?? {}) };
|
|
13393
|
+
delete remainingErrors['customError'];
|
|
13394
|
+
control.setErrors(Object.keys(remainingErrors).length ? remainingErrors : null, { emitEvent: false });
|
|
13395
|
+
statusChanged = true;
|
|
13396
|
+
}
|
|
13397
|
+
}
|
|
13398
|
+
this.previousShowErrorIds.clear();
|
|
13399
|
+
showErrorIds.forEach((id) => this.previousShowErrorIds.add(id));
|
|
13400
|
+
if (statusChanged) {
|
|
13401
|
+
// Emit a single aggregate validity change for the parent flat form.
|
|
13402
|
+
form.updateValueAndValidity({ emitEvent: true });
|
|
13403
|
+
}
|
|
13404
|
+
if (clearedField) {
|
|
13405
|
+
this.onFieldUpdate(form, clearedField);
|
|
13406
|
+
}
|
|
13281
13407
|
}
|
|
13282
13408
|
onSubmit() {
|
|
13283
13409
|
this.formUpdate.emit(this.form().getRawValue());
|
|
@@ -13302,7 +13428,7 @@ class FormComponent {
|
|
|
13302
13428
|
}
|
|
13303
13429
|
onRunTimeOptionUpdate(result) {
|
|
13304
13430
|
if (this.fieldComponents) {
|
|
13305
|
-
const fieldToUpdate = this.fieldComponents.find((fieldComponent) => fieldComponent?.field()?.dependentField?.id === result?.field?.id);
|
|
13431
|
+
const fieldToUpdate = this.fieldComponents.toArray().find((fieldComponent) => fieldComponent?.field()?.dependentField?.id === result?.field?.id);
|
|
13306
13432
|
const selectedValue = String(this.form()?.value[result?.field?.id] ??
|
|
13307
13433
|
this.form()?.value[result?.field?.key] ??
|
|
13308
13434
|
'');
|
|
@@ -13313,6 +13439,31 @@ class FormComponent {
|
|
|
13313
13439
|
ngOnDestroy() {
|
|
13314
13440
|
this.ruleProcessor.destroy();
|
|
13315
13441
|
}
|
|
13442
|
+
// get sanitizedFields(): IFormField<string>[] {
|
|
13443
|
+
// return (this.fields() || []).filter(
|
|
13444
|
+
// (field) => !this.isFieldHiddenByRules(field)
|
|
13445
|
+
// );
|
|
13446
|
+
// }
|
|
13447
|
+
// getVisibleSectionFields(section: any): IFormField<string>[] {
|
|
13448
|
+
// const rawFields: IFormField<string>[] = section?.formFields ?? [];
|
|
13449
|
+
// return rawFields.filter((field) => !this.isFieldHiddenByRules(field));
|
|
13450
|
+
// }
|
|
13451
|
+
// private isFieldHiddenByRules(field: IFormField<string>): boolean {
|
|
13452
|
+
// if (field.hidden) {
|
|
13453
|
+
// return true;
|
|
13454
|
+
// }
|
|
13455
|
+
// const type = (field as any).isDataElement
|
|
13456
|
+
// ? 'dataElement'
|
|
13457
|
+
// : 'trackedEntityAttribute';
|
|
13458
|
+
// const elementItem = (field as any)[type] || field;
|
|
13459
|
+
// if (!elementItem) return false;
|
|
13460
|
+
// const rule = (this.programRuleActions() || []).find(
|
|
13461
|
+
// (ruleAction) =>
|
|
13462
|
+
// ruleAction.field === elementItem.id &&
|
|
13463
|
+
// ruleAction.actionType === 'HIDEFIELD'
|
|
13464
|
+
// );
|
|
13465
|
+
// return !!rule;
|
|
13466
|
+
// }
|
|
13316
13467
|
get sanitizedFields() {
|
|
13317
13468
|
return (this.fields() || []).filter((field) => !this.isFieldHiddenByRules(field));
|
|
13318
13469
|
}
|
|
@@ -13321,17 +13472,7 @@ class FormComponent {
|
|
|
13321
13472
|
return rawFields.filter((field) => !this.isFieldHiddenByRules(field));
|
|
13322
13473
|
}
|
|
13323
13474
|
isFieldHiddenByRules(field) {
|
|
13324
|
-
|
|
13325
|
-
return true;
|
|
13326
|
-
}
|
|
13327
|
-
const type = field.isDataElement
|
|
13328
|
-
? 'dataElement'
|
|
13329
|
-
: 'trackedEntityAttribute';
|
|
13330
|
-
const elementItem = field || field;
|
|
13331
|
-
if (!elementItem || !elementItem.id) {
|
|
13332
|
-
return false;
|
|
13333
|
-
}
|
|
13334
|
-
return this.hiddenFieldIds().has(elementItem.id);
|
|
13475
|
+
return FormValidationScopeUtil.resolve(field, this.programEntryFormConfig(), this.programEntryFormMetaData()?.sections, this.programRuleActions()).excluded;
|
|
13335
13476
|
}
|
|
13336
13477
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
13337
13478
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FormComponent, isStandalone: false, selector: "ng-dhis2-ui-form", inputs: { programEntryFormConfig: { classPropertyName: "programEntryFormConfig", publicName: "programEntryFormConfig", isSignal: true, isRequired: false, transformFunction: null }, formConfig: { classPropertyName: "formConfig", publicName: "formConfig", isSignal: true, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, isFormHorizontal: { classPropertyName: "isFormHorizontal", publicName: "isFormHorizontal", isSignal: true, isRequired: false, transformFunction: null }, showSaveButton: { classPropertyName: "showSaveButton", publicName: "showSaveButton", isSignal: true, isRequired: false, transformFunction: null }, fieldsData: { classPropertyName: "fieldsData", publicName: "fieldsData", isSignal: true, isRequired: false, transformFunction: null }, formMetaData: { classPropertyName: "formMetaData", publicName: "formMetaData", isSignal: true, isRequired: false, transformFunction: null }, programEntryFormMetaData: { classPropertyName: "programEntryFormMetaData", publicName: "programEntryFormMetaData", isSignal: true, isRequired: false, transformFunction: null }, fieldClass: { classPropertyName: "fieldClass", publicName: "fieldClass", isSignal: true, isRequired: false, transformFunction: null }, shouldRenderAsCheckBoxesButton: { classPropertyName: "shouldRenderAsCheckBoxesButton", publicName: "shouldRenderAsCheckBoxesButton", isSignal: true, isRequired: false, transformFunction: null }, programRuleActions: { classPropertyName: "programRuleActions", publicName: "programRuleActions", isSignal: true, isRequired: false, transformFunction: null }, dataEntities: { classPropertyName: "dataEntities", publicName: "dataEntities", isSignal: true, isRequired: false, transformFunction: null }, dataId: { classPropertyName: "dataId", publicName: "dataId", isSignal: true, isRequired: false, transformFunction: null }, customOrgUnitRoots: { classPropertyName: "customOrgUnitRoots", publicName: "customOrgUnitRoots", isSignal: true, isRequired: false, transformFunction: null }, optionCascadeConfigs: { classPropertyName: "optionCascadeConfigs", publicName: "optionCascadeConfigs", isSignal: true, isRequired: false, transformFunction: null }, coordinatePickerGeoConfig: { classPropertyName: "coordinatePickerGeoConfig", publicName: "coordinatePickerGeoConfig", isSignal: true, isRequired: false, transformFunction: null }, program: { classPropertyName: "program", publicName: "program", isSignal: true, isRequired: false, transformFunction: null }, collapsibleSections: { classPropertyName: "collapsibleSections", publicName: "collapsibleSections", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { formUpdate: "formUpdate", formValidityUpdate: "formValidityUpdate" }, viewQueries: [{ propertyName: "fieldComponents", predicate: FormFieldComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!-- <form [formGroup]=\"form()\" class=\"{{ configuration().directionClassName }}\">\n <div class=\"form-name\">\n <h2>{{ configuration().formName }}</h2>\n </div>\n\n <div>\n {{ formMetaData().sections }}\n </div>\n <div\n *ngFor=\"let field of sanitizedFields\"\n class=\"form-field-{{ configuration().direction }}\"\n >\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [program]=\"program()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n</form> -->\n\n<!-- <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n\n @if (meta.programStageSections?.length) {\n @for (section of meta.programStageSections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n\n <div class=\"form__section-content\">\n @if (section.formFields?.length) {\n @for (field of section.formFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n</form> -->\n\n<!-- @if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'EVENT') {\n <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n @if (meta.programStageSections?.length) {\n @for (section of meta.programStageSections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n }\n\n @if (!collapsibleSections() || isSectionOpen(section, $index)) {\n <div class=\"form__section-content\">\n @if (section.formFields?.length) {\n @for (field of section.formFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n} @else if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'TRACKER') {\n <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n @if (meta.sections?.length) {\n @for (section of meta.sections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n }\n \n @if (!collapsibleSections() || isSectionOpen(section, $index)) {\n <div class=\"form__section-content\">\n \n @if (section.formFields?.length) {\n \n @for (field of section.formFields; track field?.id ?? $index) {\n <div>\n </div>\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n} @else {\n <form [formGroup]=\"form()\" class=\"{{ configuration().directionClassName }}\">\n <div class=\"form-name\">\n <h2>{{ configuration().formName }}</h2>\n </div>\n\n <div>\n {{ formMetaData().sections }}\n </div>\n <div\n *ngFor=\"let field of sanitizedFields\"\n class=\"form-field-{{ configuration().direction }}\"\n >\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n </form>\n} -->\n<!-- \n@if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'EVENT')\n{\n<form\n [formGroup]=\"form()\"\n class=\"form {{ configuration().directionClassName }}\"\n>\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) { @if\n (meta?.programStageSections?.length) { @for (section of\n meta?.programStageSections; track section?.id ?? $index) { @let sectionId =\n 'section-' + (section?.id ?? $index); @let descId = sectionId + '-desc'; @let\n desc = section?.description; @let hasDesc = !!desc;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionId\">\n @if (section?.name) { @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n [attr.aria-controls]=\"sectionId\"\n [attr.aria-describedby]=\"\n hasDesc && isSectionOpen(section, $index) ? descId : null\n \"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">{{ section.name }} - {{ descId }}</div>\n @if (hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n } } } @if (!collapsibleSections() || isSectionOpen(section, $index)) { @if\n (collapsibleSections() && hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n }\n\n <div class=\"form__section-content\" [id]=\"sectionId\">\n @if (section.formFields?.length) { @for (field of\n getVisibleSectionFields(section); track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n \n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [optionCascadeConfigs]=\"optionCascadeConfigs()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n } } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } }\n</form>\n} @else if (programEntryFormConfig() && programEntryFormConfig()!.formType ===\n'TRACKER') {\n<form\n [formGroup]=\"form()\"\n class=\"form {{ configuration().directionClassName }}\"\n>\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) { @if (meta?.sections?.length) {\n @for (section of meta?.sections; track section?.id ?? $index) { @let sectionId\n = 'section-' + (section?.id ?? $index); @let descId = sectionId + '-desc';\n @let desc = section?.description; @let hasDesc = !!desc;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionId\">\n @if (section?.name) { @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n [attr.aria-controls]=\"sectionId\"\n [attr.aria-describedby]=\"\n hasDesc && isSectionOpen(section, $index) ? descId : null\n \"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n @if (hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n } } } @if (!collapsibleSections() || isSectionOpen(section, $index)) { @if\n (collapsibleSections() && hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n }\n <div class=\"form__section-content\" [id]=\"sectionId\">\n @if (section.formFields?.length) { @for (field of\n getVisibleSectionFields(section); track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n } } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } }\n</form>\n} @else {\n<form [formGroup]=\"form()\" [class]=\"configuration().directionClassName\">\n @if (configuration()?.formName) {\n <div class=\"form-name\">\n <h2>{{ configuration()?.formName }}</h2>\n </div>\n } @if (sanitizedFields?.length) { @for (field of sanitizedFields; track\n field?.id ?? $index) {\n <div class=\"form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } } @else {\n <div class=\"text-sm text-gray-500\">No fields to display.</div>\n }\n</form>\n} -->\n\n@let entryFormConfig = programEntryFormConfig();\n@let entryFormMeta = programEntryFormMetaData();\n@let uiConfig = configuration();\n@let formGroupValue = form();\n\n@let isSectionsCollapsible = collapsibleSections();\n\n@let dataEntitiesValue = dataEntities();\n@let dataEntityId = dataId();\n@let orgUnitRootIds = customOrgUnitRoots();\n\n@let cascadeConfigMap = optionCascadeConfigMap();\n@let cascadeConfigs = optionCascadeConfigs();\n\n@let ruleActionList = programRuleActions();\n@let renderAsCheckboxButtons = shouldRenderAsCheckBoxesButton();\n\n@let entryFormCoordinatePickerGeoConfig = coordinatePickerGeoConfig();\n@let entryFormFieldControlKeyById = fieldControlKeyById();\n\n@if (entryFormConfig?.formType === 'EVENT') {\n <form [formGroup]=\"formGroupValue\" class=\"form {{ uiConfig.directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ uiConfig.formName }}</h2>\n </div>\n\n @if (entryFormMeta?.programStageSections?.length) {\n @for (stageSection of entryFormMeta.programStageSections; track stageSection?.id ?? $index) {\n @if (isSectionVisible(stageSection, 'PROGRAM_STAGE_SECTION')) {\n @let sectionKey = stageSection?.id ?? $index;\n @let sectionDomId = 'section-' + sectionKey;\n @let descriptionDomId = sectionDomId + '-desc';\n <!-- @let sectionDescription = $safeNavigationMigration(stageSection?.description); -->\n @let sectionDescription = stageSection?.description;\n @let hasDescription = !!sectionDescription;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionDomId\">\n @if (stageSection?.name) {\n @if (isSectionsCollapsible) {\n @let isOpen = isSectionOpen(stageSection, $index);\n\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(stageSection, $index)\"\n [attr.aria-expanded]=\"isOpen\"\n [attr.aria-controls]=\"sectionDomId\"\n [attr.aria-describedby]=\"hasDescription && isOpen ? descriptionDomId : null\"\n >\n <span class=\"form__section-title\">{{ stageSection.name }}</span>\n <span class=\"form__chevron\" [class.form__chevron--open]=\"isOpen\"></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">{{ stageSection.name }}</div>\n @if (hasDescription) {\n <p class=\"form__section-description\" [id]=\"descriptionDomId\">\n {{ sectionDescription }}\n </p>\n }\n }\n }\n\n @let isOpen = !isSectionsCollapsible || isSectionOpen(stageSection, $index);\n @if (isOpen) {\n @if (isSectionsCollapsible && hasDescription) {\n <p class=\"form__section-description\" [id]=\"descriptionDomId\">\n {{ sectionDescription }}\n </p>\n }\n\n <div class=\"form__section-content\" [id]=\"sectionDomId\">\n @if (stageSection?.formFields?.length) {\n @for (visibleField of getVisibleSectionFields(stageSection); track visibleField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"visibleField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [optionCascadeConfigs]=\"cascadeConfigs\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, visibleField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n }\n } @empty {\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n\n} @else if (entryFormConfig?.formType === 'TRACKER') {\n\n <form [formGroup]=\"formGroupValue\" class=\"form {{ uiConfig.directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ uiConfig.formName }}</h2>\n </div>\n\n @if (entryFormMeta?.sections?.length) {\n @for (teiSection of entryFormMeta.sections; track teiSection?.id ?? $index) {\n @if (isSectionVisible(teiSection, 'PROGRAM_SECTION')) {\n @let sectionKey = teiSection?.id ?? $index;\n @let sectionDomId = 'section-' + sectionKey;\n @let descriptionDomId = sectionDomId + '-desc';\n <!-- @let sectionDescription = $safeNavigationMigration(teiSection?.description); -->\n @let sectionDescription = teiSection?.description;\n @let hasDescription = !!sectionDescription;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionDomId\">\n @if (teiSection?.name) {\n @if (isSectionsCollapsible) {\n @let isOpen = isSectionOpen(teiSection, $index);\n\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(teiSection, $index)\"\n [attr.aria-expanded]=\"isOpen\"\n [attr.aria-controls]=\"sectionDomId\"\n [attr.aria-describedby]=\"hasDescription && isOpen ? descriptionDomId : null\"\n >\n <span class=\"form__section-title\">{{ teiSection.name }}</span>\n <span class=\"form__chevron\" [class.form__chevron--open]=\"isOpen\"></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">{{ teiSection.name }}</div>\n @if (hasDescription) {\n <p class=\"form__section-description\" [id]=\"descriptionDomId\">\n {{ sectionDescription }}\n </p>\n }\n }\n }\n\n @let isOpen = !isSectionsCollapsible || isSectionOpen(teiSection, $index);\n @if (isOpen) {\n @if (isSectionsCollapsible && hasDescription) {\n <p class=\"form__section-description\" [id]=\"descriptionDomId\">\n {{ sectionDescription }}\n </p>\n }\n\n <div class=\"form__section-content\" [id]=\"sectionDomId\">\n @if (teiSection?.formFields?.length) {\n @for (visibleField of getVisibleSectionFields(teiSection); track visibleField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"visibleField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, visibleField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n }\n } @empty {\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n\n} @else {\n\n <form [formGroup]=\"formGroupValue\" [class]=\"uiConfig.directionClassName\">\n @if (uiConfig?.formName) {\n <div class=\"form-name\">\n <h2>{{ uiConfig.formName }}</h2>\n </div>\n }\n\n @if (sanitizedFields?.length) {\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n }\n } @else {\n <div class=\"text-sm text-gray-500\">No fields to display.</div>\n }\n </form>\n\n}\n", styles: ["@charset \"UTF-8\";.form__section-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;font-size:15px;font-weight:600;padding:14px 16px 16px;background-color:#e8edf2;color:#374151;border:0;cursor:pointer;text-align:left}.form__section-toggle:focus{outline:2px solid #93c5fd;outline-offset:2px}.form__section-title{pointer-events:none}.form__chevron{width:10px;height:10px;display:inline-block;margin-left:12px;-webkit-mask-image:linear-gradient(#000,#000);mask-image:linear-gradient(#000,#000);border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(-45deg);transition:transform .12s ease-in-out}.form__chevron--open{transform:rotate(45deg)}.form__section{border:1px solid #eee;margin-bottom:16px;background-color:#fff}.form__field-group-name{display:inline-flex;font-size:14px;font-weight:600;padding:8px 16px;background-color:#e8edf2;color:#374151}.form__section-content{padding:16px}.form__section-description{margin:5px 5px 15px;font-size:15px;line-height:1.5;color:#4b5563;white-space:pre-line}.form__section-description:before{content:\"\";display:inline-block;width:4px;height:.9em;margin-right:8px;vertical-align:-2px;background-color:#cbd5e1;border-radius:2px}\n"], dependencies: [{ kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: FormFieldComponent, selector: "ng-dhis2-ui-form-field", inputs: ["field", "fieldConfig", "form", "isCheckBoxButton", "fieldClass", "programRuleActions", "dataEntities", "minDate", "maxDate", "dataId", "customOrgUnitRoots", "program", "optionCascadeConfigs", "optionCascadeConfigMap", "coordinatePickerGeoConfig", "fieldControlKeyById"], outputs: ["fieldUpdate", "immediateFieldUpdate", "runtimeOptionChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
@@ -13634,6 +13775,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
13634
13775
|
class FlatFormComponent extends BaseFormWrapperComponent {
|
|
13635
13776
|
constructor() {
|
|
13636
13777
|
super(...arguments);
|
|
13778
|
+
this.destroyRef = inject(DestroyRef);
|
|
13637
13779
|
this.collapsibleSections = input(false, /* @ts-ignore */
|
|
13638
13780
|
...(ngDevMode ? [{ debugName: "collapsibleSections" }] : /* istanbul ignore next */ []));
|
|
13639
13781
|
this.programEntryFormConfig = input.required(/* @ts-ignore */
|
|
@@ -13643,10 +13785,59 @@ class FlatFormComponent extends BaseFormWrapperComponent {
|
|
|
13643
13785
|
}
|
|
13644
13786
|
ngOnInit() {
|
|
13645
13787
|
this.formGroup = FormUtil.getFormGroup(this.fields(), this.dataValues());
|
|
13788
|
+
// Build the interactive validation scope before the first validity event.
|
|
13789
|
+
// A TRACKER with sections renders only fields belonging to those sections,
|
|
13790
|
+
// while FormUtil creates controls for the complete metadata field list.
|
|
13791
|
+
this.excludeUnrenderedTrackerControls();
|
|
13792
|
+
// Form controls can change validity without going through a fieldUpdate
|
|
13793
|
+
// callback (e.g. conditional validators, program rules, or async changes).
|
|
13794
|
+
// Keep the form validity output in sync with the actual FormGroup status.
|
|
13795
|
+
this.formGroup.statusChanges
|
|
13796
|
+
.pipe(startWith(this.formGroup.status), map((status) => status === 'VALID'), distinctUntilChanged(), takeUntilDestroyed(this.destroyRef))
|
|
13797
|
+
.subscribe((isValid) => this.updateFormValidity(isValid));
|
|
13646
13798
|
this.onFormUpdate(this.dataValues());
|
|
13647
13799
|
}
|
|
13800
|
+
/**
|
|
13801
|
+
* Exclude only controls that cannot be edited in this form: metadata-hidden,
|
|
13802
|
+
* HIDEFIELD, hidden auto-assigned, or absent from TRACKER sections.
|
|
13803
|
+
* Controls keep their raw values for the existing SDK save flow.
|
|
13804
|
+
*/
|
|
13805
|
+
excludeUnrenderedTrackerControls() {
|
|
13806
|
+
const config = this.programEntryFormConfig();
|
|
13807
|
+
const sections = this.programEntryFormMetaData()?.sections;
|
|
13808
|
+
const actions = this.ruleActions() ?? [];
|
|
13809
|
+
let changed = false;
|
|
13810
|
+
for (const field of this.fields() ?? []) {
|
|
13811
|
+
if (!field)
|
|
13812
|
+
continue;
|
|
13813
|
+
const scope = FormValidationScopeUtil.resolve(field, config, sections, actions);
|
|
13814
|
+
const control = this.formGroup.get(field.key || field.id);
|
|
13815
|
+
if (scope.excluded && control?.enabled) {
|
|
13816
|
+
control.disable({ emitEvent: false });
|
|
13817
|
+
changed = true;
|
|
13818
|
+
}
|
|
13819
|
+
// A referenceKey is a separate generated control and must share its
|
|
13820
|
+
// source field's visibility; it must not remain an invisible requirement.
|
|
13821
|
+
if (scope.excluded && field.referenceKey) {
|
|
13822
|
+
const reference = this.formGroup.get(field.referenceKey);
|
|
13823
|
+
if (reference?.enabled) {
|
|
13824
|
+
reference.disable({ emitEvent: false });
|
|
13825
|
+
changed = true;
|
|
13826
|
+
}
|
|
13827
|
+
}
|
|
13828
|
+
}
|
|
13829
|
+
if (changed)
|
|
13830
|
+
this.formGroup.updateValueAndValidity({ emitEvent: false });
|
|
13831
|
+
}
|
|
13648
13832
|
onFormUpdate(dataValues) {
|
|
13649
|
-
|
|
13833
|
+
// Controls can be omitted from a FLAT form when their fields are hidden.
|
|
13834
|
+
// Keep their initial values while letting rendered controls override them,
|
|
13835
|
+
// including intentional clears (null or empty string).
|
|
13836
|
+
const updatedValues = dataValues ?? this.formGroup.getRawValue();
|
|
13837
|
+
this.updateDataValues({
|
|
13838
|
+
...this.dataValues(),
|
|
13839
|
+
...updatedValues,
|
|
13840
|
+
});
|
|
13650
13841
|
this.updateFormValidity(this.formGroup.valid);
|
|
13651
13842
|
}
|
|
13652
13843
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FlatFormComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
@@ -15348,7 +15539,201 @@ class ProgramEntryFormMetaData {
|
|
|
15348
15539
|
// Use of this source code is governed by a BSD-style
|
|
15349
15540
|
// license that can be found in the LICENSE file.
|
|
15350
15541
|
|
|
15351
|
-
|
|
15542
|
+
function idOf(value) {
|
|
15543
|
+
if (typeof value === 'string')
|
|
15544
|
+
return value;
|
|
15545
|
+
if (value && typeof value === 'object' && 'id' in value) {
|
|
15546
|
+
const id = value.id;
|
|
15547
|
+
if (typeof id === 'string')
|
|
15548
|
+
return id;
|
|
15549
|
+
}
|
|
15550
|
+
return undefined;
|
|
15551
|
+
}
|
|
15552
|
+
function isEventContextField(field, config) {
|
|
15553
|
+
const name = field.id || field.key;
|
|
15554
|
+
const names = [name, field.key];
|
|
15555
|
+
if (names.some((n) => n === 'occurredAt' || n === 'eventDate')) {
|
|
15556
|
+
return config.hideEventDate !== true;
|
|
15557
|
+
}
|
|
15558
|
+
if (field.isOrgUnit || names.includes('orgUnit')) {
|
|
15559
|
+
return config.hideRegistrationUnit !== true;
|
|
15560
|
+
}
|
|
15561
|
+
return false;
|
|
15562
|
+
}
|
|
15563
|
+
function fieldIds(field) {
|
|
15564
|
+
return [field.id, idOf(field.dataElement), field.dataElementId]
|
|
15565
|
+
.filter((id) => typeof id === 'string' && id.length > 0);
|
|
15566
|
+
}
|
|
15567
|
+
function isTrackedEntityAttribute(field) {
|
|
15568
|
+
// Form metadata may use typed flags, or SDK-style attribute references.
|
|
15569
|
+
return field.isAttribute === true ||
|
|
15570
|
+
!!idOf(field.trackedEntityAttribute) ||
|
|
15571
|
+
!!idOf(field.attribute);
|
|
15572
|
+
}
|
|
15573
|
+
function belongsTo(field, stage) {
|
|
15574
|
+
return (idOf(field.programStage) ?? field.stageId ?? field.programStageId) === stage;
|
|
15575
|
+
}
|
|
15576
|
+
function matchingSectionFields(sections, stage) {
|
|
15577
|
+
return sections.filter((section) => {
|
|
15578
|
+
const owner = idOf(section.programStage) ?? section.stageId ?? section.programStageId;
|
|
15579
|
+
return !owner || owner === stage;
|
|
15580
|
+
});
|
|
15581
|
+
}
|
|
15582
|
+
class ProgramEntryFormScopeUtil {
|
|
15583
|
+
static resolve(metadata, config) {
|
|
15584
|
+
// Preserve the existing TRACKER-with-stage implementation. It can have
|
|
15585
|
+
// separate registration/stage workflows and must not be silently changed.
|
|
15586
|
+
if (config.formType !== 'EVENT' && config.formType !== 'TRACKER') {
|
|
15587
|
+
return { metadata, error: null };
|
|
15588
|
+
}
|
|
15589
|
+
if (config.formType === 'TRACKER') {
|
|
15590
|
+
if (config.programStage) {
|
|
15591
|
+
return { metadata, error: null };
|
|
15592
|
+
}
|
|
15593
|
+
// Registration without a stage has attributes and its existing special
|
|
15594
|
+
// registration fields; data elements are never required in this mode.
|
|
15595
|
+
const fields = metadata.formFields.filter((field) => field.isDataElement !== true &&
|
|
15596
|
+
!['occurredAt', 'eventDate'].includes(field.id) &&
|
|
15597
|
+
!['occurredAt', 'eventDate'].includes(field.key ?? ''));
|
|
15598
|
+
const allowed = new Set(fields.map((field) => field.id));
|
|
15599
|
+
const sections = metadata.sections?.map((section) => ({
|
|
15600
|
+
...section,
|
|
15601
|
+
formFields: (section.formFields ?? []).filter((field) => allowed.has(field.id)),
|
|
15602
|
+
})).filter((section) => section.formFields.length > 0);
|
|
15603
|
+
return {
|
|
15604
|
+
metadata: { ...metadata, formFields: fields, sections },
|
|
15605
|
+
error: null,
|
|
15606
|
+
};
|
|
15607
|
+
}
|
|
15608
|
+
const stageId = config.programStage?.trim();
|
|
15609
|
+
if (!stageId) {
|
|
15610
|
+
return { metadata: null, error: 'EVENT form requires config.programStage.' };
|
|
15611
|
+
}
|
|
15612
|
+
const stageCandidates = [
|
|
15613
|
+
...(Array.isArray(metadata.program?.programStages) ? metadata.program.programStages : []),
|
|
15614
|
+
...(Array.isArray(metadata.programStages) ? metadata.programStages : []),
|
|
15615
|
+
];
|
|
15616
|
+
if (metadata.programStage && typeof metadata.programStage !== 'string') {
|
|
15617
|
+
stageCandidates.push(metadata.programStage);
|
|
15618
|
+
}
|
|
15619
|
+
const stage = stageCandidates.find((item) => item.id === stageId);
|
|
15620
|
+
if (stageCandidates.length > 0 && !stage) {
|
|
15621
|
+
return {
|
|
15622
|
+
metadata: null,
|
|
15623
|
+
error: `Program stage ${stageId} is not part of the supplied program metadata.`,
|
|
15624
|
+
};
|
|
15625
|
+
}
|
|
15626
|
+
const stageElementIds = new Set((stage?.programStageDataElements ?? [])
|
|
15627
|
+
.map((item) => idOf(item.dataElement) ?? item.dataElementId)
|
|
15628
|
+
.filter((id) => !!id));
|
|
15629
|
+
// Sections supplied by the selected ProgramStage take precedence. The
|
|
15630
|
+
// top-level programStageSections is used when metadata is already scoped
|
|
15631
|
+
// to a stage, as is customary in entry-form metadata builders.
|
|
15632
|
+
const stageSectionsWithFields = stage?.programStageSections?.some((section) => (section.formFields ?? []).length > 0);
|
|
15633
|
+
const sectionSource = stageSectionsWithFields
|
|
15634
|
+
? stage.programStageSections
|
|
15635
|
+
: metadata.programStageSections?.length
|
|
15636
|
+
? metadata.programStageSections
|
|
15637
|
+
: stage?.programStageSections ?? [];
|
|
15638
|
+
const candidateSections = matchingSectionFields(sectionSource, stageId);
|
|
15639
|
+
const sectionFieldIds = new Set(candidateSections.flatMap((section) => (section.formFields ?? []).flatMap((field) => fieldIds(field))));
|
|
15640
|
+
// Stage sections sometimes contain complete field definitions even when
|
|
15641
|
+
// ProgramEntryFormMetaData.formFields contains registration attributes only.
|
|
15642
|
+
// Prefer the richer top-level definition where both are available.
|
|
15643
|
+
const candidates = [...metadata.formFields];
|
|
15644
|
+
const knownFieldIds = new Set(candidates.flatMap((field) => fieldIds(field)));
|
|
15645
|
+
for (const section of candidateSections) {
|
|
15646
|
+
for (const sectionField of section.formFields ?? []) {
|
|
15647
|
+
if (fieldIds(sectionField).some((id) => knownFieldIds.has(id)))
|
|
15648
|
+
continue;
|
|
15649
|
+
candidates.push(sectionField);
|
|
15650
|
+
fieldIds(sectionField).forEach((id) => knownFieldIds.add(id));
|
|
15651
|
+
}
|
|
15652
|
+
}
|
|
15653
|
+
// The metadata builder may not attach isDataElement=true. A stage's
|
|
15654
|
+
// programStageDataElements, its stage sections, or an explicit stage ID
|
|
15655
|
+
// is authoritative evidence of EVENT field membership. Do not allow
|
|
15656
|
+
// tracked-entity attributes through even when IDs overlap unexpectedly.
|
|
15657
|
+
const hasStageMembership = stageElementIds.size > 0 ||
|
|
15658
|
+
candidateSections.length > 0 ||
|
|
15659
|
+
candidates.some((field) => belongsTo(field, stageId));
|
|
15660
|
+
if (!hasStageMembership) {
|
|
15661
|
+
return {
|
|
15662
|
+
metadata: null,
|
|
15663
|
+
error: `No form metadata could be resolved for program stage ${stageId}.`,
|
|
15664
|
+
};
|
|
15665
|
+
}
|
|
15666
|
+
const fields = candidates.filter((field) => {
|
|
15667
|
+
if (isEventContextField(field, config))
|
|
15668
|
+
return true;
|
|
15669
|
+
if (isTrackedEntityAttribute(field))
|
|
15670
|
+
return false;
|
|
15671
|
+
const fieldStage = idOf(field.programStage) ?? field.stageId ?? field.programStageId;
|
|
15672
|
+
if (fieldStage && fieldStage !== stageId)
|
|
15673
|
+
return false;
|
|
15674
|
+
const refs = fieldIds(field);
|
|
15675
|
+
// An explicit stage DE list is the strongest source of truth.
|
|
15676
|
+
if (stageElementIds.size > 0) {
|
|
15677
|
+
return refs.some((id) => stageElementIds.has(id));
|
|
15678
|
+
}
|
|
15679
|
+
// Use selected-stage sections or explicit field ownership. Do not
|
|
15680
|
+
// require the optional isDataElement boolean from the metadata builder.
|
|
15681
|
+
return fieldStage === stageId || refs.some((id) => sectionFieldIds.has(id));
|
|
15682
|
+
});
|
|
15683
|
+
const allowed = new Set(fields.flatMap((field) => fieldIds(field)));
|
|
15684
|
+
const resolvedFieldById = new Map();
|
|
15685
|
+
for (const field of fields) {
|
|
15686
|
+
fieldIds(field).forEach((id) => resolvedFieldById.set(id, field));
|
|
15687
|
+
}
|
|
15688
|
+
const sections = candidateSections.map((section) => ({
|
|
15689
|
+
...section,
|
|
15690
|
+
formFields: (section.formFields ?? [])
|
|
15691
|
+
.filter((field) => fieldIds(field).some((id) => allowed.has(id)))
|
|
15692
|
+
.map((field) => fieldIds(field)
|
|
15693
|
+
.map((id) => resolvedFieldById.get(id))
|
|
15694
|
+
.find((resolved) => !!resolved) ?? field),
|
|
15695
|
+
})).filter((section) => section.formFields.length > 0);
|
|
15696
|
+
// Fail closed only when there really are no stage fields. Do not reject
|
|
15697
|
+
// verified stage fields just because isDataElement was not supplied.
|
|
15698
|
+
const hasStageFields = fields.some((field) => !isEventContextField(field, config));
|
|
15699
|
+
const stageExplicitlyEmpty = !!stage &&
|
|
15700
|
+
Array.isArray(stage.programStageDataElements) &&
|
|
15701
|
+
stage.programStageDataElements.length === 0 &&
|
|
15702
|
+
sectionFieldIds.size === 0;
|
|
15703
|
+
if (!stageExplicitlyEmpty && !hasStageFields) {
|
|
15704
|
+
return {
|
|
15705
|
+
metadata: null,
|
|
15706
|
+
error: `Stage ${stageId} has no resolvable data-element field definitions. Check ProgramEntryFormMetaData stage sections and field IDs.`,
|
|
15707
|
+
};
|
|
15708
|
+
}
|
|
15709
|
+
// In section-based EVENT forms, ensure selected-stage fields not assigned
|
|
15710
|
+
// to a named section still render and are not invisible required controls.
|
|
15711
|
+
// This also keeps occurredAt editable when hideEventDate is false.
|
|
15712
|
+
if (sections.length > 0) {
|
|
15713
|
+
const sectioned = new Set(sections.flatMap((section) => (section.formFields ?? []).map((field) => field.id)));
|
|
15714
|
+
const extraFields = fields.filter((field) => !sectioned.has(field.id));
|
|
15715
|
+
if (extraFields.length > 0) {
|
|
15716
|
+
sections.push({
|
|
15717
|
+
id: `__event_additional_${stageId}`,
|
|
15718
|
+
name: 'Additional event fields',
|
|
15719
|
+
formFields: extraFields,
|
|
15720
|
+
});
|
|
15721
|
+
}
|
|
15722
|
+
}
|
|
15723
|
+
// Keep stage sections only; never pass registration sections to the EVENT
|
|
15724
|
+
// renderer. The renderer's fallback displays 'fields' when none exist.
|
|
15725
|
+
return {
|
|
15726
|
+
metadata: {
|
|
15727
|
+
...metadata,
|
|
15728
|
+
formFields: fields,
|
|
15729
|
+
sections: [],
|
|
15730
|
+
programStageSections: sections,
|
|
15731
|
+
},
|
|
15732
|
+
error: null,
|
|
15733
|
+
};
|
|
15734
|
+
}
|
|
15735
|
+
}
|
|
15736
|
+
|
|
15352
15737
|
class ProgramEntryFormModule {
|
|
15353
15738
|
constructor() {
|
|
15354
15739
|
this.config = input.required(/* @ts-ignore */
|
|
@@ -15375,13 +15760,34 @@ class ProgramEntryFormModule {
|
|
|
15375
15760
|
...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
15376
15761
|
this.metaData = signal(null, /* @ts-ignore */
|
|
15377
15762
|
...(ngDevMode ? [{ debugName: "metaData" }] : /* istanbul ignore next */ []));
|
|
15378
|
-
|
|
15763
|
+
// Select exactly the configured EVENT program stage (or TRACKER registration)
|
|
15764
|
+
// before the FLAT form builds its FormGroup. Keep raw metadata for the SDK.
|
|
15765
|
+
this.activeFormScope = computed(() => {
|
|
15766
|
+
const metadata = this.metaData();
|
|
15767
|
+
if (!metadata)
|
|
15768
|
+
return null;
|
|
15769
|
+
return ProgramEntryFormScopeUtil.resolve(metadata, this.config());
|
|
15770
|
+
}, /* @ts-ignore */
|
|
15771
|
+
...(ngDevMode ? [{ debugName: "activeFormScope" }] : /* istanbul ignore next */ []));
|
|
15772
|
+
// Do not enable submit before the child form has reported its validity.
|
|
15773
|
+
this.isFormValid = signal(false, /* @ts-ignore */
|
|
15379
15774
|
...(ngDevMode ? [{ debugName: "isFormValid" }] : /* istanbul ignore next */ []));
|
|
15775
|
+
// Keep submission state in Angular so React component remounts cannot reset it.
|
|
15776
|
+
this.isSubmitting = signal(false, /* @ts-ignore */
|
|
15777
|
+
...(ngDevMode ? [{ debugName: "isSubmitting" }] : /* istanbul ignore next */ []));
|
|
15380
15778
|
this.isFormValid$ = toObservable(this.isFormValid);
|
|
15381
15779
|
this.instance = signal(null, /* @ts-ignore */
|
|
15382
15780
|
...(ngDevMode ? [{ debugName: "instance" }] : /* istanbul ignore next */ []));
|
|
15383
15781
|
this.trackedEntityInstance = signal(null, /* @ts-ignore */
|
|
15384
15782
|
...(ngDevMode ? [{ debugName: "trackedEntityInstance" }] : /* istanbul ignore next */ []));
|
|
15783
|
+
// SDK instances are mutable class objects. A revision signal ensures that
|
|
15784
|
+
// dependent computed values refresh after updateDataValues() mutates one.
|
|
15785
|
+
this.instanceRevision = signal(0, /* @ts-ignore */
|
|
15786
|
+
...(ngDevMode ? [{ debugName: "instanceRevision" }] : /* istanbul ignore next */ []));
|
|
15787
|
+
// Maintain configured defaults independently of the rendered field list.
|
|
15788
|
+
// hideCustomAssignedFields can remove their controls from the FormGroup.
|
|
15789
|
+
this.initialAutoAssignedValues = signal({}, /* @ts-ignore */
|
|
15790
|
+
...(ngDevMode ? [{ debugName: "initialAutoAssignedValues" }] : /* istanbul ignore next */ []));
|
|
15385
15791
|
this.preprocess = input(/* @ts-ignore */
|
|
15386
15792
|
...(ngDevMode ? [undefined, { debugName: "preprocess" }] : /* istanbul ignore next */ []));
|
|
15387
15793
|
this.instanceSave = new EventEmitter();
|
|
@@ -15403,6 +15809,7 @@ class ProgramEntryFormModule {
|
|
|
15403
15809
|
}, /* @ts-ignore */
|
|
15404
15810
|
...(ngDevMode ? [{ debugName: "dataId" }] : /* istanbul ignore next */ []));
|
|
15405
15811
|
this.dataEntities = computed(() => {
|
|
15812
|
+
this.instanceRevision();
|
|
15406
15813
|
if (!this.instance()) {
|
|
15407
15814
|
return {};
|
|
15408
15815
|
}
|
|
@@ -15414,41 +15821,60 @@ class ProgramEntryFormModule {
|
|
|
15414
15821
|
? this.#getTrackedEntityDataValues(this.instance())
|
|
15415
15822
|
: this.instance();
|
|
15416
15823
|
return {
|
|
15824
|
+
// Fallback for assignments hidden from the rendered form metadata.
|
|
15825
|
+
// Values held by the SDK instance take precedence when present.
|
|
15826
|
+
...this.initialAutoAssignedValues(),
|
|
15417
15827
|
...attributeDataValues,
|
|
15418
15828
|
...(currentInstanceDataValues || {}),
|
|
15419
15829
|
};
|
|
15420
15830
|
}, /* @ts-ignore */
|
|
15421
15831
|
...(ngDevMode ? [{ debugName: "dataEntities" }] : /* istanbul ignore next */ []));
|
|
15422
15832
|
this.FormActionButtons = computed(() => {
|
|
15423
|
-
|
|
15833
|
+
const config = this.config();
|
|
15834
|
+
if (config.hideActionButtons) {
|
|
15424
15835
|
return React__default.createElement(React__default.Fragment, null);
|
|
15425
15836
|
}
|
|
15426
15837
|
return () => {
|
|
15427
|
-
|
|
15428
|
-
|
|
15429
|
-
|
|
15430
|
-
|
|
15431
|
-
|
|
15838
|
+
// ReactWrapper may mount the supplied function only once. Angular's
|
|
15839
|
+
// computed() changing its return value does not guarantee that the
|
|
15840
|
+
// already-mounted React component will be rendered again.
|
|
15841
|
+
const [isValid, setIsValid] = React__default.useState(() => this.isFormValid());
|
|
15842
|
+
const [submitting, setSubmitting] = React__default.useState(() => this.isSubmitting());
|
|
15843
|
+
React__default.useEffect(() => {
|
|
15844
|
+
// Subscribe to the same event that Angular consumers receive.
|
|
15845
|
+
// It is emitted synchronously by onValidityUpdate(), so the mounted
|
|
15846
|
+
// React button can respond without a ReactWrapper input refresh.
|
|
15847
|
+
const subscription = this.formValidityUpdate.subscribe((valid) => {
|
|
15848
|
+
setIsValid(valid);
|
|
15432
15849
|
});
|
|
15433
|
-
|
|
15434
|
-
|
|
15435
|
-
|
|
15850
|
+
// Catch an update that arrived before React mounted its effect.
|
|
15851
|
+
setIsValid(this.isFormValid());
|
|
15852
|
+
return () => subscription.unsubscribe();
|
|
15436
15853
|
}, []);
|
|
15437
15854
|
const onSave = () => {
|
|
15855
|
+
// Do not trust a possibly stale React callback for validation.
|
|
15856
|
+
if (!this.isFormValid() || this.isSubmitting())
|
|
15857
|
+
return;
|
|
15438
15858
|
setSubmitting(true);
|
|
15439
15859
|
this.ngZone.run(async () => {
|
|
15440
|
-
|
|
15441
|
-
|
|
15442
|
-
|
|
15860
|
+
this.isSubmitting.set(true);
|
|
15861
|
+
try {
|
|
15862
|
+
const saveResponse = await this.#saveInstance();
|
|
15863
|
+
this.instanceSaveCompleted.emit(saveResponse);
|
|
15864
|
+
}
|
|
15865
|
+
finally {
|
|
15866
|
+
this.isSubmitting.set(false);
|
|
15867
|
+
setSubmitting(false);
|
|
15868
|
+
}
|
|
15443
15869
|
});
|
|
15444
15870
|
};
|
|
15445
15871
|
return (React__default.createElement(ButtonStrip$1, null,
|
|
15446
|
-
!(
|
|
15447
|
-
!
|
|
15872
|
+
!(config.hideSubmitButton || config.disableForm) && (React__default.createElement(Button$1, { primary: true, disabled: !isValid || submitting, loading: submitting, onClick: onSave }, config.submitButtonLabel)),
|
|
15873
|
+
!config.hideCancelButton && (React__default.createElement(Button$1, { onClick: () => {
|
|
15448
15874
|
this.ngZone.run(() => {
|
|
15449
15875
|
this.onCancel();
|
|
15450
15876
|
});
|
|
15451
|
-
} },
|
|
15877
|
+
} }, config.cancelButtonLabel))));
|
|
15452
15878
|
};
|
|
15453
15879
|
}, /* @ts-ignore */
|
|
15454
15880
|
...(ngDevMode ? [{ debugName: "FormActionButtons" }] : /* istanbul ignore next */ []));
|
|
@@ -15480,11 +15906,13 @@ class ProgramEntryFormModule {
|
|
|
15480
15906
|
console.error('Failed to create or load instance for program entry form');
|
|
15481
15907
|
return;
|
|
15482
15908
|
}
|
|
15483
|
-
|
|
15909
|
+
// Apply assignments BEFORE publishing the instance to the form. This
|
|
15910
|
+
// prevents a child form from initializing with pre-assignment values.
|
|
15484
15911
|
const autoAssigned = config.autoAssignedValues;
|
|
15485
15912
|
if (autoAssigned?.length) {
|
|
15486
|
-
this.#updateInstanceWithAutoAssignedValues(autoAssigned);
|
|
15913
|
+
this.#updateInstanceWithAutoAssignedValues(instance, autoAssigned);
|
|
15487
15914
|
}
|
|
15915
|
+
this.instance.set(instance);
|
|
15488
15916
|
}
|
|
15489
15917
|
catch (error) {
|
|
15490
15918
|
console.error('Error during ProgramEntryForm initialization', error);
|
|
@@ -15494,7 +15922,35 @@ class ProgramEntryFormModule {
|
|
|
15494
15922
|
}
|
|
15495
15923
|
}
|
|
15496
15924
|
onFormUpdate(dataValues) {
|
|
15497
|
-
|
|
15925
|
+
// Hidden auto-assigned fields may be absent from the FormGroup. Preserve
|
|
15926
|
+
// their CURRENT values (not repeatedly their initial defaults), so later
|
|
15927
|
+
// programmatic updates are not accidentally rolled back by another field.
|
|
15928
|
+
const preservedAssignedValues = {};
|
|
15929
|
+
if (this.config().hideCustomAssignedFields) {
|
|
15930
|
+
// Read the mutable SDK instance directly: a cached computed signal may
|
|
15931
|
+
// not yet reflect values modified by external SDK/preprocess code.
|
|
15932
|
+
const currentInstance = this.instance();
|
|
15933
|
+
const attributeValues = this.trackedEntityInstance()
|
|
15934
|
+
? this.#getTrackedEntityDataValues(this.trackedEntityInstance())
|
|
15935
|
+
: {};
|
|
15936
|
+
const currentInstanceValues = this.config().formType === 'TRACKER' && currentInstance
|
|
15937
|
+
? this.#getTrackedEntityDataValues(currentInstance)
|
|
15938
|
+
: currentInstance ?? {};
|
|
15939
|
+
const currentValues = {
|
|
15940
|
+
...attributeValues,
|
|
15941
|
+
...currentInstanceValues,
|
|
15942
|
+
};
|
|
15943
|
+
for (const [key, initialValue] of Object.entries(this.initialAutoAssignedValues())) {
|
|
15944
|
+
// orgUnit has its own registration control and precedence rules.
|
|
15945
|
+
if (key === 'orgUnit')
|
|
15946
|
+
continue;
|
|
15947
|
+
preservedAssignedValues[key] = Object.prototype.hasOwnProperty.call(currentValues, key)
|
|
15948
|
+
? currentValues[key]
|
|
15949
|
+
: initialValue;
|
|
15950
|
+
}
|
|
15951
|
+
}
|
|
15952
|
+
// Explicit user edits and clears (including null/empty string) win.
|
|
15953
|
+
this.#updateInstance({ ...preservedAssignedValues, ...dataValues });
|
|
15498
15954
|
if (this.instance()) {
|
|
15499
15955
|
this.instanceUpdate.emit(this.instance());
|
|
15500
15956
|
}
|
|
@@ -15526,10 +15982,11 @@ class ProgramEntryFormModule {
|
|
|
15526
15982
|
}
|
|
15527
15983
|
return configuredKey;
|
|
15528
15984
|
}
|
|
15529
|
-
#updateInstanceWithAutoAssignedValues(autoAssignedValues) {
|
|
15985
|
+
#updateInstanceWithAutoAssignedValues(instance, autoAssignedValues) {
|
|
15530
15986
|
const trackedEntityId = this.trackedEntity?.();
|
|
15531
15987
|
if (
|
|
15532
|
-
//
|
|
15988
|
+
// Existing TRACKER records must not have their stored attributes replaced.
|
|
15989
|
+
// EVENT forms may legitimately have an existing tracked entity ID.
|
|
15533
15990
|
this.config().formType === 'TRACKER' &&
|
|
15534
15991
|
typeof trackedEntityId === 'string' &&
|
|
15535
15992
|
trackedEntityId.trim().length > 0) {
|
|
@@ -15543,6 +16000,14 @@ class ProgramEntryFormModule {
|
|
|
15543
16000
|
const aggregatedValues = {};
|
|
15544
16001
|
for (let index = 0; index < valueCount; index++) {
|
|
15545
16002
|
const { field: configuredKey, value } = autoAssignedValues[index];
|
|
16003
|
+
if (!configuredKey)
|
|
16004
|
+
continue;
|
|
16005
|
+
// An explicit orgUnit input takes precedence over the optional
|
|
16006
|
+
// auto-assignment fallback used for new TRACKER registration.
|
|
16007
|
+
if (configuredKey === 'orgUnit' && this.orgUnit()?.trim()) {
|
|
16008
|
+
aggregatedValues['orgUnit'] = this.orgUnit().trim();
|
|
16009
|
+
continue;
|
|
16010
|
+
}
|
|
15546
16011
|
const semanticKey = metaData
|
|
15547
16012
|
? this.#resolveFieldRuntimeId(configuredKey, metaData)
|
|
15548
16013
|
: configuredKey;
|
|
@@ -15554,26 +16019,30 @@ class ProgramEntryFormModule {
|
|
|
15554
16019
|
if (Object.keys(aggregatedValues).length === 0) {
|
|
15555
16020
|
return;
|
|
15556
16021
|
}
|
|
15557
|
-
this
|
|
16022
|
+
this.initialAutoAssignedValues.set(aggregatedValues);
|
|
16023
|
+
this.#applyDataValues(instance, aggregatedValues);
|
|
16024
|
+
}
|
|
16025
|
+
#applyDataValues(instance, dataValues) {
|
|
16026
|
+
for (const key in dataValues) {
|
|
16027
|
+
if (Object.prototype.hasOwnProperty.call(dataValues, key)) {
|
|
16028
|
+
// Keep the existing SDK integration behavior for other consumers.
|
|
16029
|
+
instance[key] = dataValues[key];
|
|
16030
|
+
}
|
|
16031
|
+
}
|
|
16032
|
+
instance.updateDataValues(dataValues, this.config().updateTeiOrgUnit);
|
|
15558
16033
|
}
|
|
15559
16034
|
#updateInstance(dataValues) {
|
|
15560
16035
|
if (!dataValues || Object.keys(dataValues).length === 0) {
|
|
15561
16036
|
return;
|
|
15562
16037
|
}
|
|
15563
|
-
const
|
|
15564
|
-
|
|
15565
|
-
|
|
15566
|
-
|
|
15567
|
-
|
|
15568
|
-
|
|
15569
|
-
|
|
15570
|
-
|
|
15571
|
-
dataValues[key];
|
|
15572
|
-
}
|
|
15573
|
-
}
|
|
15574
|
-
instance.updateDataValues(dataValues, shouldUpdateOrgUnit);
|
|
15575
|
-
return instance;
|
|
15576
|
-
});
|
|
16038
|
+
const instance = this.instance();
|
|
16039
|
+
if (!instance) {
|
|
16040
|
+
return;
|
|
16041
|
+
}
|
|
16042
|
+
this.#applyDataValues(instance, dataValues);
|
|
16043
|
+
// The SDK model is a class, so do not spread/clone it just to change the
|
|
16044
|
+
// signal reference (that would discard its prototype methods).
|
|
16045
|
+
this.instanceRevision.update((revision) => revision + 1);
|
|
15577
16046
|
}
|
|
15578
16047
|
async #saveInstance() {
|
|
15579
16048
|
if (this.preprocess() && this.instance()) {
|
|
@@ -15603,7 +16072,7 @@ class ProgramEntryFormModule {
|
|
|
15603
16072
|
}
|
|
15604
16073
|
}
|
|
15605
16074
|
async #setReservedValuesForCodeGeneration(instance) {
|
|
15606
|
-
const orgUnitForCodeGeneration = this.codeGeneratorOrgUnit() || this
|
|
16075
|
+
const orgUnitForCodeGeneration = this.codeGeneratorOrgUnit() || this.#resolveTrackerOrgUnit();
|
|
15607
16076
|
const reservedValueQuery = this.d2.trackerModule.trackedEntity.setProgram(this.config().program);
|
|
15608
16077
|
if (orgUnitForCodeGeneration) {
|
|
15609
16078
|
reservedValueQuery.setOrgUnit(orgUnitForCodeGeneration);
|
|
@@ -15614,13 +16083,28 @@ class ProgramEntryFormModule {
|
|
|
15614
16083
|
});
|
|
15615
16084
|
return instance;
|
|
15616
16085
|
}
|
|
16086
|
+
#resolveTrackerOrgUnit() {
|
|
16087
|
+
const explicitOrgUnit = this.orgUnit()?.trim();
|
|
16088
|
+
if (explicitOrgUnit) {
|
|
16089
|
+
return explicitOrgUnit;
|
|
16090
|
+
}
|
|
16091
|
+
// For new TRACKER records, an orgUnit auto-assignment must also be used
|
|
16092
|
+
// when creating the instance/query, not only after it has been created.
|
|
16093
|
+
if (this.config().formType !== 'TRACKER' || this.trackedEntity()?.trim()) {
|
|
16094
|
+
return undefined;
|
|
16095
|
+
}
|
|
16096
|
+
const assignedOrgUnit = this.config().autoAssignedValues?.find((item) => item.field === 'orgUnit')?.value;
|
|
16097
|
+
return typeof assignedOrgUnit === 'string' && assignedOrgUnit.trim()
|
|
16098
|
+
? assignedOrgUnit.trim()
|
|
16099
|
+
: undefined;
|
|
16100
|
+
}
|
|
15617
16101
|
#getQuery(instanceType) {
|
|
15618
16102
|
const d2 = window.d2Web;
|
|
15619
16103
|
switch (instanceType) {
|
|
15620
16104
|
case 'TRACKER':
|
|
15621
16105
|
return d2.trackerModule.trackedEntity
|
|
15622
16106
|
.setProgram(this.config().program)
|
|
15623
|
-
.setOrgUnit(this
|
|
16107
|
+
.setOrgUnit(this.#resolveTrackerOrgUnit());
|
|
15624
16108
|
case 'EVENT':
|
|
15625
16109
|
return d2.eventModule.event
|
|
15626
16110
|
.setProgram(this.config().program)
|
|
@@ -15689,11 +16173,11 @@ class ProgramEntryFormModule {
|
|
|
15689
16173
|
}
|
|
15690
16174
|
}
|
|
15691
16175
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: ProgramEntryFormModule, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
15692
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: ProgramEntryFormModule, isStandalone: true, selector: "ng-dhis2-ui-program-entry-form", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, trackedEntity: { classPropertyName: "trackedEntity", publicName: "trackedEntity", isSignal: true, isRequired: false, transformFunction: null }, event: { classPropertyName: "event", publicName: "event", isSignal: true, isRequired: false, transformFunction: null }, enrollment: { classPropertyName: "enrollment", publicName: "enrollment", isSignal: true, isRequired: false, transformFunction: null }, orgUnit: { classPropertyName: "orgUnit", publicName: "orgUnit", isSignal: true, isRequired: false, transformFunction: null }, codeGeneratorOrgUnit: { classPropertyName: "codeGeneratorOrgUnit", publicName: "codeGeneratorOrgUnit", isSignal: true, isRequired: false, transformFunction: null }, customOrgUnitRoots: { classPropertyName: "customOrgUnitRoots", publicName: "customOrgUnitRoots", isSignal: true, isRequired: false, transformFunction: null }, formMetaData: { classPropertyName: "formMetaData", publicName: "formMetaData", isSignal: true, isRequired: false, transformFunction: null }, collapsibleSections: { classPropertyName: "collapsibleSections", publicName: "collapsibleSections", isSignal: true, isRequired: false, transformFunction: null }, preprocess: { classPropertyName: "preprocess", publicName: "preprocess", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { instanceSave: "instanceSave", instanceSaveCompleted: "instanceSaveCompleted", instanceUpdate: "instanceUpdate", formValidityUpdate: "formValidityUpdate", formCancel: "formCancel" }, ngImport: i0, template: "@if (loading()) {\n<div className=\"program-entry__form-loader\">\n <ng-dhis2-ui-wrapper [component]=\"FormLoader\" />\n</div>\n} @else if(
|
|
16176
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: ProgramEntryFormModule, isStandalone: true, selector: "ng-dhis2-ui-program-entry-form", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, trackedEntity: { classPropertyName: "trackedEntity", publicName: "trackedEntity", isSignal: true, isRequired: false, transformFunction: null }, event: { classPropertyName: "event", publicName: "event", isSignal: true, isRequired: false, transformFunction: null }, enrollment: { classPropertyName: "enrollment", publicName: "enrollment", isSignal: true, isRequired: false, transformFunction: null }, orgUnit: { classPropertyName: "orgUnit", publicName: "orgUnit", isSignal: true, isRequired: false, transformFunction: null }, codeGeneratorOrgUnit: { classPropertyName: "codeGeneratorOrgUnit", publicName: "codeGeneratorOrgUnit", isSignal: true, isRequired: false, transformFunction: null }, customOrgUnitRoots: { classPropertyName: "customOrgUnitRoots", publicName: "customOrgUnitRoots", isSignal: true, isRequired: false, transformFunction: null }, formMetaData: { classPropertyName: "formMetaData", publicName: "formMetaData", isSignal: true, isRequired: false, transformFunction: null }, collapsibleSections: { classPropertyName: "collapsibleSections", publicName: "collapsibleSections", isSignal: true, isRequired: false, transformFunction: null }, preprocess: { classPropertyName: "preprocess", publicName: "preprocess", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { instanceSave: "instanceSave", instanceSaveCompleted: "instanceSaveCompleted", instanceUpdate: "instanceUpdate", formValidityUpdate: "formValidityUpdate", formCancel: "formCancel" }, ngImport: i0, template: "@if (loading()) {\n<div className=\"program-entry__form-loader\">\n <ng-dhis2-ui-wrapper [component]=\"FormLoader\" />\n</div>\n} @else if (activeFormScope()?.error) {\n<div role=\"alert\" class=\"program-entry__form-error\">\n {{ activeFormScope()?.error }}\n</div>\n} @else if (activeFormScope()?.metadata) {\n@let activeMetaData = activeFormScope()!.metadata!;\n\n<div>\n <!-- Form content -->\n @switch (config().displayType) {\n\n <!-- Flat display -->\n @case ('FLAT') {\n <ng-dhis2-ui-flat-form\n [programEntryFormConfig]=\"config()\"\n [optionCascadeConfigs]=\"config().optionCascadeConfigs || []\"\n [collapsibleSections]=\"collapsibleSections()\"\n [programEntryFormMetaData]=\"activeMetaData\"\n [name]=\"activeMetaData.name\"\n [dataValues]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [rules]=\"activeMetaData.rules\"\n [fields]=\"activeMetaData.formFields\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [coordinatePickerGeoConfig]=\"config().coordinatePickerGeoConfig\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n />\n\n <!-- <ng-dhis2-ui-flat-form\n [name]=\"metaData()!.name\"\n [dataValues]=\"instance() || {}\"\n [dataId]=\"dataId()\"\n [rules]=\"metaData()!.rules\"\n [fields]=\"metaData()!.formFields\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [program]=\"config().program\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n /> -->\n }\n\n <!-- SECTION display -->\n @case ('SECTION') { Section form }\n\n <!-- CUSTOM FORM -->\n @case ('CUSTOM') { } }\n\n <!-- Action buttons -->\n\n @if(!config().hideActionButtons) {\n <ng-dhis2-ui-wrapper [component]=\"FormActionButtons()\" />\n }\n</div>\n}\n", styles: ["::ng-deep .program-entry__form-loader{padding:8px}\n"], dependencies: [{ kind: "ngmodule", type: D2FormModule }, { kind: "component", type: FlatFormComponent, selector: "ng-dhis2-ui-flat-form", inputs: ["collapsibleSections", "programEntryFormConfig", "optionCascadeConfigs"] }, { kind: "directive", type: ReactWrapperModule, selector: "ng-dhis2-ui-wrapper", inputs: ["props", "component"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
15693
16177
|
}
|
|
15694
16178
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: ProgramEntryFormModule, decorators: [{
|
|
15695
16179
|
type: Component,
|
|
15696
|
-
args: [{ selector: 'ng-dhis2-ui-program-entry-form', changeDetection: ChangeDetectionStrategy.OnPush, imports: [D2FormModule, ReactWrapperModule], template: "@if (loading()) {\n<div className=\"program-entry__form-loader\">\n <ng-dhis2-ui-wrapper [component]=\"FormLoader\" />\n</div>\n} @else if(
|
|
16180
|
+
args: [{ selector: 'ng-dhis2-ui-program-entry-form', changeDetection: ChangeDetectionStrategy.OnPush, imports: [D2FormModule, ReactWrapperModule], template: "@if (loading()) {\n<div className=\"program-entry__form-loader\">\n <ng-dhis2-ui-wrapper [component]=\"FormLoader\" />\n</div>\n} @else if (activeFormScope()?.error) {\n<div role=\"alert\" class=\"program-entry__form-error\">\n {{ activeFormScope()?.error }}\n</div>\n} @else if (activeFormScope()?.metadata) {\n@let activeMetaData = activeFormScope()!.metadata!;\n\n<div>\n <!-- Form content -->\n @switch (config().displayType) {\n\n <!-- Flat display -->\n @case ('FLAT') {\n <ng-dhis2-ui-flat-form\n [programEntryFormConfig]=\"config()\"\n [optionCascadeConfigs]=\"config().optionCascadeConfigs || []\"\n [collapsibleSections]=\"collapsibleSections()\"\n [programEntryFormMetaData]=\"activeMetaData\"\n [name]=\"activeMetaData.name\"\n [dataValues]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [rules]=\"activeMetaData.rules\"\n [fields]=\"activeMetaData.formFields\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [coordinatePickerGeoConfig]=\"config().coordinatePickerGeoConfig\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n />\n\n <!-- <ng-dhis2-ui-flat-form\n [name]=\"metaData()!.name\"\n [dataValues]=\"instance() || {}\"\n [dataId]=\"dataId()\"\n [rules]=\"metaData()!.rules\"\n [fields]=\"metaData()!.formFields\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [program]=\"config().program\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n /> -->\n }\n\n <!-- SECTION display -->\n @case ('SECTION') { Section form }\n\n <!-- CUSTOM FORM -->\n @case ('CUSTOM') { } }\n\n <!-- Action buttons -->\n\n @if(!config().hideActionButtons) {\n <ng-dhis2-ui-wrapper [component]=\"FormActionButtons()\" />\n }\n</div>\n}\n", styles: ["::ng-deep .program-entry__form-loader{padding:8px}\n"] }]
|
|
15697
16181
|
}], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: true }] }], trackedEntity: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackedEntity", required: false }] }], event: [{ type: i0.Input, args: [{ isSignal: true, alias: "event", required: false }] }], enrollment: [{ type: i0.Input, args: [{ isSignal: true, alias: "enrollment", required: false }] }], orgUnit: [{ type: i0.Input, args: [{ isSignal: true, alias: "orgUnit", required: false }] }], codeGeneratorOrgUnit: [{ type: i0.Input, args: [{ isSignal: true, alias: "codeGeneratorOrgUnit", required: false }] }], customOrgUnitRoots: [{ type: i0.Input, args: [{ isSignal: true, alias: "customOrgUnitRoots", required: false }] }], formMetaData: [{ type: i0.Input, args: [{ isSignal: true, alias: "formMetaData", required: false }] }], collapsibleSections: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsibleSections", required: false }] }], preprocess: [{ type: i0.Input, args: [{ isSignal: true, alias: "preprocess", required: false }] }], instanceSave: [{
|
|
15698
16182
|
type: Output
|
|
15699
16183
|
}], instanceSaveCompleted: [{
|