@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.
Files changed (80) hide show
  1. package/Changelog.md +1 -0
  2. package/dist/formio.form.js +583 -593
  3. package/dist/formio.form.min.js +1 -1
  4. package/dist/formio.form.min.js.LICENSE.txt +1 -3
  5. package/dist/formio.full.js +584 -594
  6. package/dist/formio.full.min.js +1 -1
  7. package/dist/formio.full.min.js.LICENSE.txt +1 -3
  8. package/dist/formio.js +3006 -287
  9. package/dist/formio.min.js +1 -1
  10. package/dist/formio.min.js.LICENSE.txt +12 -0
  11. package/dist/formio.utils.js +41 -51
  12. package/dist/formio.utils.min.js +1 -1
  13. package/dist/formio.utils.min.js.LICENSE.txt +1 -3
  14. package/lib/cjs/Webform.d.ts +1 -1
  15. package/lib/cjs/Webform.js +27 -28
  16. package/lib/cjs/WebformBuilder.js +6 -13
  17. package/lib/cjs/Wizard.js +4 -11
  18. package/lib/cjs/components/Components.d.ts +0 -7
  19. package/lib/cjs/components/Components.js +1 -33
  20. package/lib/cjs/components/_classes/component/Component.d.ts +39 -7
  21. package/lib/cjs/components/_classes/component/Component.js +97 -29
  22. package/lib/cjs/components/_classes/component/editForm/Component.edit.data.js +2 -2
  23. package/lib/cjs/components/_classes/componentModal/ComponentModal.d.ts +1 -0
  24. package/lib/cjs/components/_classes/componentModal/ComponentModal.js +1 -0
  25. package/lib/cjs/components/_classes/nested/NestedComponent.d.ts +4 -19
  26. package/lib/cjs/components/_classes/nested/NestedComponent.js +54 -60
  27. package/lib/cjs/components/_classes/nestedarray/NestedArrayComponent.d.ts +2 -1
  28. package/lib/cjs/components/_classes/nestedarray/NestedArrayComponent.js +9 -46
  29. package/lib/cjs/components/datagrid/DataGrid.d.ts +0 -1
  30. package/lib/cjs/components/datagrid/DataGrid.js +1 -45
  31. package/lib/cjs/components/datamap/DataMap.js +2 -3
  32. package/lib/cjs/components/editgrid/EditGrid.js +13 -13
  33. package/lib/cjs/components/form/Form.d.ts +1 -3
  34. package/lib/cjs/components/form/Form.js +21 -28
  35. package/lib/cjs/components/html/HTML.js +15 -3
  36. package/lib/cjs/components/selectboxes/SelectBoxes.js +0 -1
  37. package/lib/cjs/formio.form.js +1 -0
  38. package/lib/cjs/utils/conditionOperators/DateGreaterThan.js +2 -2
  39. package/lib/cjs/utils/conditionOperators/IsEmptyValue.d.ts +2 -2
  40. package/lib/cjs/utils/conditionOperators/IsEmptyValue.js +2 -2
  41. package/lib/cjs/utils/conditionOperators/IsEqualTo.d.ts +2 -2
  42. package/lib/cjs/utils/conditionOperators/IsEqualTo.js +2 -2
  43. package/lib/cjs/utils/formUtils.d.ts +25 -14
  44. package/lib/cjs/utils/formUtils.js +11 -16
  45. package/lib/cjs/utils/utils.d.ts +1 -2
  46. package/lib/cjs/utils/utils.js +15 -31
  47. package/lib/mjs/Webform.d.ts +1 -1
  48. package/lib/mjs/Webform.js +24 -27
  49. package/lib/mjs/WebformBuilder.js +6 -13
  50. package/lib/mjs/Wizard.js +2 -8
  51. package/lib/mjs/components/Components.d.ts +0 -7
  52. package/lib/mjs/components/Components.js +1 -32
  53. package/lib/mjs/components/_classes/component/Component.d.ts +39 -7
  54. package/lib/mjs/components/_classes/component/Component.js +99 -30
  55. package/lib/mjs/components/_classes/component/editForm/Component.edit.data.js +2 -2
  56. package/lib/mjs/components/_classes/componentModal/ComponentModal.d.ts +1 -0
  57. package/lib/mjs/components/_classes/componentModal/ComponentModal.js +1 -0
  58. package/lib/mjs/components/_classes/nested/NestedComponent.d.ts +4 -19
  59. package/lib/mjs/components/_classes/nested/NestedComponent.js +55 -61
  60. package/lib/mjs/components/_classes/nestedarray/NestedArrayComponent.d.ts +2 -1
  61. package/lib/mjs/components/_classes/nestedarray/NestedArrayComponent.js +8 -43
  62. package/lib/mjs/components/datagrid/DataGrid.d.ts +0 -1
  63. package/lib/mjs/components/datagrid/DataGrid.js +1 -45
  64. package/lib/mjs/components/datamap/DataMap.js +2 -3
  65. package/lib/mjs/components/editgrid/EditGrid.js +15 -12
  66. package/lib/mjs/components/form/Form.d.ts +1 -3
  67. package/lib/mjs/components/form/Form.js +22 -28
  68. package/lib/mjs/components/html/HTML.js +15 -3
  69. package/lib/mjs/components/selectboxes/SelectBoxes.js +0 -1
  70. package/lib/mjs/formio.form.js +1 -0
  71. package/lib/mjs/utils/conditionOperators/DateGreaterThan.js +2 -2
  72. package/lib/mjs/utils/conditionOperators/IsEmptyValue.d.ts +2 -2
  73. package/lib/mjs/utils/conditionOperators/IsEmptyValue.js +2 -2
  74. package/lib/mjs/utils/conditionOperators/IsEqualTo.d.ts +2 -2
  75. package/lib/mjs/utils/conditionOperators/IsEqualTo.js +2 -2
  76. package/lib/mjs/utils/formUtils.d.ts +25 -14
  77. package/lib/mjs/utils/formUtils.js +2 -12
  78. package/lib/mjs/utils/utils.d.ts +1 -2
  79. package/lib/mjs/utils/utils.js +14 -29
  80. 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, getComponentPath, isInsideScopingComponent, currentTimezone, getScriptPlugin } from '../../../utils/utils';
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.conditionallyVisible(null, data);
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.visible || !this.component.clearOnHide) {
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
- if (this.localRoot?.childComponentsMap) {
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._visible = this.conditionallyVisible(null, null);
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 && getComponentPath(changed.instance) === refreshData) && changed && changed.instance &&
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.conditionallyVisible(null, null);
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 || !this.hasCondition()) {
1835
- return !this.component.hidden;
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 visible = this.conditionallyVisible(data, row);
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 && !this.visible)) {
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 && !this.visible)) {
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 (!this.visible) {
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
- (!this.visible && this.component.clearOnHide && !this.rootPristine)) {
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
- (!this.visible && this.component.clearOnHide && !this.rootPristine)) {
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 = !this.visible && clearOnHide;
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.conditionallyVisible(null, null);
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: 'Clear Value When Hidden',
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, clear the value.',
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>'),
@@ -22,6 +22,7 @@ export default class ComponentModal {
22
22
  modalOverlay: string;
23
23
  modalContents: string;
24
24
  modalClose: string;
25
+ componentContent: string;
25
26
  openModalWrapper: string;
26
27
  openModal: string;
27
28
  modalSave: string;
@@ -61,6 +61,7 @@ export default class ComponentModal {
61
61
  modalOverlay: 'single',
62
62
  modalContents: 'single',
63
63
  modalClose: 'single',
64
+ componentContent: 'single',
64
65
  openModalWrapper: 'single',
65
66
  openModal: 'single',
66
67
  modalSave: 'single',
@@ -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, fn?: Function | undefined, originalPath?: string | undefined): any;
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, component }: {
199
+ validationProcessor({ scope, data, row, instance, paths }: {
215
200
  scope: any;
216
201
  data: any;
217
202
  row: any;
218
203
  instance: any;
219
- component: any;
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
- import { getArrayFromComponentPath, getStringFromComponentPath, getRandomComponentId } from '../../../utils/utils';
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
- const conditionallyVisible = component.conditionallyVisible();
90
- if (forceShow || conditionallyVisible) {
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 || !conditionallyVisible) {
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, fn, originalPath) {
304
- originalPath = originalPath || getStringFromComponentPath(path);
305
- if (this.componentsMap.hasOwnProperty(originalPath)) {
306
- if (fn) {
307
- return fn(this.componentsMap[originalPath]);
308
- }
309
- else {
310
- return this.componentsMap[originalPath];
311
- }
312
- }
313
- path = getArrayFromComponentPath(path);
314
- const pathStr = originalPath;
315
- const newPath = _.clone(path);
316
- let key = newPath.shift();
317
- const remainingPath = newPath;
318
- let comp = null;
319
- let possibleComp = null;
320
- if (_.isNumber(key)) {
321
- key = remainingPath.shift();
322
- }
323
- if (!_.isString(key)) {
324
- return comp;
325
- }
326
- this.everyComponent((component, components) => {
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
- if (!comp) {
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() && !(this.options.server && !this.visible)) {
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 (!this.conditionallyVisible()) {
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, component }, flags) {
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.childComponentsMap?.hasOwnProperty(component.path)
685
- ? this.childComponentsMap[component.path]
686
- : this.getComponent(component.path);
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;