@iapps/ng-dhis2-ui 1.1.56 → 1.1.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/iapps-ng-dhis2-ui.mjs +247 -133
- package/fesm2022/iapps-ng-dhis2-ui.mjs.map +1 -1
- package/lib/modules/form/components/base-form-field.component.d.ts +3 -1
- package/lib/modules/form/containers/form-field/form-field.component.d.ts +1 -0
- package/lib/modules/form/hooks/field-validation.hook.d.ts +3 -1
- package/lib/modules/form/interfaces/form-field.interface.d.ts +1 -0
- package/lib/modules/form/models/form-field.model.d.ts +1 -0
- package/lib/modules/form/models/form-metadata-section.model.d.ts +1 -0
- package/lib/modules/form/utils/field-type.util.d.ts +1 -1
- package/lib/modules/form/utils/field.util.d.ts +1 -1
- package/lib/modules/program-entry-form/utils/program-entry-form-field.util.d.ts +1 -0
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@ import { NgxDhis2HttpClientService } from '@iapps/ngx-dhis2-http-client';
|
|
|
8
8
|
import * as React from 'react';
|
|
9
9
|
import React__default, { useState, useCallback, useRef, useEffect, createContext, useContext, useMemo } from 'react';
|
|
10
10
|
import * as ReactDOM from 'react-dom/client';
|
|
11
|
-
import { catchError, of, map, zip, firstValueFrom, Subject, takeUntil } from 'rxjs';
|
|
11
|
+
import { catchError, of, map, zip, firstValueFrom, filter, Subject, takeUntil } from 'rxjs';
|
|
12
12
|
import i18n from '@dhis2/d2-i18n';
|
|
13
13
|
import { colors, theme, spacers } from '@dhis2/ui-constants';
|
|
14
14
|
import PropTypes from 'prop-types';
|
|
@@ -34,8 +34,8 @@ import * as i2 from '@angular/forms';
|
|
|
34
34
|
import { Validators, UntypedFormControl, UntypedFormGroup, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
|
35
35
|
import { toObservable } from '@angular/core/rxjs-interop';
|
|
36
36
|
import { format } from 'date-fns';
|
|
37
|
+
import { DataQueryFilter, DataFilterCondition, ProgramRuleEngine } from '@iapps/d2-web-sdk';
|
|
37
38
|
import moment from 'moment';
|
|
38
|
-
import { ProgramRuleEngine } from '@iapps/d2-web-sdk';
|
|
39
39
|
|
|
40
40
|
class SharedDhis2UiModule {
|
|
41
41
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: SharedDhis2UiModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
@@ -4065,11 +4065,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
|
|
|
4065
4065
|
// Use of this source code is governed by a BSD-style
|
|
4066
4066
|
// license that can be found in the LICENSE file.
|
|
4067
4067
|
const useFieldValidation = (props) => {
|
|
4068
|
-
const { form, touched, field, value } = props;
|
|
4068
|
+
const { form, touched, field, value, initialError, recordExistError } = props;
|
|
4069
4069
|
const hasError = useMemo(() => {
|
|
4070
|
+
if (recordExistError) {
|
|
4071
|
+
return true;
|
|
4072
|
+
}
|
|
4073
|
+
if (initialError && value) {
|
|
4074
|
+
return true;
|
|
4075
|
+
}
|
|
4070
4076
|
return touched && (form.get(field.id) || form.get(field.key))?.invalid;
|
|
4071
|
-
}, [value, touched]);
|
|
4077
|
+
}, [value, touched, initialError, recordExistError]);
|
|
4072
4078
|
const validationError = useMemo(() => {
|
|
4079
|
+
if (recordExistError) {
|
|
4080
|
+
return recordExistError;
|
|
4081
|
+
}
|
|
4082
|
+
if (initialError && value) {
|
|
4083
|
+
return initialError;
|
|
4084
|
+
}
|
|
4073
4085
|
if (!touched) {
|
|
4074
4086
|
return undefined;
|
|
4075
4087
|
}
|
|
@@ -4080,25 +4092,26 @@ const useFieldValidation = (props) => {
|
|
|
4080
4092
|
if (error['min']) {
|
|
4081
4093
|
return `${field.label || 'Value'} should not be less than ${error['min'].min}!`;
|
|
4082
4094
|
}
|
|
4083
|
-
|
|
4095
|
+
if (error['max']) {
|
|
4084
4096
|
return `${field.label || 'Value'} should not be greater than ${error['max'].max}!`;
|
|
4085
4097
|
}
|
|
4086
|
-
|
|
4098
|
+
if (error['pattern']) {
|
|
4087
4099
|
if (field.type === 'email') {
|
|
4088
4100
|
return `The email address provided is not valid`;
|
|
4089
4101
|
}
|
|
4090
|
-
|
|
4102
|
+
if (field.type === 'tel') {
|
|
4091
4103
|
return 'Phone number provided is not valid';
|
|
4092
4104
|
}
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4105
|
+
return `${field.label || 'Value'} should have appropriate format`;
|
|
4106
|
+
}
|
|
4107
|
+
if (error['customError']) {
|
|
4108
|
+
return error['customError'];
|
|
4096
4109
|
}
|
|
4097
4110
|
return error['required']
|
|
4098
4111
|
? `${field.label || 'Value'} is required`
|
|
4099
4112
|
: undefined;
|
|
4100
|
-
}, [
|
|
4101
|
-
return {
|
|
4113
|
+
}, [touched, value, initialError, recordExistError]);
|
|
4114
|
+
return { validationError, hasError };
|
|
4102
4115
|
};
|
|
4103
4116
|
|
|
4104
4117
|
// Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
|
|
@@ -4134,6 +4147,7 @@ class FormField {
|
|
|
4134
4147
|
this.programStage = options.programStage;
|
|
4135
4148
|
this.program = options.program;
|
|
4136
4149
|
this.trackedEntityInstance = options.trackedEntityInstance;
|
|
4150
|
+
this.trackedEntityType = options.trackedEntityType;
|
|
4137
4151
|
this.hasOptions = options.hasOptions;
|
|
4138
4152
|
this.dependentField = options.dependentField;
|
|
4139
4153
|
this.displayInList = options.displayInList;
|
|
@@ -4319,6 +4333,8 @@ class FieldUtil {
|
|
|
4319
4333
|
return 'number';
|
|
4320
4334
|
case FieldType.PHONE_NUMBER:
|
|
4321
4335
|
return 'tel';
|
|
4336
|
+
case FieldType.EMAIL:
|
|
4337
|
+
return 'email';
|
|
4322
4338
|
case FieldType.ORG_UNIT:
|
|
4323
4339
|
return 'org-unit';
|
|
4324
4340
|
case FieldType.DATE:
|
|
@@ -4435,8 +4451,11 @@ class FormUtil {
|
|
|
4435
4451
|
const maxValidators = field.max
|
|
4436
4452
|
? [Validators.max(field.max)]
|
|
4437
4453
|
: [];
|
|
4438
|
-
const phoneNumberValidator = field.type === 'tel'
|
|
4439
|
-
|
|
4454
|
+
const phoneNumberValidator = field.type === 'tel' ? [] : [];
|
|
4455
|
+
const emailValidator = field.type === 'email'
|
|
4456
|
+
? [
|
|
4457
|
+
Validators.pattern('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$'),
|
|
4458
|
+
]
|
|
4440
4459
|
: [];
|
|
4441
4460
|
group[field.key] = field.required
|
|
4442
4461
|
? new UntypedFormControl({ value, disabled: field.disabled }, {
|
|
@@ -4445,6 +4464,7 @@ class FormUtil {
|
|
|
4445
4464
|
...minValidators,
|
|
4446
4465
|
...maxValidators,
|
|
4447
4466
|
...phoneNumberValidator,
|
|
4467
|
+
...emailValidator,
|
|
4448
4468
|
],
|
|
4449
4469
|
updateOn: 'change',
|
|
4450
4470
|
})
|
|
@@ -4453,6 +4473,7 @@ class FormUtil {
|
|
|
4453
4473
|
...minValidators,
|
|
4454
4474
|
...maxValidators,
|
|
4455
4475
|
...phoneNumberValidator,
|
|
4476
|
+
...emailValidator,
|
|
4456
4477
|
],
|
|
4457
4478
|
});
|
|
4458
4479
|
if (field.referenceKey) {
|
|
@@ -4466,6 +4487,7 @@ class FormUtil {
|
|
|
4466
4487
|
...minValidators,
|
|
4467
4488
|
...maxValidators,
|
|
4468
4489
|
...phoneNumberValidator,
|
|
4490
|
+
...emailValidator,
|
|
4469
4491
|
],
|
|
4470
4492
|
updateOn: 'change',
|
|
4471
4493
|
})
|
|
@@ -4474,6 +4496,7 @@ class FormUtil {
|
|
|
4474
4496
|
...minValidators,
|
|
4475
4497
|
...maxValidators,
|
|
4476
4498
|
...phoneNumberValidator,
|
|
4499
|
+
...emailValidator,
|
|
4477
4500
|
],
|
|
4478
4501
|
});
|
|
4479
4502
|
}
|
|
@@ -4692,6 +4715,9 @@ class MetadataRule {
|
|
|
4692
4715
|
const regex = /(A|#|V)\{([^}]+)\}/g;
|
|
4693
4716
|
return this.rule?.condition?.replace(regex, (match, _, ruleVariable) => {
|
|
4694
4717
|
const ruleVariableObject = this.ruleVariables?.find((variable) => variable.name === ruleVariable);
|
|
4718
|
+
if (!ruleVariableObject) {
|
|
4719
|
+
return `{${ruleVariable}}`;
|
|
4720
|
+
}
|
|
4695
4721
|
const code = camelCase(ruleVariableObject?.dataElement?.code) ||
|
|
4696
4722
|
ruleVariableObject?.dataElement?.id ||
|
|
4697
4723
|
camelCase(ruleVariableObject?.trackedEntityAttribute?.code) ||
|
|
@@ -4719,6 +4745,7 @@ class FormMetadataSection {
|
|
|
4719
4745
|
sortOrder: programTrackedEntityAttribute['sortOrder'],
|
|
4720
4746
|
mandatory: programTrackedEntityAttribute['mandatory'],
|
|
4721
4747
|
allowFutureDate: programTrackedEntityAttribute['allowFutureDate'],
|
|
4748
|
+
trackedEntityType: (this.params.program['trackedEntityType'] || {})['id'],
|
|
4722
4749
|
metaType: 'ATTRIBUTE',
|
|
4723
4750
|
};
|
|
4724
4751
|
});
|
|
@@ -5331,6 +5358,7 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
5331
5358
|
this.httpClient = inject(NgxDhis2HttpClientService);
|
|
5332
5359
|
this.fieldType = 'textbox';
|
|
5333
5360
|
this.field = input.required();
|
|
5361
|
+
this.fieldError = input();
|
|
5334
5362
|
this.fieldConfig = input(new FieldConfig());
|
|
5335
5363
|
this.form = model.required();
|
|
5336
5364
|
this.isValid = input();
|
|
@@ -5338,6 +5366,7 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
5338
5366
|
this.value = model();
|
|
5339
5367
|
this.value$ = toObservable(this.value);
|
|
5340
5368
|
this.isValueAssigned$ = toObservable(this.isValueAssigned);
|
|
5369
|
+
this.fieldError$ = toObservable(this.fieldError);
|
|
5341
5370
|
this.label = computed(() => {
|
|
5342
5371
|
return !this.fieldConfig()?.hideLabel ? this.field().label : undefined;
|
|
5343
5372
|
});
|
|
@@ -5369,13 +5398,30 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
5369
5398
|
const [selected, setSelected] = useState();
|
|
5370
5399
|
const [touched, setTouched] = useState(false);
|
|
5371
5400
|
const [disabled, setDisabled] = useState(this.field()?.disabled ?? this.field()?.generated ?? false);
|
|
5401
|
+
const [initialError, setInitialError] = useState();
|
|
5402
|
+
const [recordExistError, setRecordExistError] = useState();
|
|
5403
|
+
const [checkingUniqueness, setCheckingUniqueness] = useState();
|
|
5372
5404
|
useEffect(() => {
|
|
5373
5405
|
if (this.isValueAssigned()) {
|
|
5406
|
+
const value = this.form().get(this.field().id)?.value ||
|
|
5407
|
+
this.form().get(this.field().key)?.value;
|
|
5374
5408
|
setDisabled(true);
|
|
5375
|
-
setValue(
|
|
5376
|
-
|
|
5409
|
+
setValue(value);
|
|
5410
|
+
checkValueUniqueness();
|
|
5377
5411
|
}
|
|
5378
5412
|
}, [this.isValueAssigned()]);
|
|
5413
|
+
useEffect(() => {
|
|
5414
|
+
const fieldErrorSubscription = this.fieldError$
|
|
5415
|
+
.pipe(filter((error) => error !== initialError))
|
|
5416
|
+
.subscribe({
|
|
5417
|
+
next: (error) => {
|
|
5418
|
+
setInitialError(error);
|
|
5419
|
+
},
|
|
5420
|
+
});
|
|
5421
|
+
return () => {
|
|
5422
|
+
fieldErrorSubscription.unsubscribe();
|
|
5423
|
+
};
|
|
5424
|
+
});
|
|
5379
5425
|
const onChange = (payload) => setSelected(payload.selected);
|
|
5380
5426
|
const arrayValue = useMemo(() => {
|
|
5381
5427
|
if (value && value.length > 0) {
|
|
@@ -5383,131 +5429,186 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
5383
5429
|
}
|
|
5384
5430
|
return [];
|
|
5385
5431
|
}, [value]);
|
|
5386
|
-
const {
|
|
5432
|
+
const { validationError, hasError } = useFieldValidation({
|
|
5387
5433
|
field: this.field(),
|
|
5388
5434
|
form: this.form(),
|
|
5435
|
+
initialError,
|
|
5436
|
+
recordExistError,
|
|
5389
5437
|
value,
|
|
5390
5438
|
touched,
|
|
5391
5439
|
});
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5440
|
+
const checkValueUniqueness = async () => {
|
|
5441
|
+
if (this.field().unique && this.field().trackedEntityType) {
|
|
5442
|
+
setCheckingUniqueness(true);
|
|
5443
|
+
setRecordExistError(undefined);
|
|
5444
|
+
const d2 = window.d2Web;
|
|
5445
|
+
try {
|
|
5446
|
+
const response = (await d2.trackerModule.trackedEntity
|
|
5447
|
+
.setTrackedEntityType(this.field().trackedEntityType)
|
|
5448
|
+
.setOuMode('ACCESSIBLE')
|
|
5449
|
+
.setFilters([
|
|
5450
|
+
new DataQueryFilter()
|
|
5451
|
+
.setAttribute(this.field().id)
|
|
5452
|
+
.setCondition(DataFilterCondition.Equal)
|
|
5453
|
+
.setValue(value),
|
|
5454
|
+
])
|
|
5455
|
+
.get())?.data;
|
|
5456
|
+
setCheckingUniqueness(false);
|
|
5457
|
+
if (response?.length > 0) {
|
|
5458
|
+
const customError = `Record with this ${this.label()} is already registered`;
|
|
5459
|
+
(this.form().controls[this.field().id] ||
|
|
5460
|
+
this.form().controls[this.field().key])?.setErrors({
|
|
5461
|
+
customError,
|
|
5402
5462
|
});
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5463
|
+
setRecordExistError(customError);
|
|
5464
|
+
}
|
|
5465
|
+
}
|
|
5466
|
+
catch (e) {
|
|
5467
|
+
setCheckingUniqueness(false);
|
|
5468
|
+
setRecordExistError(undefined);
|
|
5469
|
+
}
|
|
5470
|
+
}
|
|
5471
|
+
};
|
|
5472
|
+
const formFieldContent = () => {
|
|
5473
|
+
switch (this.field().controlType) {
|
|
5474
|
+
case 'textarea':
|
|
5475
|
+
return (React__default.createElement(TextAreaField, { error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, required: this.field().required, name: this.field().id, label: this.label(), rows: 5, placeholder: this.placeholder(), value: value, onChange: (event) => {
|
|
5476
|
+
this.ngZone.run(() => {
|
|
5477
|
+
(this.form().get(this.field().id) ||
|
|
5478
|
+
this.form().get(this.field().key))?.setValue(event.value);
|
|
5479
|
+
this.immediateUpdate.emit({
|
|
5480
|
+
form: this.form(),
|
|
5481
|
+
value: event.value,
|
|
5482
|
+
});
|
|
5418
5483
|
});
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5484
|
+
setValue(event.value);
|
|
5485
|
+
setTouched(true);
|
|
5486
|
+
}, onBlur: () => {
|
|
5487
|
+
checkValueUniqueness();
|
|
5488
|
+
this.ngZone.run(() => {
|
|
5489
|
+
this.update.emit({ form: this.form(), value });
|
|
5490
|
+
});
|
|
5491
|
+
} }));
|
|
5492
|
+
case 'org-unit':
|
|
5493
|
+
return (React__default.createElement(OrgUnitFormField, { label: this.label(), key: this.field().id, required: this.field().required, onSelectOrgUnit: (selectedOrgUnit) => {
|
|
5494
|
+
this.ngZone.run(() => {
|
|
5495
|
+
(this.form().get(this.field().id) ||
|
|
5496
|
+
this.form().get(this.field().key))?.setValue(selectedOrgUnit);
|
|
5497
|
+
this.update.emit({
|
|
5498
|
+
form: this.form(),
|
|
5499
|
+
value: selectedOrgUnit,
|
|
5500
|
+
});
|
|
5501
|
+
});
|
|
5502
|
+
setValue(selectedOrgUnit);
|
|
5503
|
+
setTouched(true);
|
|
5504
|
+
}, selected: value }));
|
|
5505
|
+
case 'transfer':
|
|
5506
|
+
return (React__default.createElement(Transfer, { filterable: true, filterPlaceholder: "Search", selected: selected, leftHeader: React__default.createElement("div", { style: {
|
|
5507
|
+
fontSize: 14,
|
|
5508
|
+
padding: '8px 4px',
|
|
5509
|
+
} }, this.field().availableOptionsLabel), rightHeader: React__default.createElement("div", { style: {
|
|
5510
|
+
fontSize: 14,
|
|
5511
|
+
padding: '8px 4px',
|
|
5512
|
+
} }, this.field().selectedOptionsLabel), options: this.field().options, onChange: (event) => {
|
|
5513
|
+
onChange({ selected: event.selected });
|
|
5514
|
+
this.ngZone.run(() => {
|
|
5515
|
+
(this.form().get(this.field().id) ||
|
|
5516
|
+
this.form().get(this.field().key))?.setValue(event.selected);
|
|
5517
|
+
});
|
|
5518
|
+
setValue(event.selected);
|
|
5519
|
+
setTouched(true);
|
|
5450
5520
|
this.update.emit({ form: this.form(), value });
|
|
5451
|
-
});
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
this.form().get(this.field().key))?.setValue(event.selected);
|
|
5458
|
-
this.update.emit({
|
|
5459
|
-
form: this.form(),
|
|
5460
|
-
value: event.selected,
|
|
5521
|
+
} }));
|
|
5522
|
+
case 'checkbox':
|
|
5523
|
+
return (React__default.createElement(Checkbox, { checked: Boolean(value), error: hasError, label: this.label(), name: this.field().id, disabled: disabled, onChange: (event) => {
|
|
5524
|
+
this.ngZone.run(() => {
|
|
5525
|
+
(this.form().get(this.field().id) ||
|
|
5526
|
+
this.form().get(this.field().key))?.setValue(event.checked);
|
|
5461
5527
|
});
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
const selectedValue = (event.selected || []).join(',');
|
|
5469
|
-
this.ngZone.run(() => {
|
|
5470
|
-
(this.form().get(this.field().id) ||
|
|
5471
|
-
this.form().get(this.field().key))?.setValue(selectedValue);
|
|
5472
|
-
this.update.emit({
|
|
5473
|
-
form: this.form(),
|
|
5474
|
-
value: selectedValue,
|
|
5528
|
+
setValue(event.checked);
|
|
5529
|
+
setTouched(true);
|
|
5530
|
+
}, onBlur: () => {
|
|
5531
|
+
checkValueUniqueness();
|
|
5532
|
+
this.ngZone.run(() => {
|
|
5533
|
+
this.update.emit({ form: this.form(), value });
|
|
5475
5534
|
});
|
|
5476
|
-
});
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
}, selected: arrayValue }, (this.field().options || []).map((option) => (React__default.createElement(MultiSelectOption, { key: option.key, label: option.label, value: option.value })))));
|
|
5480
|
-
case 'file':
|
|
5481
|
-
return (React__default.createElement(React__default.Fragment, null,
|
|
5482
|
-
React__default.createElement(FileUploadField, { label: this.label(), id: this.field().id, hasError: hasError, required: this.field().required, validationText: validationError, performUpload: true, uploadUrl: 'fileResources', onUploadSuccess: (fileId) => {
|
|
5535
|
+
} }));
|
|
5536
|
+
case 'dropdown':
|
|
5537
|
+
return (React__default.createElement(SingleSelectField, { filterable: (this.field().options || []).length > 5, clearable: true, error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, disabled: disabled, required: this.field().required, className: "select", label: this.label(), selected: value, onChange: (event) => {
|
|
5483
5538
|
this.ngZone.run(() => {
|
|
5484
|
-
this.form().get(this.field().id) ||
|
|
5485
|
-
this.form().get(this.field().key)?.setValue(
|
|
5539
|
+
(this.form().get(this.field().id) ||
|
|
5540
|
+
this.form().get(this.field().key))?.setValue(event.selected);
|
|
5486
5541
|
this.update.emit({
|
|
5487
5542
|
form: this.form(),
|
|
5488
|
-
value:
|
|
5543
|
+
value: event.selected,
|
|
5489
5544
|
});
|
|
5490
5545
|
});
|
|
5491
|
-
setValue(
|
|
5546
|
+
setValue(event.selected);
|
|
5492
5547
|
setTouched(true);
|
|
5493
|
-
}
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
this.
|
|
5500
|
-
|
|
5501
|
-
|
|
5548
|
+
}, onBlur: () => {
|
|
5549
|
+
checkValueUniqueness();
|
|
5550
|
+
} }, (this.field().options || []).map((option) => (React__default.createElement(SingleSelectOption, { key: crypto.randomUUID() || option.key, label: option.label, value: option.value })))));
|
|
5551
|
+
case 'multi-dropdown':
|
|
5552
|
+
return (React__default.createElement(MultiSelectField, { clearText: "Clear", clearable: true, empty: "No data found", filterable: (this.field().options || []).length > 5, filterPlaceholder: "Type to filter options", error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, disabled: disabled, label: this.label(), required: this.field().required, loadingText: "Loading options", noMatchText: "No options found", onChange: (event) => {
|
|
5553
|
+
const selectedValue = (event.selected || []).join(',');
|
|
5554
|
+
this.ngZone.run(() => {
|
|
5555
|
+
(this.form().get(this.field().id) ||
|
|
5556
|
+
this.form().get(this.field().key))?.setValue(selectedValue);
|
|
5557
|
+
this.update.emit({
|
|
5558
|
+
form: this.form(),
|
|
5559
|
+
value: selectedValue,
|
|
5560
|
+
});
|
|
5502
5561
|
});
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
this.
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5562
|
+
setValue(selectedValue);
|
|
5563
|
+
setTouched(true);
|
|
5564
|
+
}, onBlur: () => {
|
|
5565
|
+
checkValueUniqueness();
|
|
5566
|
+
}, selected: arrayValue }, (this.field().options || []).map((option) => (React__default.createElement(MultiSelectOption, { key: option.key, label: option.label, value: option.value })))));
|
|
5567
|
+
case 'file':
|
|
5568
|
+
return (React__default.createElement(React__default.Fragment, null,
|
|
5569
|
+
React__default.createElement(FileUploadField, { label: this.label(), id: this.field().id, hasError: hasError, required: this.field().required, validationText: validationError, performUpload: true, uploadUrl: 'fileResources', onUploadSuccess: (fileId) => {
|
|
5570
|
+
this.ngZone.run(() => {
|
|
5571
|
+
this.form().get(this.field().id) ||
|
|
5572
|
+
this.form().get(this.field().key)?.setValue(fileId);
|
|
5573
|
+
this.update.emit({
|
|
5574
|
+
form: this.form(),
|
|
5575
|
+
value: fileId,
|
|
5576
|
+
});
|
|
5577
|
+
});
|
|
5578
|
+
setValue(fileId);
|
|
5579
|
+
setTouched(true);
|
|
5580
|
+
} })));
|
|
5581
|
+
default:
|
|
5582
|
+
return (React__default.createElement(InputField$1, { error: hasError, validationText: validationError, type: this.field().type, inputWidth: this.fieldConfig()?.inputWidth, required: this.field().required, name: this.field().id, label: this.label(), min: this.field().min?.toString(), max: this.field().max?.toString(), placeholder: this.placeholder(), value: value, readOnly: disabled, onChange: (event) => {
|
|
5583
|
+
this.ngZone.run(() => {
|
|
5584
|
+
(this.form().get(this.field().id) ||
|
|
5585
|
+
this.form().get(this.field().key))?.setValue(event.value);
|
|
5586
|
+
this.immediateUpdate.emit({
|
|
5587
|
+
form: this.form(),
|
|
5588
|
+
value: event.value,
|
|
5589
|
+
});
|
|
5590
|
+
});
|
|
5591
|
+
setValue(event.value);
|
|
5592
|
+
setTouched(true);
|
|
5593
|
+
}, onBlur: () => {
|
|
5594
|
+
checkValueUniqueness();
|
|
5595
|
+
this.ngZone.run(() => {
|
|
5596
|
+
this.update.emit({ form: this.form(), value });
|
|
5597
|
+
});
|
|
5598
|
+
} }));
|
|
5599
|
+
}
|
|
5600
|
+
};
|
|
5601
|
+
{
|
|
5602
|
+
return (React__default.createElement(React__default.Fragment, null,
|
|
5603
|
+
formFieldContent(),
|
|
5604
|
+
checkingUniqueness && (React__default.createElement("div", { style: {
|
|
5605
|
+
display: 'flex',
|
|
5606
|
+
alignItems: 'center',
|
|
5607
|
+
gap: 8,
|
|
5608
|
+
paddingTop: 8,
|
|
5609
|
+
} },
|
|
5610
|
+
React__default.createElement(CircularLoader$1, { small: true }),
|
|
5611
|
+
React__default.createElement("div", { style: { color: colors$1.grey800, fontSize: 14 } }, "Checking...")))));
|
|
5511
5612
|
}
|
|
5512
5613
|
};
|
|
5513
5614
|
}
|
|
@@ -5515,7 +5616,7 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
5515
5616
|
this.value.set(event);
|
|
5516
5617
|
}
|
|
5517
5618
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: BaseFormFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
5518
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.1.8", type: BaseFormFieldComponent, isStandalone: true, inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, fieldConfig: { classPropertyName: "fieldConfig", publicName: "fieldConfig", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, isValid: { classPropertyName: "isValid", publicName: "isValid", isSignal: true, isRequired: false, transformFunction: null }, isValueAssigned: { classPropertyName: "isValueAssigned", publicName: "isValueAssigned", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { form: "formChange", value: "valueChange", update: "update", immediateUpdate: "immediateUpdate" }, usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
|
|
5619
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.1.8", type: BaseFormFieldComponent, isStandalone: true, inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, fieldError: { classPropertyName: "fieldError", publicName: "fieldError", isSignal: true, isRequired: false, transformFunction: null }, fieldConfig: { classPropertyName: "fieldConfig", publicName: "fieldConfig", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, isValid: { classPropertyName: "isValid", publicName: "isValid", isSignal: true, isRequired: false, transformFunction: null }, isValueAssigned: { classPropertyName: "isValueAssigned", publicName: "isValueAssigned", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { form: "formChange", value: "valueChange", update: "update", immediateUpdate: "immediateUpdate" }, usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
|
|
5519
5620
|
}
|
|
5520
5621
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: BaseFormFieldComponent, decorators: [{
|
|
5521
5622
|
type: Directive
|
|
@@ -5548,6 +5649,7 @@ class FormFieldComponent {
|
|
|
5548
5649
|
this.immediateFieldUpdate = new EventEmitter();
|
|
5549
5650
|
this.runtimeOptionChange = new EventEmitter();
|
|
5550
5651
|
this.value = signal('');
|
|
5652
|
+
this.runtimeError = signal(undefined);
|
|
5551
5653
|
this._runtimeOptions = [];
|
|
5552
5654
|
this.runtimeOptions = [];
|
|
5553
5655
|
this.fieldFilterControl = new FormControl();
|
|
@@ -5581,9 +5683,10 @@ class FormFieldComponent {
|
|
|
5581
5683
|
});
|
|
5582
5684
|
}
|
|
5583
5685
|
#processRules(ruleActions) {
|
|
5584
|
-
ruleActions
|
|
5585
|
-
|
|
5586
|
-
|
|
5686
|
+
const fieldRuleActions = ruleActions.filter((ruleAction) => ruleAction.field === this.field().id);
|
|
5687
|
+
let runtimeError;
|
|
5688
|
+
let isValueAssigned = false;
|
|
5689
|
+
fieldRuleActions.forEach((ruleAction) => {
|
|
5587
5690
|
switch (ruleAction.actionType) {
|
|
5588
5691
|
case 'ASSIGN': {
|
|
5589
5692
|
if (ruleAction.assignedData) {
|
|
@@ -5592,16 +5695,26 @@ class FormFieldComponent {
|
|
|
5592
5695
|
this.form
|
|
5593
5696
|
?.get(this.field().key)
|
|
5594
5697
|
?.setValue(ruleAction.assignedData);
|
|
5595
|
-
|
|
5698
|
+
isValueAssigned = true;
|
|
5596
5699
|
this.onValueChange();
|
|
5597
5700
|
}
|
|
5598
5701
|
}
|
|
5599
5702
|
break;
|
|
5600
5703
|
}
|
|
5704
|
+
case 'SHOWERROR': {
|
|
5705
|
+
runtimeError = ruleAction.displayedContent;
|
|
5706
|
+
(this.form.controls[this.field().id] ||
|
|
5707
|
+
this.form.controls[this.field().key])?.setErrors({
|
|
5708
|
+
customError: runtimeError,
|
|
5709
|
+
});
|
|
5710
|
+
break;
|
|
5711
|
+
}
|
|
5601
5712
|
default:
|
|
5602
5713
|
break;
|
|
5603
5714
|
}
|
|
5604
5715
|
});
|
|
5716
|
+
this.runtimeError.set(runtimeError);
|
|
5717
|
+
this.isValueAssigned.set(isValueAssigned);
|
|
5605
5718
|
}
|
|
5606
5719
|
ngOnDestroy() {
|
|
5607
5720
|
this._onDestroy.next();
|
|
@@ -5709,11 +5822,11 @@ class FormFieldComponent {
|
|
|
5709
5822
|
this._runtimeOptions = [...options];
|
|
5710
5823
|
}
|
|
5711
5824
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: FormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5712
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.1.8", type: FormFieldComponent, isStandalone: false, selector: "ng-dhis2-ui-form-field", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, fieldConfig: { classPropertyName: "fieldConfig", publicName: "fieldConfig", isSignal: false, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: false, isRequired: false, transformFunction: null }, isCheckBoxButton: { classPropertyName: "isCheckBoxButton", publicName: "isCheckBoxButton", isSignal: false, isRequired: false, transformFunction: null }, fieldClass: { classPropertyName: "fieldClass", publicName: "fieldClass", isSignal: false, isRequired: false, transformFunction: null }, programRuleActions: { classPropertyName: "programRuleActions", publicName: "programRuleActions", isSignal: true, isRequired: false, transformFunction: null }, dataEntities: { classPropertyName: "dataEntities", publicName: "dataEntities", isSignal: false, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: false, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { fieldUpdate: "fieldUpdate", immediateFieldUpdate: "immediateFieldUpdate", runtimeOptionChange: "runtimeOptionChange" }, usesOnChanges: true, ngImport: i0, template: "<div *ngIf=\"field()\" class=\"form-field-item\">\n <ng-dhis2-ui-form-field-item\n [field]=\"field()\"\n [isValueAssigned]=\"isValueAssigned()\"\n [fieldConfig]=\"fieldConfig\"\n [(form)]=\"form\"\n [value]=\"value()\"\n (update)=\"onValueChange()\"\n (immediateUpdate)=\"onImmediateChange($event)\"\n />\n</div>\n", styles: [".form-field-item{margin-bottom:16px}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FormFieldItemComponent, selector: "ng-dhis2-ui-form-field-item" }] }); }
|
|
5825
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.1.8", type: FormFieldComponent, isStandalone: false, selector: "ng-dhis2-ui-form-field", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, fieldConfig: { classPropertyName: "fieldConfig", publicName: "fieldConfig", isSignal: false, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: false, isRequired: false, transformFunction: null }, isCheckBoxButton: { classPropertyName: "isCheckBoxButton", publicName: "isCheckBoxButton", isSignal: false, isRequired: false, transformFunction: null }, fieldClass: { classPropertyName: "fieldClass", publicName: "fieldClass", isSignal: false, isRequired: false, transformFunction: null }, programRuleActions: { classPropertyName: "programRuleActions", publicName: "programRuleActions", isSignal: true, isRequired: false, transformFunction: null }, dataEntities: { classPropertyName: "dataEntities", publicName: "dataEntities", isSignal: false, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: false, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { fieldUpdate: "fieldUpdate", immediateFieldUpdate: "immediateFieldUpdate", runtimeOptionChange: "runtimeOptionChange" }, usesOnChanges: true, ngImport: i0, template: "<div *ngIf=\"field()\" class=\"form-field-item\">\n <ng-dhis2-ui-form-field-item\n [field]=\"field()\"\n [fieldError]=\"runtimeError()\"\n [isValueAssigned]=\"isValueAssigned()\"\n [fieldConfig]=\"fieldConfig\"\n [(form)]=\"form\"\n [value]=\"value()\"\n (update)=\"onValueChange()\"\n (immediateUpdate)=\"onImmediateChange($event)\"\n />\n</div>\n", styles: [".form-field-item{margin-bottom:16px}\n"], dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FormFieldItemComponent, selector: "ng-dhis2-ui-form-field-item" }] }); }
|
|
5713
5826
|
}
|
|
5714
5827
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: FormFieldComponent, decorators: [{
|
|
5715
5828
|
type: Component,
|
|
5716
|
-
args: [{ selector: 'ng-dhis2-ui-form-field', standalone: false, template: "<div *ngIf=\"field()\" class=\"form-field-item\">\n <ng-dhis2-ui-form-field-item\n [field]=\"field()\"\n [isValueAssigned]=\"isValueAssigned()\"\n [fieldConfig]=\"fieldConfig\"\n [(form)]=\"form\"\n [value]=\"value()\"\n (update)=\"onValueChange()\"\n (immediateUpdate)=\"onImmediateChange($event)\"\n />\n</div>\n", styles: [".form-field-item{margin-bottom:16px}\n"] }]
|
|
5829
|
+
args: [{ selector: 'ng-dhis2-ui-form-field', standalone: false, template: "<div *ngIf=\"field()\" class=\"form-field-item\">\n <ng-dhis2-ui-form-field-item\n [field]=\"field()\"\n [fieldError]=\"runtimeError()\"\n [isValueAssigned]=\"isValueAssigned()\"\n [fieldConfig]=\"fieldConfig\"\n [(form)]=\"form\"\n [value]=\"value()\"\n (update)=\"onValueChange()\"\n (immediateUpdate)=\"onImmediateChange($event)\"\n />\n</div>\n", styles: [".form-field-item{margin-bottom:16px}\n"] }]
|
|
5717
5830
|
}], ctorParameters: () => [], propDecorators: { fieldConfig: [{
|
|
5718
5831
|
type: Input
|
|
5719
5832
|
}], form: [{
|
|
@@ -6647,6 +6760,7 @@ class ProgramEntryFormFieldUtil {
|
|
|
6647
6760
|
sortOrder: programTrackedEntityAttribute.sortOrder,
|
|
6648
6761
|
mandatory: programTrackedEntityAttribute.mandatory,
|
|
6649
6762
|
allowFutureDate: programTrackedEntityAttribute.allowFutureDate,
|
|
6763
|
+
trackedEntityType: this.program.trackedEntityType?.id,
|
|
6650
6764
|
metaType: 'ATTRIBUTE',
|
|
6651
6765
|
stepId: null,
|
|
6652
6766
|
};
|
|
@@ -6729,7 +6843,7 @@ class ProgramEntryFormFieldUtil {
|
|
|
6729
6843
|
label: field.formName || field.name,
|
|
6730
6844
|
key: field.code ? camelCase(field.code) : field.id,
|
|
6731
6845
|
required: field.mandatory,
|
|
6732
|
-
type: field.valueType,
|
|
6846
|
+
type: FieldUtil.getFieldType(field.valueType),
|
|
6733
6847
|
options,
|
|
6734
6848
|
disabled: this.#getDisabledStatus(field),
|
|
6735
6849
|
order: field.sortOrder,
|
|
@@ -7000,7 +7114,7 @@ class ProgramEntryFormModule {
|
|
|
7000
7114
|
const instance = await this.#getInstance();
|
|
7001
7115
|
this.instance.set(instance);
|
|
7002
7116
|
if (this.config().autoAssignedValues) {
|
|
7003
|
-
this.#updateInstanceWithAutoAssignedValues(this.config().autoAssignedValues);
|
|
7117
|
+
this.#updateInstanceWithAutoAssignedValues(this.config().autoAssignedValues || []);
|
|
7004
7118
|
}
|
|
7005
7119
|
this.loading.set(false);
|
|
7006
7120
|
}
|