@iapps/ng-dhis2-ui 1.4.4 → 1.4.5

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.
@@ -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] || dataEntities[field.key] || ''
12357
+ ? dataEntities[field.id] ?? dataEntities[field.key] ?? ''
12358
12358
  : '';
12359
12359
  return isArray(fieldValue) ? JSON.stringify(fieldValue) : fieldValue;
12360
12360
  }
@@ -13646,7 +13646,14 @@ class FlatFormComponent extends BaseFormWrapperComponent {
13646
13646
  this.onFormUpdate(this.dataValues());
13647
13647
  }
13648
13648
  onFormUpdate(dataValues) {
13649
- this.updateDataValues(dataValues ?? this.formGroup.getRawValue());
13649
+ // Controls can be omitted from a FLAT form when their fields are hidden.
13650
+ // Keep their initial values while letting rendered controls override them,
13651
+ // including intentional clears (null or empty string).
13652
+ const updatedValues = dataValues ?? this.formGroup.getRawValue();
13653
+ this.updateDataValues({
13654
+ ...this.dataValues(),
13655
+ ...updatedValues,
13656
+ });
13650
13657
  this.updateFormValidity(this.formGroup.valid);
13651
13658
  }
13652
13659
  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 +15355,6 @@ class ProgramEntryFormMetaData {
15348
15355
  // Use of this source code is governed by a BSD-style
15349
15356
  // license that can be found in the LICENSE file.
15350
15357
 
15351
- // eslint-disable-next-line @angular-eslint/component-class-suffix
15352
15358
  class ProgramEntryFormModule {
15353
15359
  constructor() {
15354
15360
  this.config = input.required(/* @ts-ignore */
@@ -15382,6 +15388,14 @@ class ProgramEntryFormModule {
15382
15388
  ...(ngDevMode ? [{ debugName: "instance" }] : /* istanbul ignore next */ []));
15383
15389
  this.trackedEntityInstance = signal(null, /* @ts-ignore */
15384
15390
  ...(ngDevMode ? [{ debugName: "trackedEntityInstance" }] : /* istanbul ignore next */ []));
15391
+ // SDK instances are mutable class objects. A revision signal ensures that
15392
+ // dependent computed values refresh after updateDataValues() mutates one.
15393
+ this.instanceRevision = signal(0, /* @ts-ignore */
15394
+ ...(ngDevMode ? [{ debugName: "instanceRevision" }] : /* istanbul ignore next */ []));
15395
+ // Maintain configured defaults independently of the rendered field list.
15396
+ // hideCustomAssignedFields can remove their controls from the FormGroup.
15397
+ this.initialAutoAssignedValues = signal({}, /* @ts-ignore */
15398
+ ...(ngDevMode ? [{ debugName: "initialAutoAssignedValues" }] : /* istanbul ignore next */ []));
15385
15399
  this.preprocess = input(/* @ts-ignore */
15386
15400
  ...(ngDevMode ? [undefined, { debugName: "preprocess" }] : /* istanbul ignore next */ []));
15387
15401
  this.instanceSave = new EventEmitter();
@@ -15403,6 +15417,7 @@ class ProgramEntryFormModule {
15403
15417
  }, /* @ts-ignore */
15404
15418
  ...(ngDevMode ? [{ debugName: "dataId" }] : /* istanbul ignore next */ []));
15405
15419
  this.dataEntities = computed(() => {
15420
+ this.instanceRevision();
15406
15421
  if (!this.instance()) {
15407
15422
  return {};
15408
15423
  }
@@ -15414,6 +15429,9 @@ class ProgramEntryFormModule {
15414
15429
  ? this.#getTrackedEntityDataValues(this.instance())
15415
15430
  : this.instance();
15416
15431
  return {
15432
+ // Fallback for assignments hidden from the rendered form metadata.
15433
+ // Values held by the SDK instance take precedence when present.
15434
+ ...this.initialAutoAssignedValues(),
15417
15435
  ...attributeDataValues,
15418
15436
  ...(currentInstanceDataValues || {}),
15419
15437
  };
@@ -15480,11 +15498,13 @@ class ProgramEntryFormModule {
15480
15498
  console.error('Failed to create or load instance for program entry form');
15481
15499
  return;
15482
15500
  }
15483
- this.instance.set(instance);
15501
+ // Apply assignments BEFORE publishing the instance to the form. This
15502
+ // prevents a child form from initializing with pre-assignment values.
15484
15503
  const autoAssigned = config.autoAssignedValues;
15485
15504
  if (autoAssigned?.length) {
15486
- this.#updateInstanceWithAutoAssignedValues(autoAssigned);
15505
+ this.#updateInstanceWithAutoAssignedValues(instance, autoAssigned);
15487
15506
  }
15507
+ this.instance.set(instance);
15488
15508
  }
15489
15509
  catch (error) {
15490
15510
  console.error('Error during ProgramEntryForm initialization', error);
@@ -15494,7 +15514,35 @@ class ProgramEntryFormModule {
15494
15514
  }
15495
15515
  }
15496
15516
  onFormUpdate(dataValues) {
15497
- this.#updateInstance(dataValues);
15517
+ // Hidden auto-assigned fields may be absent from the FormGroup. Preserve
15518
+ // their CURRENT values (not repeatedly their initial defaults), so later
15519
+ // programmatic updates are not accidentally rolled back by another field.
15520
+ const preservedAssignedValues = {};
15521
+ if (this.config().hideCustomAssignedFields) {
15522
+ // Read the mutable SDK instance directly: a cached computed signal may
15523
+ // not yet reflect values modified by external SDK/preprocess code.
15524
+ const currentInstance = this.instance();
15525
+ const attributeValues = this.trackedEntityInstance()
15526
+ ? this.#getTrackedEntityDataValues(this.trackedEntityInstance())
15527
+ : {};
15528
+ const currentInstanceValues = this.config().formType === 'TRACKER' && currentInstance
15529
+ ? this.#getTrackedEntityDataValues(currentInstance)
15530
+ : currentInstance ?? {};
15531
+ const currentValues = {
15532
+ ...attributeValues,
15533
+ ...currentInstanceValues,
15534
+ };
15535
+ for (const [key, initialValue] of Object.entries(this.initialAutoAssignedValues())) {
15536
+ // orgUnit has its own registration control and precedence rules.
15537
+ if (key === 'orgUnit')
15538
+ continue;
15539
+ preservedAssignedValues[key] = Object.prototype.hasOwnProperty.call(currentValues, key)
15540
+ ? currentValues[key]
15541
+ : initialValue;
15542
+ }
15543
+ }
15544
+ // Explicit user edits and clears (including null/empty string) win.
15545
+ this.#updateInstance({ ...preservedAssignedValues, ...dataValues });
15498
15546
  if (this.instance()) {
15499
15547
  this.instanceUpdate.emit(this.instance());
15500
15548
  }
@@ -15526,10 +15574,11 @@ class ProgramEntryFormModule {
15526
15574
  }
15527
15575
  return configuredKey;
15528
15576
  }
15529
- #updateInstanceWithAutoAssignedValues(autoAssignedValues) {
15577
+ #updateInstanceWithAutoAssignedValues(instance, autoAssignedValues) {
15530
15578
  const trackedEntityId = this.trackedEntity?.();
15531
15579
  if (
15532
- // Event forms also receive a trackedEntity ID checking the ID alone prevented their auto-assigned fields from being populated since its passed even in creation of the events.
15580
+ // Existing TRACKER records must not have their stored attributes replaced.
15581
+ // EVENT forms may legitimately have an existing tracked entity ID.
15533
15582
  this.config().formType === 'TRACKER' &&
15534
15583
  typeof trackedEntityId === 'string' &&
15535
15584
  trackedEntityId.trim().length > 0) {
@@ -15543,6 +15592,14 @@ class ProgramEntryFormModule {
15543
15592
  const aggregatedValues = {};
15544
15593
  for (let index = 0; index < valueCount; index++) {
15545
15594
  const { field: configuredKey, value } = autoAssignedValues[index];
15595
+ if (!configuredKey)
15596
+ continue;
15597
+ // An explicit orgUnit input takes precedence over the optional
15598
+ // auto-assignment fallback used for new TRACKER registration.
15599
+ if (configuredKey === 'orgUnit' && this.orgUnit()?.trim()) {
15600
+ aggregatedValues['orgUnit'] = this.orgUnit().trim();
15601
+ continue;
15602
+ }
15546
15603
  const semanticKey = metaData
15547
15604
  ? this.#resolveFieldRuntimeId(configuredKey, metaData)
15548
15605
  : configuredKey;
@@ -15554,26 +15611,30 @@ class ProgramEntryFormModule {
15554
15611
  if (Object.keys(aggregatedValues).length === 0) {
15555
15612
  return;
15556
15613
  }
15557
- this.#updateInstance(aggregatedValues);
15614
+ this.initialAutoAssignedValues.set(aggregatedValues);
15615
+ this.#applyDataValues(instance, aggregatedValues);
15616
+ }
15617
+ #applyDataValues(instance, dataValues) {
15618
+ for (const key in dataValues) {
15619
+ if (Object.prototype.hasOwnProperty.call(dataValues, key)) {
15620
+ // Keep the existing SDK integration behavior for other consumers.
15621
+ instance[key] = dataValues[key];
15622
+ }
15623
+ }
15624
+ instance.updateDataValues(dataValues, this.config().updateTeiOrgUnit);
15558
15625
  }
15559
15626
  #updateInstance(dataValues) {
15560
15627
  if (!dataValues || Object.keys(dataValues).length === 0) {
15561
15628
  return;
15562
15629
  }
15563
- const shouldUpdateOrgUnit = this.config().updateTeiOrgUnit;
15564
- this.instance.update((instance) => {
15565
- if (!instance) {
15566
- return instance;
15567
- }
15568
- for (const key in dataValues) {
15569
- if (Object.prototype.hasOwnProperty.call(dataValues, key)) {
15570
- instance[key] =
15571
- dataValues[key];
15572
- }
15573
- }
15574
- instance.updateDataValues(dataValues, shouldUpdateOrgUnit);
15575
- return instance;
15576
- });
15630
+ const instance = this.instance();
15631
+ if (!instance) {
15632
+ return;
15633
+ }
15634
+ this.#applyDataValues(instance, dataValues);
15635
+ // The SDK model is a class, so do not spread/clone it just to change the
15636
+ // signal reference (that would discard its prototype methods).
15637
+ this.instanceRevision.update((revision) => revision + 1);
15577
15638
  }
15578
15639
  async #saveInstance() {
15579
15640
  if (this.preprocess() && this.instance()) {
@@ -15603,7 +15664,7 @@ class ProgramEntryFormModule {
15603
15664
  }
15604
15665
  }
15605
15666
  async #setReservedValuesForCodeGeneration(instance) {
15606
- const orgUnitForCodeGeneration = this.codeGeneratorOrgUnit() || this.orgUnit();
15667
+ const orgUnitForCodeGeneration = this.codeGeneratorOrgUnit() || this.#resolveTrackerOrgUnit();
15607
15668
  const reservedValueQuery = this.d2.trackerModule.trackedEntity.setProgram(this.config().program);
15608
15669
  if (orgUnitForCodeGeneration) {
15609
15670
  reservedValueQuery.setOrgUnit(orgUnitForCodeGeneration);
@@ -15614,13 +15675,28 @@ class ProgramEntryFormModule {
15614
15675
  });
15615
15676
  return instance;
15616
15677
  }
15678
+ #resolveTrackerOrgUnit() {
15679
+ const explicitOrgUnit = this.orgUnit()?.trim();
15680
+ if (explicitOrgUnit) {
15681
+ return explicitOrgUnit;
15682
+ }
15683
+ // For new TRACKER records, an orgUnit auto-assignment must also be used
15684
+ // when creating the instance/query, not only after it has been created.
15685
+ if (this.config().formType !== 'TRACKER' || this.trackedEntity()?.trim()) {
15686
+ return undefined;
15687
+ }
15688
+ const assignedOrgUnit = this.config().autoAssignedValues?.find((item) => item.field === 'orgUnit')?.value;
15689
+ return typeof assignedOrgUnit === 'string' && assignedOrgUnit.trim()
15690
+ ? assignedOrgUnit.trim()
15691
+ : undefined;
15692
+ }
15617
15693
  #getQuery(instanceType) {
15618
15694
  const d2 = window.d2Web;
15619
15695
  switch (instanceType) {
15620
15696
  case 'TRACKER':
15621
15697
  return d2.trackerModule.trackedEntity
15622
15698
  .setProgram(this.config().program)
15623
- .setOrgUnit(this.orgUnit());
15699
+ .setOrgUnit(this.#resolveTrackerOrgUnit());
15624
15700
  case 'EVENT':
15625
15701
  return d2.eventModule.event
15626
15702
  .setProgram(this.config().program)