@formio/js 5.0.0-dev.5944.74e70b0 → 5.0.0-dev.5948.072adfa
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/Changelog.md +1 -0
- package/dist/formio.form.js +583 -593
- package/dist/formio.form.min.js +1 -1
- package/dist/formio.form.min.js.LICENSE.txt +1 -3
- package/dist/formio.full.js +584 -594
- package/dist/formio.full.min.js +1 -1
- package/dist/formio.full.min.js.LICENSE.txt +1 -3
- package/dist/formio.js +3006 -287
- package/dist/formio.min.js +1 -1
- package/dist/formio.min.js.LICENSE.txt +12 -0
- package/dist/formio.utils.js +41 -51
- package/dist/formio.utils.min.js +1 -1
- package/dist/formio.utils.min.js.LICENSE.txt +1 -3
- package/lib/cjs/Webform.d.ts +1 -1
- package/lib/cjs/Webform.js +27 -28
- package/lib/cjs/WebformBuilder.js +6 -13
- package/lib/cjs/Wizard.js +4 -11
- package/lib/cjs/components/Components.d.ts +0 -7
- package/lib/cjs/components/Components.js +1 -33
- package/lib/cjs/components/_classes/component/Component.d.ts +39 -7
- package/lib/cjs/components/_classes/component/Component.js +97 -29
- package/lib/cjs/components/_classes/component/editForm/Component.edit.data.js +2 -2
- package/lib/cjs/components/_classes/componentModal/ComponentModal.d.ts +1 -0
- package/lib/cjs/components/_classes/componentModal/ComponentModal.js +1 -0
- package/lib/cjs/components/_classes/nested/NestedComponent.d.ts +4 -19
- package/lib/cjs/components/_classes/nested/NestedComponent.js +54 -60
- package/lib/cjs/components/_classes/nestedarray/NestedArrayComponent.d.ts +2 -1
- package/lib/cjs/components/_classes/nestedarray/NestedArrayComponent.js +9 -46
- package/lib/cjs/components/datagrid/DataGrid.d.ts +0 -1
- package/lib/cjs/components/datagrid/DataGrid.js +1 -45
- package/lib/cjs/components/datamap/DataMap.js +2 -3
- package/lib/cjs/components/editgrid/EditGrid.js +13 -13
- package/lib/cjs/components/form/Form.d.ts +1 -3
- package/lib/cjs/components/form/Form.js +21 -28
- package/lib/cjs/components/html/HTML.js +15 -3
- package/lib/cjs/components/selectboxes/SelectBoxes.js +0 -1
- package/lib/cjs/formio.form.js +1 -0
- package/lib/cjs/utils/conditionOperators/DateGreaterThan.js +2 -2
- package/lib/cjs/utils/conditionOperators/IsEmptyValue.d.ts +2 -2
- package/lib/cjs/utils/conditionOperators/IsEmptyValue.js +2 -2
- package/lib/cjs/utils/conditionOperators/IsEqualTo.d.ts +2 -2
- package/lib/cjs/utils/conditionOperators/IsEqualTo.js +2 -2
- package/lib/cjs/utils/formUtils.d.ts +25 -14
- package/lib/cjs/utils/formUtils.js +11 -16
- package/lib/cjs/utils/utils.d.ts +1 -2
- package/lib/cjs/utils/utils.js +15 -31
- package/lib/mjs/Webform.d.ts +1 -1
- package/lib/mjs/Webform.js +24 -27
- package/lib/mjs/WebformBuilder.js +6 -13
- package/lib/mjs/Wizard.js +2 -8
- package/lib/mjs/components/Components.d.ts +0 -7
- package/lib/mjs/components/Components.js +1 -32
- package/lib/mjs/components/_classes/component/Component.d.ts +39 -7
- package/lib/mjs/components/_classes/component/Component.js +99 -30
- package/lib/mjs/components/_classes/component/editForm/Component.edit.data.js +2 -2
- package/lib/mjs/components/_classes/componentModal/ComponentModal.d.ts +1 -0
- package/lib/mjs/components/_classes/componentModal/ComponentModal.js +1 -0
- package/lib/mjs/components/_classes/nested/NestedComponent.d.ts +4 -19
- package/lib/mjs/components/_classes/nested/NestedComponent.js +55 -61
- package/lib/mjs/components/_classes/nestedarray/NestedArrayComponent.d.ts +2 -1
- package/lib/mjs/components/_classes/nestedarray/NestedArrayComponent.js +8 -43
- package/lib/mjs/components/datagrid/DataGrid.d.ts +0 -1
- package/lib/mjs/components/datagrid/DataGrid.js +1 -45
- package/lib/mjs/components/datamap/DataMap.js +2 -3
- package/lib/mjs/components/editgrid/EditGrid.js +15 -12
- package/lib/mjs/components/form/Form.d.ts +1 -3
- package/lib/mjs/components/form/Form.js +22 -28
- package/lib/mjs/components/html/HTML.js +15 -3
- package/lib/mjs/components/selectboxes/SelectBoxes.js +0 -1
- package/lib/mjs/formio.form.js +1 -0
- package/lib/mjs/utils/conditionOperators/DateGreaterThan.js +2 -2
- package/lib/mjs/utils/conditionOperators/IsEmptyValue.d.ts +2 -2
- package/lib/mjs/utils/conditionOperators/IsEmptyValue.js +2 -2
- package/lib/mjs/utils/conditionOperators/IsEqualTo.d.ts +2 -2
- package/lib/mjs/utils/conditionOperators/IsEqualTo.js +2 -2
- package/lib/mjs/utils/formUtils.d.ts +25 -14
- package/lib/mjs/utils/formUtils.js +2 -12
- package/lib/mjs/utils/utils.d.ts +1 -2
- package/lib/mjs/utils/utils.js +14 -29
- package/package.json +4 -4
@@ -6,7 +6,7 @@ import isMobile from 'ismobilejs';
|
|
6
6
|
import { processOne, processOneSync, validateProcessInfo } from '@formio/core/process';
|
7
7
|
import { Formio } from '../../../Formio';
|
8
8
|
import * as FormioUtils from '../../../utils/utils';
|
9
|
-
import { fastCloneDeep, boolValue,
|
9
|
+
import { fastCloneDeep, boolValue, isInsideScopingComponent, currentTimezone, getScriptPlugin, getContextualRowData } from '../../../utils/utils';
|
10
10
|
import Element from '../../../Element';
|
11
11
|
import ComponentModal from '../componentModal/ComponentModal';
|
12
12
|
import Widgets from '../../../widgets';
|
@@ -221,6 +221,10 @@ export default class Component extends Element {
|
|
221
221
|
* @private
|
222
222
|
*/
|
223
223
|
this._hasCondition = null;
|
224
|
+
/**
|
225
|
+
* The row index for this component.
|
226
|
+
*/
|
227
|
+
this._rowIndex = undefined;
|
224
228
|
/**
|
225
229
|
* References to dom elements
|
226
230
|
*/
|
@@ -231,11 +235,6 @@ export default class Component extends Element {
|
|
231
235
|
this.options.components[component.type]) {
|
232
236
|
_.merge(component, this.options.components[component.type]);
|
233
237
|
}
|
234
|
-
/**
|
235
|
-
* The data path to this specific component instance.
|
236
|
-
* @type {string}
|
237
|
-
*/
|
238
|
-
this.path = component?.key || '';
|
239
238
|
/**
|
240
239
|
* An array of all the children components errors.
|
241
240
|
*/
|
@@ -304,15 +303,30 @@ export default class Component extends Element {
|
|
304
303
|
* @type {Component}
|
305
304
|
*/
|
306
305
|
this.parent = this.options.parent;
|
306
|
+
/**
|
307
|
+
* The component paths for this component.
|
308
|
+
* @type {import('@formio/core').ComponentPaths} - The component paths.
|
309
|
+
*/
|
310
|
+
this.paths = FormioUtils.getComponentPaths(this.component, this.parent?.component, {
|
311
|
+
...this.parent?.paths,
|
312
|
+
dataIndex: this.options.rowIndex === undefined ? this.parent?.paths?.dataIndex : this.options.rowIndex
|
313
|
+
});
|
307
314
|
this.options.name = this.options.name || 'data';
|
308
315
|
this._path = '';
|
309
316
|
// Needs for Nextgen Rules Engine
|
310
317
|
this.resetCaches();
|
318
|
+
/**
|
319
|
+
* Determines if this component is conditionally hidden. Should generally not be set outside of conditional logic pipeline.
|
320
|
+
* This is necessary because of clearOnHide behavior that only clears when conditionally hidden - we need to track
|
321
|
+
* conditionallyHidden separately from "regular" visibility.
|
322
|
+
*/
|
323
|
+
this._parentConditionallyHidden = this.options.hasOwnProperty('parentConditionallyHidden') ? this.options.parentConditionallyHidden : false;
|
324
|
+
this._conditionallyHidden = this.checkConditionallyHidden(null, data) || this._parentConditionallyHidden;
|
311
325
|
/**
|
312
326
|
* Determines if this component is visible, or not.
|
313
327
|
*/
|
314
328
|
this._parentVisible = this.options.hasOwnProperty('parentVisible') ? this.options.parentVisible : true;
|
315
|
-
this._visible = this._parentVisible && this.
|
329
|
+
this._visible = this._parentVisible && (this.hasCondition() ? !this._conditionallyHidden : !this.component.hidden);
|
316
330
|
this._parentDisabled = false;
|
317
331
|
/**
|
318
332
|
* The reference attribute name for this component
|
@@ -381,7 +395,7 @@ export default class Component extends Element {
|
|
381
395
|
if (this.allowData && this.key) {
|
382
396
|
this.options.name += `[${this.key}]`;
|
383
397
|
// If component is visible or not set to clear on hide, set the default value.
|
384
|
-
if (this.
|
398
|
+
if (!(this.conditionallyHidden && this.component.clearOnHide)) {
|
385
399
|
if (!this.hasValue()) {
|
386
400
|
if (this.shouldAddDefaultValue) {
|
387
401
|
this.dataValue = this.defaultValue;
|
@@ -409,12 +423,7 @@ export default class Component extends Element {
|
|
409
423
|
}
|
410
424
|
/* eslint-enable max-statements */
|
411
425
|
get componentsMap() {
|
412
|
-
|
413
|
-
return this.localRoot.childComponentsMap;
|
414
|
-
}
|
415
|
-
const localMap = {};
|
416
|
-
localMap[this.path] = this;
|
417
|
-
return localMap;
|
426
|
+
return this.root?.childComponentsMap || {};
|
418
427
|
}
|
419
428
|
get data() {
|
420
429
|
return this._data;
|
@@ -455,11 +464,31 @@ export default class Component extends Element {
|
|
455
464
|
}
|
456
465
|
init() {
|
457
466
|
this.disabled = this.shouldDisabled;
|
458
|
-
this.
|
467
|
+
this._conditionallyHidden = this.checkConditionallyHidden();
|
468
|
+
this._visible = (this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden);
|
459
469
|
if (this.component.addons?.length) {
|
460
470
|
this.component.addons.forEach((addon) => this.createAddon(addon));
|
461
471
|
}
|
462
472
|
}
|
473
|
+
/**
|
474
|
+
* Get Row Index.
|
475
|
+
* @returns {number} - The row index.
|
476
|
+
*/
|
477
|
+
get rowIndex() {
|
478
|
+
return this._rowIndex;
|
479
|
+
}
|
480
|
+
/**
|
481
|
+
* Set Row Index to row and update each component.
|
482
|
+
* @param {number} value - The row index.
|
483
|
+
* @returns {void}
|
484
|
+
*/
|
485
|
+
set rowIndex(value) {
|
486
|
+
this.paths = FormioUtils.getComponentPaths(this.component, this.parent?.component, {
|
487
|
+
...(this.parent?.paths || {}),
|
488
|
+
...{ dataIndex: value }
|
489
|
+
});
|
490
|
+
this._rowIndex = value;
|
491
|
+
}
|
463
492
|
afterComponentAssign() {
|
464
493
|
//implement in extended classes
|
465
494
|
}
|
@@ -528,6 +557,12 @@ export default class Component extends Element {
|
|
528
557
|
get key() {
|
529
558
|
return _.get(this.component, 'key', '');
|
530
559
|
}
|
560
|
+
get path() {
|
561
|
+
return this.paths.dataPath;
|
562
|
+
}
|
563
|
+
set path(path) {
|
564
|
+
throw new Error('Should not be setting the path of a component.');
|
565
|
+
}
|
531
566
|
set parentVisible(value) {
|
532
567
|
this._parentVisible = value;
|
533
568
|
}
|
@@ -573,7 +608,6 @@ export default class Component extends Element {
|
|
573
608
|
return;
|
574
609
|
}
|
575
610
|
this._visible = value;
|
576
|
-
this.clearOnHide();
|
577
611
|
this.redraw();
|
578
612
|
}
|
579
613
|
}
|
@@ -594,6 +628,21 @@ export default class Component extends Element {
|
|
594
628
|
}
|
595
629
|
return this._visible && this._parentVisible;
|
596
630
|
}
|
631
|
+
get conditionallyHidden() {
|
632
|
+
return this._conditionallyHidden || this._parentConditionallyHidden;
|
633
|
+
}
|
634
|
+
/**
|
635
|
+
* Evaluates whether the component is conditionally hidden (as opposed to intentionally hidden, e.g. via the `hidden` component schema property).
|
636
|
+
* @param {object} data - The data object to evaluate the condition against.
|
637
|
+
* @param {object} row - The row object to evaluate the condition against.
|
638
|
+
* @returns {boolean} - Whether the component is conditionally hidden.
|
639
|
+
*/
|
640
|
+
checkConditionallyHidden(data = null, row = null) {
|
641
|
+
if (!this.hasCondition()) {
|
642
|
+
return false;
|
643
|
+
}
|
644
|
+
return !this.conditionallyVisible(data, row);
|
645
|
+
}
|
597
646
|
get currentForm() {
|
598
647
|
return this._currentForm;
|
599
648
|
}
|
@@ -1246,7 +1295,7 @@ export default class Component extends Element {
|
|
1246
1295
|
if (refreshData === 'data') {
|
1247
1296
|
this.refresh(this.data, changed, flags);
|
1248
1297
|
}
|
1249
|
-
else if ((changePath &&
|
1298
|
+
else if ((changePath && (changed.instance?.paths?.localPath === refreshData)) && changed && changed.instance &&
|
1250
1299
|
// Make sure the changed component is not in a different "context". Solves issues where refreshOn being set
|
1251
1300
|
// in fields inside EditGrids could alter their state from other rows (which is bad).
|
1252
1301
|
this.inContext(changed.instance)) {
|
@@ -1764,7 +1813,7 @@ export default class Component extends Element {
|
|
1764
1813
|
rebuild() {
|
1765
1814
|
this.destroy();
|
1766
1815
|
this.init();
|
1767
|
-
this.visible = this.
|
1816
|
+
this.visible = this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden;
|
1768
1817
|
return this.redraw();
|
1769
1818
|
}
|
1770
1819
|
/**
|
@@ -1831,8 +1880,8 @@ export default class Component extends Element {
|
|
1831
1880
|
conditionallyVisible(data, row) {
|
1832
1881
|
data = data || this.rootValue;
|
1833
1882
|
row = row || this.data;
|
1834
|
-
if (this.builderMode || this.previewMode
|
1835
|
-
return
|
1883
|
+
if (this.builderMode || this.previewMode) {
|
1884
|
+
return true;
|
1836
1885
|
}
|
1837
1886
|
data = data || (this.root ? this.root.data : {});
|
1838
1887
|
return this.checkCondition(row, data);
|
@@ -1862,8 +1911,14 @@ export default class Component extends Element {
|
|
1862
1911
|
if (!this.builderMode & !this.previewMode && this.fieldLogic(data, row)) {
|
1863
1912
|
this.redraw();
|
1864
1913
|
}
|
1865
|
-
// Check advanced conditions
|
1866
|
-
const
|
1914
|
+
// Check advanced conditions (and cache the result)
|
1915
|
+
const isConditionallyHidden = this.checkConditionallyHidden(data, row) || this._parentConditionallyHidden;
|
1916
|
+
if (isConditionallyHidden !== this._conditionallyHidden) {
|
1917
|
+
this._conditionallyHidden = isConditionallyHidden;
|
1918
|
+
this.clearOnHide();
|
1919
|
+
}
|
1920
|
+
// Check visibility
|
1921
|
+
const visible = (this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden);
|
1867
1922
|
if (this.visible !== visible) {
|
1868
1923
|
this.visible = visible;
|
1869
1924
|
}
|
@@ -1973,6 +2028,12 @@ export default class Component extends Element {
|
|
1973
2028
|
FormioUtils.setActionProperty(newComponent, action, result, row, data, this);
|
1974
2029
|
const property = action.property.value;
|
1975
2030
|
if (!_.isEqual(_.get(this.component, property), _.get(newComponent, property))) {
|
2031
|
+
// Advanced Logic can modify the component's hidden property; because we track conditionally hidden state
|
2032
|
+
// separately from the component's hidden property, and technically this Advanced Logic conditionally hides
|
2033
|
+
// a component, we need to set _conditionallyHidden to the new value
|
2034
|
+
if (property === 'hidden') {
|
2035
|
+
this._conditionallyHidden = newComponent.hidden;
|
2036
|
+
}
|
1976
2037
|
changed = true;
|
1977
2038
|
}
|
1978
2039
|
break;
|
@@ -1986,7 +2047,7 @@ export default class Component extends Element {
|
|
1986
2047
|
component: newComponent,
|
1987
2048
|
result,
|
1988
2049
|
});
|
1989
|
-
if (!_.isEqual(oldValue, newValue) && !(this.component.clearOnHide &&
|
2050
|
+
if (!_.isEqual(oldValue, newValue) && !(this.component.clearOnHide && this.conditionallyHidden)) {
|
1990
2051
|
this.setValue(newValue);
|
1991
2052
|
if (this.viewOnly) {
|
1992
2053
|
this.dataValue = newValue;
|
@@ -2019,7 +2080,7 @@ export default class Component extends Element {
|
|
2019
2080
|
component: newComponent,
|
2020
2081
|
result,
|
2021
2082
|
}, 'value');
|
2022
|
-
if (!_.isEqual(oldValue, newValue) && !(this.component.clearOnHide &&
|
2083
|
+
if (!_.isEqual(oldValue, newValue) && !(this.component.clearOnHide && this.conditionallyHidden)) {
|
2023
2084
|
this.setValue(newValue);
|
2024
2085
|
if (this.viewOnly) {
|
2025
2086
|
this.dataValue = newValue;
|
@@ -2130,7 +2191,7 @@ export default class Component extends Element {
|
|
2130
2191
|
this.component.clearOnHide !== false &&
|
2131
2192
|
!this.options.readOnly &&
|
2132
2193
|
!this.options.showHiddenFields) {
|
2133
|
-
if (
|
2194
|
+
if (this.conditionallyHidden) {
|
2134
2195
|
this.deleteValue();
|
2135
2196
|
}
|
2136
2197
|
else if (!this.hasValue() && this.shouldAddDefaultValue) {
|
@@ -2392,7 +2453,7 @@ export default class Component extends Element {
|
|
2392
2453
|
*/
|
2393
2454
|
get dataValue() {
|
2394
2455
|
if (!this.key ||
|
2395
|
-
(
|
2456
|
+
(this.conditionallyHidden && this.component.clearOnHide && !this.rootPristine)) {
|
2396
2457
|
return this.emptyValue;
|
2397
2458
|
}
|
2398
2459
|
if (!this.hasValue() && this.shouldAddDefaultValue) {
|
@@ -2411,7 +2472,7 @@ export default class Component extends Element {
|
|
2411
2472
|
set dataValue(value) {
|
2412
2473
|
if (!this.allowData ||
|
2413
2474
|
!this.key ||
|
2414
|
-
(
|
2475
|
+
(this.conditionallyHidden && this.component.clearOnHide && !this.rootPristine)) {
|
2415
2476
|
return;
|
2416
2477
|
}
|
2417
2478
|
if ((value !== null) && (value !== undefined)) {
|
@@ -2731,7 +2792,7 @@ export default class Component extends Element {
|
|
2731
2792
|
// If no calculated value or
|
2732
2793
|
// hidden and set to clearOnHide (Don't calculate a value for a hidden field set to clear when hidden)
|
2733
2794
|
const { clearOnHide } = this.component;
|
2734
|
-
const shouldBeCleared =
|
2795
|
+
const shouldBeCleared = this.conditionallyHidden && clearOnHide;
|
2735
2796
|
const allowOverride = _.get(this.component, 'allowCalculateOverride', false);
|
2736
2797
|
if (shouldBeCleared) {
|
2737
2798
|
// remove calculated value so that the value is recalculated once component becomes visible
|
@@ -2857,6 +2918,9 @@ export default class Component extends Element {
|
|
2857
2918
|
* @returns {string} - The message to show when the component is invalid.
|
2858
2919
|
*/
|
2859
2920
|
invalidMessage(data, dirty, ignoreCondition, row) {
|
2921
|
+
if (!row) {
|
2922
|
+
row = getContextualRowData(this.component, data, this.paths);
|
2923
|
+
}
|
2860
2924
|
if (!ignoreCondition && !this.checkCondition(row, data)) {
|
2861
2925
|
return '';
|
2862
2926
|
}
|
@@ -2874,6 +2938,8 @@ export default class Component extends Element {
|
|
2874
2938
|
data,
|
2875
2939
|
row,
|
2876
2940
|
path: this.path || this.component.key,
|
2941
|
+
parent: this.parent?.component,
|
2942
|
+
paths: this.paths,
|
2877
2943
|
scope: validationScope,
|
2878
2944
|
instance: this,
|
2879
2945
|
processors: [
|
@@ -2926,7 +2992,7 @@ export default class Component extends Element {
|
|
2926
2992
|
if (flags.silentCheck) {
|
2927
2993
|
return [];
|
2928
2994
|
}
|
2929
|
-
let isDirty = this.dirty || flags.dirty;
|
2995
|
+
let isDirty = (flags.dirty === false) ? false : (this.dirty || flags.dirty);
|
2930
2996
|
if (this.options.alwaysDirty) {
|
2931
2997
|
isDirty = true;
|
2932
2998
|
}
|
@@ -2951,7 +3017,10 @@ export default class Component extends Element {
|
|
2951
3017
|
component: this.component,
|
2952
3018
|
data,
|
2953
3019
|
row,
|
3020
|
+
local: !!flags.local,
|
2954
3021
|
value: this.validationValue,
|
3022
|
+
parent: this.parent?.component,
|
3023
|
+
paths: this.paths,
|
2955
3024
|
path: this.path || this.component.key,
|
2956
3025
|
instance: this,
|
2957
3026
|
form: this.root ? this.root._form : {},
|
@@ -3368,7 +3437,7 @@ export default class Component extends Element {
|
|
3368
3437
|
// If component definition changed, replace it.
|
3369
3438
|
if (!_.isEqual(this.component, newComponent)) {
|
3370
3439
|
this.component = newComponent;
|
3371
|
-
const visible = this.
|
3440
|
+
const visible = this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden;
|
3372
3441
|
const disabled = this.shouldDisabled;
|
3373
3442
|
// Change states which won't be recalculated during redrawing
|
3374
3443
|
if (this.visible !== visible) {
|
@@ -128,10 +128,10 @@ export default [
|
|
128
128
|
{
|
129
129
|
weight: 700,
|
130
130
|
type: 'checkbox',
|
131
|
-
label: '
|
131
|
+
label: 'Omit Value From Submission Data When Conditionally Hidden',
|
132
132
|
key: 'clearOnHide',
|
133
133
|
defaultValue: true,
|
134
|
-
tooltip: 'When a field is hidden,
|
134
|
+
tooltip: 'When a field is conditionally hidden, omit the value from the submission data.',
|
135
135
|
input: true
|
136
136
|
},
|
137
137
|
EditFormUtils.javaScriptValue('Custom Default Value', 'customDefaultValue', 'customDefaultValue', 1000, '<p><h4>Example:</h4><pre>value = data.firstName + " " + data.lastName;</pre></p>', '<p><h4>Example:</h4><pre>{"cat": [{"var": "data.firstName"}, " ", {"var": "data.lastName"}]}</pre>'),
|
@@ -56,18 +56,6 @@ export default class NestedComponent extends Field {
|
|
56
56
|
* @returns {object} - The current form object.
|
57
57
|
*/
|
58
58
|
get currentForm(): object;
|
59
|
-
/**
|
60
|
-
* Set Row Index to row and update each component.
|
61
|
-
* @param {number} value - The row index.
|
62
|
-
* @returns {void}
|
63
|
-
*/
|
64
|
-
set rowIndex(value: number);
|
65
|
-
/**
|
66
|
-
* Get Row Index.
|
67
|
-
* @returns {number} - The row index.
|
68
|
-
*/
|
69
|
-
get rowIndex(): number;
|
70
|
-
_rowIndex: number | undefined;
|
71
59
|
/**
|
72
60
|
* Get Contextual data of the component.
|
73
61
|
* @returns {object} - The contextual data of the component.
|
@@ -115,14 +103,11 @@ export default class NestedComponent extends Field {
|
|
115
103
|
*/
|
116
104
|
eachComponent(fn: Function): void;
|
117
105
|
/**
|
118
|
-
* Returns a component provided a key. This performs a deep search within the
|
119
|
-
* component tree.
|
106
|
+
* Returns a component provided a key. This performs a deep search within the component tree.
|
120
107
|
* @param {string} path - The path to the component.
|
121
|
-
* @param {Function} [fn] - Called with the component once found.
|
122
|
-
* @param {string} [originalPath] - The original path to the component.
|
123
108
|
* @returns {any} - The component that is located.
|
124
109
|
*/
|
125
|
-
getComponent(path: string
|
110
|
+
getComponent(path: string): any;
|
126
111
|
/**
|
127
112
|
* Return a component provided the Id of the component.
|
128
113
|
* @param {string} id - The Id of the component.
|
@@ -211,12 +196,12 @@ export default class NestedComponent extends Field {
|
|
211
196
|
calculateValue(data: any, flags: any, row: any): any;
|
212
197
|
isLastPage(): boolean;
|
213
198
|
isValid(data: any, dirty: any): any;
|
214
|
-
validationProcessor({ scope, data, row, instance,
|
199
|
+
validationProcessor({ scope, data, row, instance, paths }: {
|
215
200
|
scope: any;
|
216
201
|
data: any;
|
217
202
|
row: any;
|
218
203
|
instance: any;
|
219
|
-
|
204
|
+
paths: any;
|
220
205
|
}, flags: any): void;
|
221
206
|
/**
|
222
207
|
* Perform a validation on all child components of this nested component.
|
@@ -2,7 +2,8 @@
|
|
2
2
|
import _ from 'lodash';
|
3
3
|
import Field from '../field/Field';
|
4
4
|
import Components from '../../Components';
|
5
|
-
|
5
|
+
'';
|
6
|
+
import { getComponentPaths, getRandomComponentId, componentMatches, getBestMatch, getStringFromComponentPath } from '../../../utils/utils';
|
6
7
|
import { process as processAsync, processSync } from '@formio/core/process';
|
7
8
|
/**
|
8
9
|
* NestedComponent class.
|
@@ -80,17 +81,26 @@ export default class NestedComponent extends Field {
|
|
80
81
|
const visibilityChanged = this._visible !== value;
|
81
82
|
this._visible = value;
|
82
83
|
const isVisible = this.visible;
|
84
|
+
const isConditionallyHidden = this.checkConditionallyHidden();
|
83
85
|
const forceShow = this.shouldForceShow();
|
84
86
|
const forceHide = this.shouldForceHide();
|
85
|
-
this.components.forEach(component => {
|
87
|
+
this.components.forEach((component) => {
|
86
88
|
// Set the parent visibility first since we may have nested components within nested components
|
87
89
|
// and they need to be able to determine their visibility based on the parent visibility.
|
88
90
|
component.parentVisible = isVisible;
|
89
|
-
|
90
|
-
|
91
|
+
component._parentConditionallyHidden = isConditionallyHidden;
|
92
|
+
let visible;
|
93
|
+
if (component.hasCondition()) {
|
94
|
+
component._conditionallyHidden = component.checkConditionallyHidden() || component._parentConditionallyHidden;
|
95
|
+
visible = !component.conditionallyHidden;
|
96
|
+
}
|
97
|
+
else {
|
98
|
+
visible = !component.component.hidden;
|
99
|
+
}
|
100
|
+
if (forceShow || visible) {
|
91
101
|
component.visible = true;
|
92
102
|
}
|
93
|
-
else if (forceHide || !isVisible || !
|
103
|
+
else if (forceHide || !isVisible || !visible) {
|
94
104
|
component.visible = false;
|
95
105
|
}
|
96
106
|
// If hiding a nested component, clear all errors below.
|
@@ -99,7 +109,6 @@ export default class NestedComponent extends Field {
|
|
99
109
|
}
|
100
110
|
});
|
101
111
|
if (visibilityChanged) {
|
102
|
-
this.clearOnHide();
|
103
112
|
this.redraw();
|
104
113
|
}
|
105
114
|
}
|
@@ -198,6 +207,10 @@ export default class NestedComponent extends Field {
|
|
198
207
|
*/
|
199
208
|
set rowIndex(value) {
|
200
209
|
this._rowIndex = value;
|
210
|
+
this.paths = getComponentPaths(this.component, this.parent?.component, {
|
211
|
+
...(this.parent?.paths || {}),
|
212
|
+
...{ dataIndex: value }
|
213
|
+
});
|
201
214
|
this.eachComponent((component) => {
|
202
215
|
component.rowIndex = value;
|
203
216
|
});
|
@@ -293,56 +306,36 @@ export default class NestedComponent extends Field {
|
|
293
306
|
});
|
294
307
|
}
|
295
308
|
/**
|
296
|
-
* Returns a component provided a key. This performs a deep search within the
|
297
|
-
* component tree.
|
309
|
+
* Returns a component provided a key. This performs a deep search within the component tree.
|
298
310
|
* @param {string} path - The path to the component.
|
299
|
-
* @param {Function} [fn] - Called with the component once found.
|
300
|
-
* @param {string} [originalPath] - The original path to the component.
|
301
311
|
* @returns {any} - The component that is located.
|
302
312
|
*/
|
303
|
-
getComponent(path
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
const matchPath = component.hasInput && component.path ? pathStr.includes(component.path) : true;
|
328
|
-
if (component.component.key === key) {
|
329
|
-
possibleComp = component;
|
330
|
-
if (matchPath) {
|
331
|
-
comp = component;
|
332
|
-
if (remainingPath.length > 0 && 'getComponent' in component) {
|
333
|
-
comp = component.getComponent(remainingPath, fn, originalPath);
|
334
|
-
}
|
335
|
-
else if (fn) {
|
336
|
-
fn(component, components);
|
337
|
-
}
|
338
|
-
return false;
|
339
|
-
}
|
340
|
-
}
|
313
|
+
getComponent(path) {
|
314
|
+
path = getStringFromComponentPath(path);
|
315
|
+
const matches = {
|
316
|
+
path: undefined,
|
317
|
+
fullPath: undefined,
|
318
|
+
localPath: undefined,
|
319
|
+
fullLocalPath: undefined,
|
320
|
+
dataPath: undefined,
|
321
|
+
localDataPath: undefined,
|
322
|
+
key: undefined,
|
323
|
+
};
|
324
|
+
this.everyComponent((component) => {
|
325
|
+
// All searches are relative to this component so replace this path from the child paths.
|
326
|
+
componentMatches(component.component, {
|
327
|
+
path: component.paths?.path?.replace(new RegExp(`^${this.paths?.path}\\.?`), ''),
|
328
|
+
fullPath: component.paths?.fullPath?.replace(new RegExp(`^${this.paths?.fullPath}\\.?`), ''),
|
329
|
+
localPath: component.paths?.localPath?.replace(new RegExp(`^${this.paths?.localPath}\\.?`), ''),
|
330
|
+
fullLocalPath: component.paths?.fullLocalPath?.replace(new RegExp(`^${this.paths?.fullLocalPath}\\.?`), ''),
|
331
|
+
dataPath: component.paths?.dataPath?.replace(new RegExp(`^${this.paths?.dataPath}\\.?`), ''),
|
332
|
+
localDataPath: component.paths?.localDataPath?.replace(new RegExp(`^${this.paths?.localDataPath}\\.?`), ''),
|
333
|
+
}, path, this.rowIndex, matches, (type, match) => {
|
334
|
+
match.instance = component;
|
335
|
+
return match;
|
336
|
+
});
|
341
337
|
});
|
342
|
-
|
343
|
-
comp = possibleComp;
|
344
|
-
}
|
345
|
-
return comp;
|
338
|
+
return getBestMatch(matches)?.instance;
|
346
339
|
}
|
347
340
|
/**
|
348
341
|
* Return a component provided the Id of the component.
|
@@ -380,6 +373,7 @@ export default class NestedComponent extends Field {
|
|
380
373
|
data = data || this.data;
|
381
374
|
options.parent = this;
|
382
375
|
options.parentVisible = this.visible;
|
376
|
+
options.parentConditionallyHidden = this.conditionallyHidden;
|
383
377
|
options.root = options?.root || this.root || this;
|
384
378
|
options.localRoot = this.localRoot;
|
385
379
|
options.skipInit = true;
|
@@ -638,7 +632,7 @@ export default class NestedComponent extends Field {
|
|
638
632
|
clearOnHide(show) {
|
639
633
|
super.clearOnHide(show);
|
640
634
|
if (this.component.clearOnHide) {
|
641
|
-
if (this.allowData && !this.hasValue() && !
|
635
|
+
if (this.allowData && !this.hasValue() && !this.conditionallyHidden) {
|
642
636
|
this.dataValue = this.defaultValue;
|
643
637
|
}
|
644
638
|
if (this.hasValue()) {
|
@@ -667,7 +661,7 @@ export default class NestedComponent extends Field {
|
|
667
661
|
}
|
668
662
|
calculateValue(data, flags, row) {
|
669
663
|
// Do not iterate into children and calculateValues if this nested component is conditionally hidden.
|
670
|
-
if (
|
664
|
+
if (this.conditionallyHidden) {
|
671
665
|
return false;
|
672
666
|
}
|
673
667
|
return this.getComponents().reduce((changed, comp) => comp.calculateValue(data, flags, row) || changed, super.calculateValue(data, flags, row));
|
@@ -678,19 +672,16 @@ export default class NestedComponent extends Field {
|
|
678
672
|
isValid(data, dirty) {
|
679
673
|
return this.getComponents().reduce((valid, comp) => comp.isValid(data, dirty) && valid, super.isValid(data, dirty));
|
680
674
|
}
|
681
|
-
validationProcessor({ scope, data, row, instance,
|
675
|
+
validationProcessor({ scope, data, row, instance, paths }, flags) {
|
682
676
|
const { dirty } = flags;
|
683
677
|
if (this.root.hasExtraPages && this.page !== this.root.page) {
|
684
|
-
instance = this.
|
685
|
-
? this.
|
686
|
-
: this.getComponent(
|
678
|
+
instance = this.componentsMap?.hasOwnProperty(paths.dataPath)
|
679
|
+
? this.componentsMap[paths.dataPath]
|
680
|
+
: this.getComponent(paths.dataPath);
|
687
681
|
}
|
688
682
|
if (!instance) {
|
689
683
|
return;
|
690
684
|
}
|
691
|
-
if (!instance.component.path) {
|
692
|
-
instance.component.path = component.path;
|
693
|
-
}
|
694
685
|
instance.checkComponentValidity(data, dirty, row, flags, scope.errors);
|
695
686
|
if (instance.processOwnValidation) {
|
696
687
|
scope.noRecurse = true;
|
@@ -722,7 +713,10 @@ export default class NestedComponent extends Field {
|
|
722
713
|
components,
|
723
714
|
instances: this.componentsMap,
|
724
715
|
data: data,
|
716
|
+
local: !!flags.local,
|
725
717
|
scope: { errors: [] },
|
718
|
+
parent: this.component,
|
719
|
+
parentPaths: this.paths,
|
726
720
|
processors: [
|
727
721
|
{
|
728
722
|
process: validationProcessorProcess,
|
@@ -2,6 +2,8 @@ export default class NestedArrayComponent extends NestedDataComponent {
|
|
2
2
|
static savedValueTypes(): string[];
|
3
3
|
componentContext(component: any): any;
|
4
4
|
get iteratableRows(): void;
|
5
|
+
set rowIndex(value: number | undefined);
|
6
|
+
get rowIndex(): number | undefined;
|
5
7
|
prevHasAddButton: any;
|
6
8
|
checkAddButtonChanged(): void;
|
7
9
|
checkData(data: any, flags: any, row: any): any;
|
@@ -10,7 +12,6 @@ export default class NestedArrayComponent extends NestedDataComponent {
|
|
10
12
|
checkRow(...args: any[]): any;
|
11
13
|
processRow(method: any, data: any, opts: any, row: any, components: any, silentCheck: any): any;
|
12
14
|
hasAddButton(): any;
|
13
|
-
getComponent(path: any, fn: any, originalPath: any): any;
|
14
15
|
everyComponent(fn: any, rowIndex: any, options?: {}): void;
|
15
16
|
_getEmailTableHeader(options: any): string;
|
16
17
|
_getEmailTableBody(options: any): string;
|