@formio/js 5.1.0-dev.6039.a838d78 → 5.1.0-dev.6042.18ef5d3

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 (144) hide show
  1. package/Changelog.md +140 -6
  2. package/dist/formio.form.js +587 -576
  3. package/dist/formio.form.min.js +1 -1
  4. package/dist/formio.full.js +609 -598
  5. package/dist/formio.full.min.js +1 -1
  6. package/dist/formio.js +45 -12
  7. package/dist/formio.min.js +1 -1
  8. package/dist/formio.utils.js +46 -13
  9. package/dist/formio.utils.min.js +1 -1
  10. package/lib/cjs/Element.d.ts +2 -1
  11. package/lib/cjs/Element.js +6 -4
  12. package/lib/cjs/Webform.d.ts +2 -2
  13. package/lib/cjs/Webform.js +6 -8
  14. package/lib/cjs/WebformBuilder.js +4 -0
  15. package/lib/cjs/Wizard.d.ts +1 -0
  16. package/lib/cjs/Wizard.js +23 -3
  17. package/lib/cjs/components/_classes/component/Component.d.ts +27 -17
  18. package/lib/cjs/components/_classes/component/Component.js +124 -70
  19. package/lib/cjs/components/_classes/component/editForm/Component.edit.data.js +19 -0
  20. package/lib/cjs/components/_classes/component/editForm/utils.js +1 -1
  21. package/lib/cjs/components/_classes/list/ListComponent.js +2 -2
  22. package/lib/cjs/components/_classes/nested/NestedComponent.d.ts +0 -1
  23. package/lib/cjs/components/_classes/nested/NestedComponent.form.js +13 -0
  24. package/lib/cjs/components/_classes/nested/NestedComponent.js +10 -18
  25. package/lib/cjs/components/_classes/nesteddata/NestedDataComponent.d.ts +0 -2
  26. package/lib/cjs/components/_classes/nesteddata/NestedDataComponent.js +0 -11
  27. package/lib/cjs/components/address/Address.d.ts +9 -0
  28. package/lib/cjs/components/address/Address.js +31 -8
  29. package/lib/cjs/components/address/editForm/Address.edit.display.d.ts +4 -0
  30. package/lib/cjs/components/address/editForm/Address.edit.display.js +1 -0
  31. package/lib/cjs/components/address/editForm/Address.edit.provider.js +8 -8
  32. package/lib/cjs/components/content/editForm/Content.edit.display.js +8 -0
  33. package/lib/cjs/components/currency/editForm/Currency.edit.display.js +12 -0
  34. package/lib/cjs/components/datagrid/DataGrid.js +0 -3
  35. package/lib/cjs/components/datamap/DataMap.js +2 -6
  36. package/lib/cjs/components/datetime/editForm/DateTime.edit.validation.d.ts +66 -15
  37. package/lib/cjs/components/datetime/editForm/DateTime.edit.validation.js +68 -47
  38. package/lib/cjs/components/day/editForm/Day.edit.display.js +8 -0
  39. package/lib/cjs/components/editgrid/EditGrid.js +3 -13
  40. package/lib/cjs/components/email/editForm/Email.edit.display.js +12 -0
  41. package/lib/cjs/components/fieldset/editForm/Fieldset.edit.display.js +8 -0
  42. package/lib/cjs/components/file/File.js +7 -2
  43. package/lib/cjs/components/file/editForm/File.edit.file.d.ts +13 -0
  44. package/lib/cjs/components/file/editForm/File.edit.file.js +1 -0
  45. package/lib/cjs/components/form/Form.js +11 -11
  46. package/lib/cjs/components/hidden/editForm/Hidden.edit.display.js +8 -0
  47. package/lib/cjs/components/html/HTML.js +1 -2
  48. package/lib/cjs/components/html/editForm/HTML.edit.display.js +8 -0
  49. package/lib/cjs/components/number/editForm/Number.edit.display.js +12 -0
  50. package/lib/cjs/components/password/editForm/Password.edit.display.js +13 -1
  51. package/lib/cjs/components/phonenumber/PhoneNumber.form.js +9 -1
  52. package/lib/cjs/components/radio/Radio.js +1 -1
  53. package/lib/cjs/components/select/Select.js +1 -1
  54. package/lib/cjs/components/select/editForm/Select.edit.data.d.ts +68 -110
  55. package/lib/cjs/components/select/editForm/Select.edit.data.js +2 -37
  56. package/lib/cjs/components/selectboxes/SelectBoxes.js +3 -0
  57. package/lib/cjs/components/survey/Survey.js +1 -1
  58. package/lib/cjs/components/tabs/Tabs.js +1 -0
  59. package/lib/cjs/components/tabs/editForm/Tabs.edit.display.js +8 -0
  60. package/lib/cjs/components/textarea/TextArea.js +9 -1
  61. package/lib/cjs/components/textarea/editForm/TextArea.edit.display.js +12 -0
  62. package/lib/cjs/components/unknown/Unknown.form.d.ts +2 -1
  63. package/lib/cjs/components/unknown/Unknown.form.js +13 -9
  64. package/lib/cjs/components/url/editForm/Url.edit.display.js +12 -0
  65. package/lib/cjs/components/well/editForm/Well.edit.display.js +8 -0
  66. package/lib/cjs/formio.form.js +2 -2
  67. package/lib/cjs/providers/storage/uploadAdapter.js +5 -3
  68. package/lib/cjs/translations/en.d.ts +1 -234
  69. package/lib/cjs/translations/en.js +4 -2
  70. package/lib/cjs/utils/formUtils.d.ts +2 -2
  71. package/lib/cjs/utils/utils.d.ts +0 -8
  72. package/lib/cjs/utils/utils.js +3 -23
  73. package/lib/mjs/Element.d.ts +2 -1
  74. package/lib/mjs/Element.js +6 -4
  75. package/lib/mjs/Webform.d.ts +2 -2
  76. package/lib/mjs/Webform.js +6 -8
  77. package/lib/mjs/WebformBuilder.js +4 -0
  78. package/lib/mjs/Wizard.d.ts +1 -0
  79. package/lib/mjs/Wizard.js +22 -2
  80. package/lib/mjs/components/_classes/component/Component.d.ts +27 -17
  81. package/lib/mjs/components/_classes/component/Component.js +125 -71
  82. package/lib/mjs/components/_classes/component/editForm/Component.edit.data.js +19 -0
  83. package/lib/mjs/components/_classes/component/editForm/utils.js +1 -1
  84. package/lib/mjs/components/_classes/list/ListComponent.js +2 -2
  85. package/lib/mjs/components/_classes/nested/NestedComponent.d.ts +0 -1
  86. package/lib/mjs/components/_classes/nested/NestedComponent.form.js +13 -0
  87. package/lib/mjs/components/_classes/nested/NestedComponent.js +10 -18
  88. package/lib/mjs/components/_classes/nesteddata/NestedDataComponent.d.ts +0 -2
  89. package/lib/mjs/components/_classes/nesteddata/NestedDataComponent.js +0 -11
  90. package/lib/mjs/components/address/Address.d.ts +9 -0
  91. package/lib/mjs/components/address/Address.js +31 -8
  92. package/lib/mjs/components/address/editForm/Address.edit.display.d.ts +4 -0
  93. package/lib/mjs/components/address/editForm/Address.edit.display.js +1 -0
  94. package/lib/mjs/components/address/editForm/Address.edit.provider.js +8 -8
  95. package/lib/mjs/components/content/editForm/Content.edit.display.js +8 -0
  96. package/lib/mjs/components/currency/editForm/Currency.edit.display.js +12 -0
  97. package/lib/mjs/components/datagrid/DataGrid.js +0 -3
  98. package/lib/mjs/components/datamap/DataMap.js +2 -6
  99. package/lib/mjs/components/datetime/editForm/DateTime.edit.validation.d.ts +66 -15
  100. package/lib/mjs/components/datetime/editForm/DateTime.edit.validation.js +68 -47
  101. package/lib/mjs/components/day/editForm/Day.edit.display.js +8 -0
  102. package/lib/mjs/components/editgrid/EditGrid.js +3 -12
  103. package/lib/mjs/components/email/editForm/Email.edit.display.js +12 -0
  104. package/lib/mjs/components/fieldset/editForm/Fieldset.edit.display.js +8 -0
  105. package/lib/mjs/components/file/File.js +7 -2
  106. package/lib/mjs/components/file/editForm/File.edit.file.d.ts +13 -0
  107. package/lib/mjs/components/file/editForm/File.edit.file.js +1 -0
  108. package/lib/mjs/components/form/Form.js +11 -11
  109. package/lib/mjs/components/hidden/editForm/Hidden.edit.display.js +8 -0
  110. package/lib/mjs/components/html/HTML.js +1 -2
  111. package/lib/mjs/components/html/editForm/HTML.edit.display.js +8 -0
  112. package/lib/mjs/components/number/editForm/Number.edit.display.js +12 -0
  113. package/lib/mjs/components/password/editForm/Password.edit.display.js +13 -1
  114. package/lib/mjs/components/phonenumber/PhoneNumber.form.js +9 -1
  115. package/lib/mjs/components/radio/Radio.js +1 -1
  116. package/lib/mjs/components/select/Select.js +1 -1
  117. package/lib/mjs/components/select/editForm/Select.edit.data.d.ts +68 -110
  118. package/lib/mjs/components/select/editForm/Select.edit.data.js +2 -37
  119. package/lib/mjs/components/selectboxes/SelectBoxes.js +3 -0
  120. package/lib/mjs/components/survey/Survey.js +1 -1
  121. package/lib/mjs/components/tabs/Tabs.js +1 -0
  122. package/lib/mjs/components/tabs/editForm/Tabs.edit.display.js +8 -0
  123. package/lib/mjs/components/textarea/TextArea.js +9 -1
  124. package/lib/mjs/components/textarea/editForm/TextArea.edit.display.js +12 -0
  125. package/lib/mjs/components/unknown/Unknown.form.d.ts +2 -1
  126. package/lib/mjs/components/unknown/Unknown.form.js +13 -9
  127. package/lib/mjs/components/url/editForm/Url.edit.display.js +12 -0
  128. package/lib/mjs/components/well/editForm/Well.edit.display.js +8 -0
  129. package/lib/mjs/formio.form.js +1 -1
  130. package/lib/mjs/providers/storage/uploadAdapter.js +5 -3
  131. package/lib/mjs/translations/en.d.ts +1 -234
  132. package/lib/mjs/translations/en.js +3 -47
  133. package/lib/mjs/utils/formUtils.d.ts +2 -2
  134. package/lib/mjs/utils/utils.d.ts +0 -8
  135. package/lib/mjs/utils/utils.js +2 -21
  136. package/package.json +2 -2
  137. package/lib/cjs/i18n.d.ts +0 -13
  138. package/lib/cjs/i18n.js +0 -19
  139. package/lib/cjs/utils/i18n.d.ts +0 -19
  140. package/lib/cjs/utils/i18n.js +0 -120
  141. package/lib/mjs/i18n.d.ts +0 -13
  142. package/lib/mjs/i18n.js +0 -14
  143. package/lib/mjs/utils/i18n.d.ts +0 -19
  144. package/lib/mjs/utils/i18n.js +0 -112
@@ -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, isInsideScopingComponent, currentTimezone, getScriptPlugin, getContextualRowData } from '../../../utils/utils';
9
+ import { fastCloneDeep, boolValue, 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';
@@ -316,18 +316,11 @@ export default class Component extends Element {
316
316
  this._path = '';
317
317
  // Needs for Nextgen Rules Engine
318
318
  this.resetCaches();
319
- /**
320
- * Determines if this component is conditionally hidden. Should generally not be set outside of conditional logic pipeline.
321
- * This is necessary because of clearOnHide behavior that only clears when conditionally hidden - we need to track
322
- * conditionallyHidden separately from "regular" visibility.
323
- */
324
- this._parentConditionallyHidden = this.options.hasOwnProperty('parentConditionallyHidden') ? this.options.parentConditionallyHidden : false;
325
- this._conditionallyHidden = this.checkConditionallyHidden(null, data) || this._parentConditionallyHidden;
326
319
  /**
327
320
  * Determines if this component is visible, or not.
328
321
  */
329
322
  this._parentVisible = this.options.hasOwnProperty('parentVisible') ? this.options.parentVisible : true;
330
- this._visible = this._parentVisible && (this.hasCondition() ? !this._conditionallyHidden : !this.component.hidden);
323
+ this._visible = this._parentVisible && (this.hasCondition() ? !this.conditionallyHidden() : !this.component.hidden);
331
324
  this._parentDisabled = false;
332
325
  /**
333
326
  * The reference attribute name for this component
@@ -396,7 +389,7 @@ export default class Component extends Element {
396
389
  if (this.allowData && this.key) {
397
390
  this.options.name += `[${this.key}]`;
398
391
  // If component is visible or not set to clear on hide, set the default value.
399
- if (!(this.conditionallyHidden && this.component.clearOnHide)) {
392
+ if (!this.shouldConditionallyClear()) {
400
393
  if (!this.hasValue()) {
401
394
  if (this.shouldAddDefaultValue) {
402
395
  this.dataValue = this.defaultValue;
@@ -429,6 +422,26 @@ export default class Component extends Element {
429
422
  get componentsMap() {
430
423
  return this.root?.childComponentsMap || {};
431
424
  }
425
+ parentShouldConditionallyClear() {
426
+ let currentParent = this.parent;
427
+ while (currentParent) {
428
+ if (currentParent.shouldConditionallyClear(true)) {
429
+ return true;
430
+ }
431
+ currentParent = currentParent.parent;
432
+ }
433
+ return false;
434
+ }
435
+ parentConditionallyHidden() {
436
+ let currentParent = this.parent;
437
+ while (currentParent) {
438
+ if (currentParent.conditionallyHidden(true)) {
439
+ return true;
440
+ }
441
+ currentParent = currentParent.parent;
442
+ }
443
+ return false;
444
+ }
432
445
  get data() {
433
446
  return this._data;
434
447
  }
@@ -468,8 +481,7 @@ export default class Component extends Element {
468
481
  }
469
482
  init() {
470
483
  this.disabled = this.shouldDisabled;
471
- this._conditionallyHidden = this.checkConditionallyHidden();
472
- this._visible = (this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden);
484
+ this._visible = (this.hasCondition() ? !this.conditionallyHidden() : !this.component.hidden);
473
485
  if (this.component.addons?.length) {
474
486
  this.component.addons.forEach((addon) => this.createAddon(addon));
475
487
  }
@@ -635,20 +647,54 @@ export default class Component extends Element {
635
647
  }
636
648
  return this._visible && this._parentVisible;
637
649
  }
638
- get conditionallyHidden() {
639
- return this._conditionallyHidden || this._parentConditionallyHidden;
650
+ get logicallyHidden() {
651
+ if (this._logicallyHidden && !this.component.hidden) {
652
+ this._logicallyHidden = false;
653
+ }
654
+ return this._logicallyHidden;
640
655
  }
641
- /**
642
- * Evaluates whether the component is conditionally hidden (as opposed to intentionally hidden, e.g. via the `hidden` component schema property).
643
- * @param {object} data - The data object to evaluate the condition against.
644
- * @param {object} row - The row object to evaluate the condition against.
645
- * @returns {boolean} - Whether the component is conditionally hidden.
646
- */
647
- checkConditionallyHidden(data = null, row = null) {
648
- if (!this.hasCondition()) {
656
+ shouldConditionallyClear(skipParent = false) {
657
+ // Skip if this component has clearOnHide set to false.
658
+ if (this.component.clearOnHide === false) {
649
659
  return false;
650
660
  }
651
- return !this.conditionallyVisible(data, row);
661
+ // If the component is logically hidden, then it is conditionally hidden and should clear.
662
+ if (this.logicallyHidden) {
663
+ return true;
664
+ }
665
+ // If we have a condition and it is not conditionally visible, the it should conditionally clear.
666
+ if (this.hasCondition() && !this.conditionallyVisible()) {
667
+ return true;
668
+ }
669
+ if (skipParent) {
670
+ // Stop recurrsion for the parent checks.
671
+ return false;
672
+ }
673
+ // If this component has a set value, then it should ONLY clear if a parent is hidden
674
+ // and has the clearOnHide set to true.
675
+ if (this.hasSetValue) {
676
+ return this.parentShouldConditionallyClear();
677
+ }
678
+ // Clear the value if the parent is conditionally hidden.
679
+ return this.parentConditionallyHidden();
680
+ }
681
+ conditionallyHidden(skipParent = false) {
682
+ if (this.logicallyHidden) {
683
+ return true;
684
+ }
685
+ if (!this.hasCondition() && !skipParent) {
686
+ return this.parentConditionallyHidden();
687
+ }
688
+ // Return if we are not conditionally visible (conditionallyHidden)
689
+ if (!this.conditionallyVisible()) {
690
+ return true;
691
+ }
692
+ if (skipParent) {
693
+ // Stop recurrsion for the parent checks.
694
+ return false;
695
+ }
696
+ // Check the parent.
697
+ return this.parentConditionallyHidden();
652
698
  }
653
699
  get currentForm() {
654
700
  return this._currentForm;
@@ -1818,7 +1864,7 @@ export default class Component extends Element {
1818
1864
  rebuild() {
1819
1865
  this.destroy();
1820
1866
  this.init();
1821
- this.visible = this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden;
1867
+ this.visible = this.hasCondition() ? !this.conditionallyHidden() : !this.component.hidden;
1822
1868
  return this.redraw();
1823
1869
  }
1824
1870
  /**
@@ -1916,23 +1962,12 @@ export default class Component extends Element {
1916
1962
  if (!this.builderMode & !this.previewMode && this.fieldLogic(data, row)) {
1917
1963
  this.redraw();
1918
1964
  }
1919
- // Check advanced conditions (and cache the result)
1920
- const isConditionallyHidden = this.checkConditionallyHidden(data, row) || this._parentConditionallyHidden;
1921
- let shouldClear = false;
1922
- if (isConditionallyHidden !== this._conditionallyHidden) {
1923
- this._conditionallyHidden = isConditionallyHidden;
1924
- shouldClear = true;
1925
- }
1926
1965
  // Check visibility
1927
- const visible = (this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden);
1966
+ const visible = (this.hasCondition() ? !this.conditionallyHidden() : !this.component.hidden);
1928
1967
  if (this.visible !== visible) {
1929
1968
  this.visible = visible;
1930
1969
  }
1931
- // Wait for visibility to update for nested components, so the component state is up-to-date when
1932
- // calling clearOnHide
1933
- if (shouldClear) {
1934
- this.clearOnHide();
1935
- }
1970
+ this.clearComponentOnHide();
1936
1971
  return visible;
1937
1972
  }
1938
1973
  /**
@@ -2041,9 +2076,9 @@ export default class Component extends Element {
2041
2076
  if (!_.isEqual(_.get(this.component, property), _.get(newComponent, property))) {
2042
2077
  // Advanced Logic can modify the component's hidden property; because we track conditionally hidden state
2043
2078
  // separately from the component's hidden property, and technically this Advanced Logic conditionally hides
2044
- // a component, we need to set _conditionallyHidden to the new value
2079
+ // a component, we need to set a temporary variable to the new value
2045
2080
  if (property === 'hidden') {
2046
- this._conditionallyHidden = newComponent.hidden;
2081
+ this._logicallyHidden = newComponent.hidden;
2047
2082
  }
2048
2083
  changed = true;
2049
2084
  }
@@ -2058,7 +2093,7 @@ export default class Component extends Element {
2058
2093
  component: newComponent,
2059
2094
  result,
2060
2095
  });
2061
- if (!_.isEqual(oldValue, newValue) && !(this.component.clearOnHide && this.conditionallyHidden)) {
2096
+ if (!_.isEqual(oldValue, newValue) && !this.shouldConditionallyClear()) {
2062
2097
  this.setValue(newValue);
2063
2098
  if (this.viewOnly) {
2064
2099
  this.dataValue = newValue;
@@ -2091,7 +2126,7 @@ export default class Component extends Element {
2091
2126
  component: newComponent,
2092
2127
  result,
2093
2128
  }, 'value');
2094
- if (!_.isEqual(oldValue, newValue) && !(this.component.clearOnHide && this.conditionallyHidden)) {
2129
+ if (!_.isEqual(oldValue, newValue) && !this.shouldConditionallyClear()) {
2095
2130
  this.setValue(newValue);
2096
2131
  if (this.viewOnly) {
2097
2132
  this.dataValue = newValue;
@@ -2192,17 +2227,12 @@ export default class Component extends Element {
2192
2227
  element.setAttribute('aria-invalid', invalid ? 'true' : 'false');
2193
2228
  }
2194
2229
  /**
2195
- * Clears the components data if it is conditionally hidden AND clearOnHide is set to true for this component.
2230
+ * Clear any conditionally hidden components for this component only.
2196
2231
  */
2197
- clearOnHide() {
2232
+ clearComponentOnHide() {
2198
2233
  // clearOnHide defaults to true for old forms (without the value set) so only trigger if the value is false.
2199
- if (
2200
- // if change happens inside EditGrid's row, it doesn't trigger change on the root level, so rootPristine will be true
2201
- (!this.rootPristine || this.options.server || isInsideScopingComponent(this)) &&
2202
- this.component.clearOnHide !== false &&
2203
- !this.options.readOnly &&
2204
- !this.options.showHiddenFields) {
2205
- if (this.conditionallyHidden) {
2234
+ if (this.component.clearOnHide !== false && !this.options.readOnly && !this.options.showHiddenFields) {
2235
+ if (this.shouldConditionallyClear()) {
2206
2236
  this.deleteValue();
2207
2237
  }
2208
2238
  else if (!this.hasValue() && this.shouldAddDefaultValue) {
@@ -2213,6 +2243,12 @@ export default class Component extends Element {
2213
2243
  }
2214
2244
  }
2215
2245
  }
2246
+ /**
2247
+ * Clears the components data if it is conditionally hidden AND clearOnHide is set to true for this component.
2248
+ */
2249
+ clearOnHide() {
2250
+ this.clearComponentOnHide();
2251
+ }
2216
2252
  /**
2217
2253
  * Triggers a debounced onChange event for the root component (usually Webform).
2218
2254
  * @param {...any} args - The arguments to pass to the onChange event.
@@ -2463,27 +2499,17 @@ export default class Component extends Element {
2463
2499
  * @returns {*} - The value for this component.
2464
2500
  */
2465
2501
  get dataValue() {
2466
- if (!this.key ||
2467
- (this.conditionallyHidden && this.component.clearOnHide && !this.rootPristine)) {
2468
- return this.emptyValue;
2469
- }
2470
- if (!this.hasValue() && this.shouldAddDefaultValue) {
2471
- const empty = this.component.multiple ? [] : this.emptyValue;
2472
- if (!this.rootPristine) {
2473
- this.dataValue = empty;
2474
- }
2475
- return empty;
2502
+ if (!this.key) {
2503
+ return this.component.multiple ? [] : this.emptyValue;
2476
2504
  }
2477
- return _.get(this._data, this.key);
2505
+ return _.get(this._data, this.key, this.component.multiple ? [] : this.emptyValue);
2478
2506
  }
2479
2507
  /**
2480
2508
  * Sets the static value of this component.
2481
2509
  * @param {*} value - The value to set for this component.
2482
2510
  */
2483
2511
  set dataValue(value) {
2484
- if (!this.allowData ||
2485
- !this.key ||
2486
- (this.conditionallyHidden && this.component.clearOnHide && !this.rootPristine)) {
2512
+ if (!this.allowData || !this.key) {
2487
2513
  return;
2488
2514
  }
2489
2515
  if ((value !== null) && (value !== undefined)) {
@@ -2526,13 +2552,30 @@ export default class Component extends Element {
2526
2552
  }
2527
2553
  getCustomDefaultValue(defaultValue) {
2528
2554
  if (this.component.customDefaultValue && !this.options.preview) {
2529
- defaultValue = this.evaluate(this.component.customDefaultValue, { value: '' }, 'value');
2555
+ defaultValue = this.evaluate(this.component.customDefaultValue, { value: this.dataValue }, 'value');
2530
2556
  }
2531
2557
  return defaultValue;
2532
2558
  }
2559
+ /**
2560
+ * Returns if a component has a default value set.
2561
+ * @returns {boolean} - TRUE if a default value is set.
2562
+ */
2563
+ get hasDefaultValue() {
2564
+ return this.component.customDefaultValue || (this.component.hasOwnProperty('defaultValue') &&
2565
+ (this.component.defaultValue !== null) &&
2566
+ (this.component.defaultValue !== undefined));
2567
+ }
2568
+ /**
2569
+ * Determine if we should add a default value for this component.
2570
+ * @returns {boolean} - TRUE if a default value should be set
2571
+ */
2533
2572
  get shouldAddDefaultValue() {
2534
- return !this.options.noDefaults || (this.component.defaultValue && !this.isEmpty(this.component.defaultValue)) || this.component.customDefaultValue;
2573
+ return this.pristine && this.allowData && (this.hasDefaultValue || !this.options.noDefaults);
2535
2574
  }
2575
+ /**
2576
+ * Get the default value of this component.
2577
+ * @returns {*} - The default value for this component.
2578
+ */
2536
2579
  get defaultValue() {
2537
2580
  let defaultValue = this.emptyValue;
2538
2581
  if (this.component.defaultValue) {
@@ -2802,10 +2845,8 @@ export default class Component extends Element {
2802
2845
  }
2803
2846
  // If no calculated value or
2804
2847
  // hidden and set to clearOnHide (Don't calculate a value for a hidden field set to clear when hidden)
2805
- const { clearOnHide } = this.component;
2806
- const shouldBeCleared = this.conditionallyHidden && clearOnHide;
2807
2848
  const allowOverride = _.get(this.component, 'allowCalculateOverride', false);
2808
- if (shouldBeCleared) {
2849
+ if (this.shouldConditionallyClear()) {
2809
2850
  // remove calculated value so that the value is recalculated once component becomes visible
2810
2851
  if (this.hasOwnProperty('calculatedValue') && allowOverride) {
2811
2852
  _.unset(this, 'calculatedValue');
@@ -2926,9 +2967,11 @@ export default class Component extends Element {
2926
2967
  * @param {boolean} dirty - If the component is dirty.
2927
2968
  * @param {boolean} ignoreCondition - If conditions for the component should be ignored when checking validity.
2928
2969
  * @param {*} row - Contextual row data for this component.
2970
+ * @param {*} options - Additional options for validation.
2929
2971
  * @returns {string} - The message to show when the component is invalid.
2930
2972
  */
2931
- invalidMessage(data, dirty, ignoreCondition, row) {
2973
+ invalidMessage(data, dirty, ignoreCondition, row, options = {}) {
2974
+ const { local } = options;
2932
2975
  if (!row) {
2933
2976
  row = getContextualRowData(this.component, data, this.paths);
2934
2977
  }
@@ -2948,6 +2991,7 @@ export default class Component extends Element {
2948
2991
  component: this.component,
2949
2992
  data,
2950
2993
  row,
2994
+ local,
2951
2995
  path: this.path || this.component.key,
2952
2996
  parent: this.parent?.component,
2953
2997
  paths: this.paths,
@@ -3122,6 +3166,14 @@ export default class Component extends Element {
3122
3166
  data = data || this.rootValue;
3123
3167
  flags = flags || {};
3124
3168
  row = row || this.data;
3169
+ // Some components (for legacy reasons) have calls to "checkData" in inappropriate places such
3170
+ // as setValue. Historically, this was bypassed by a series of cached states around the data model
3171
+ // which caused its own problems. We need to ensure that premium and custom components do not fall into
3172
+ // an infinite loop by only checking this component once.
3173
+ if (this.checkingData) {
3174
+ return;
3175
+ }
3176
+ this.checkingData = true;
3125
3177
  // Needs for Nextgen Rules Engine
3126
3178
  this.resetCaches();
3127
3179
  // Do not trigger refresh if change was triggered on blur event since components with Refresh on Blur have their own listeners
@@ -3135,6 +3187,8 @@ export default class Component extends Element {
3135
3187
  if (this.id !== flags.triggeredComponentId) {
3136
3188
  this.calculateComponentValue(data, flags, row);
3137
3189
  }
3190
+ // We are done checking data.
3191
+ this.checkingData = false;
3138
3192
  }
3139
3193
  checkModal(errors = [], dirty = false) {
3140
3194
  const messages = errors.filter(error => !error.fromServer);
@@ -3448,7 +3502,7 @@ export default class Component extends Element {
3448
3502
  // If component definition changed, replace it.
3449
3503
  if (!_.isEqual(this.component, newComponent)) {
3450
3504
  this.component = newComponent;
3451
- const visible = this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden;
3505
+ const visible = this.hasCondition() ? !this.conditionallyHidden() : !this.component.hidden;
3452
3506
  const disabled = this.shouldDisabled;
3453
3507
  // Change states which won't be recalculated during redrawing
3454
3508
  if (this.visible !== visible) {
@@ -76,6 +76,25 @@ export default [
76
76
  }
77
77
  ]
78
78
  },
79
+ {
80
+ name: 'hide',
81
+ trigger: {
82
+ type: 'javascript',
83
+ javascript: 'result = instance.root.options.editJson === false;'
84
+ },
85
+ actions: [
86
+ {
87
+ name: 'hide',
88
+ type: 'property',
89
+ property: {
90
+ label: 'Hidden',
91
+ value: 'hidden',
92
+ type: 'boolean'
93
+ },
94
+ state: true
95
+ }
96
+ ]
97
+ },
79
98
  {
80
99
  name: 'disabledToolTip',
81
100
  trigger: {
@@ -6,7 +6,7 @@ const EditFormUtils = {
6
6
  },
7
7
  unifyComponents(objValue, srcValue) {
8
8
  if (objValue.key && srcValue.key) {
9
- if (objValue.skipMerge || srcValue.skipMerge) {
9
+ if ((objValue.skipMerge || srcValue.skipMerge) && !objValue.ignore) {
10
10
  return false;
11
11
  }
12
12
  if (objValue.key === srcValue.key) {
@@ -24,9 +24,9 @@ export default class ListComponent extends Field {
24
24
  get dataReady() {
25
25
  // If the root submission has been set, and we are still not attached, then assume
26
26
  // that our data is ready.
27
- if (this.root &&
27
+ if ((this.root &&
28
28
  this.root.submissionSet &&
29
- !this.attached) {
29
+ !this.attached) || !this.visible) {
30
30
  return Promise.resolve();
31
31
  }
32
32
  return this.itemsLoaded;
@@ -181,7 +181,6 @@ export default class NestedComponent extends Field {
181
181
  checkData(data: any, flags: any, row: any, components: any): true | undefined;
182
182
  checkConditions(data: any, flags: any, row: any): boolean;
183
183
  clearOnHide(show: any): void;
184
- restoreComponentsContext(): void;
185
184
  /**
186
185
  * Allow components to hook into the next page trigger to perform their own logic.
187
186
  * @param {Function} next - The callback to continue to the next page.
@@ -6,6 +6,19 @@ import Components from '../../Components';
6
6
  */
7
7
  export default function (...extend) {
8
8
  return Components.baseEditForm([
9
+ {
10
+ key: 'display',
11
+ components: [
12
+ {
13
+ key: 'labelWidth',
14
+ ignore: true
15
+ },
16
+ {
17
+ key: 'labelMargin',
18
+ ignore: true
19
+ }
20
+ ]
21
+ },
9
22
  {
10
23
  key: 'data',
11
24
  ignore: true
@@ -81,18 +81,15 @@ export default class NestedComponent extends Field {
81
81
  const visibilityChanged = this._visible !== value;
82
82
  this._visible = value;
83
83
  const isVisible = this.visible;
84
- const isConditionallyHidden = this.checkConditionallyHidden();
85
84
  const forceShow = this.shouldForceShow();
86
85
  const forceHide = this.shouldForceHide();
87
86
  this.components.forEach((component) => {
88
87
  // Set the parent visibility first since we may have nested components within nested components
89
88
  // and they need to be able to determine their visibility based on the parent visibility.
90
89
  component.parentVisible = isVisible;
91
- component._parentConditionallyHidden = isConditionallyHidden;
92
90
  let visible;
93
91
  if (component.hasCondition()) {
94
- component._conditionallyHidden = component.checkConditionallyHidden() || component._parentConditionallyHidden;
95
- visible = !component.conditionallyHidden;
92
+ visible = !component.conditionallyHidden();
96
93
  }
97
94
  else {
98
95
  visible = !component.component.hidden;
@@ -373,7 +370,6 @@ export default class NestedComponent extends Field {
373
370
  data = data || this.data;
374
371
  options.parent = this;
375
372
  options.parentVisible = this.visible;
376
- options.parentConditionallyHidden = this.conditionallyHidden;
377
373
  options.root = options?.root || this.root || this;
378
374
  options.localRoot = this.localRoot;
379
375
  options.skipInit = true;
@@ -631,19 +627,8 @@ export default class NestedComponent extends Field {
631
627
  }
632
628
  clearOnHide(show) {
633
629
  super.clearOnHide(show);
634
- if (this.component.clearOnHide) {
635
- if (this.allowData && !this.hasValue() && !this.conditionallyHidden) {
636
- this.dataValue = this.defaultValue;
637
- }
638
- if (this.hasValue()) {
639
- this.restoreComponentsContext();
640
- }
641
- }
642
630
  this.getComponents().forEach(component => component.clearOnHide(show));
643
631
  }
644
- restoreComponentsContext() {
645
- this.getComponents().forEach((component) => component.data = this.dataValue);
646
- }
647
632
  /**
648
633
  * Allow components to hook into the next page trigger to perform their own logic.
649
634
  * @param {Function} next - The callback to continue to the next page.
@@ -661,7 +646,7 @@ export default class NestedComponent extends Field {
661
646
  }
662
647
  calculateValue(data, flags, row) {
663
648
  // Do not iterate into children and calculateValues if this nested component is conditionally hidden.
664
- if (this.conditionallyHidden) {
649
+ if (this.conditionallyHidden()) {
665
650
  return false;
666
651
  }
667
652
  return this.getComponents().reduce((changed, comp) => comp.calculateValue(data, flags, row) || changed, super.calculateValue(data, flags, row));
@@ -831,7 +816,7 @@ export default class NestedComponent extends Field {
831
816
  else if (value && component.hasValue(value)) {
832
817
  return component.setValue(_.get(value, component.key), flags);
833
818
  }
834
- else if ((!this.rootPristine || component.visible) && component.shouldAddDefaultValue) {
819
+ else if ((!this.rootPristine || component.visible) && (flags.resetValue || component.shouldAddDefaultValue)) {
835
820
  flags.noValidate = !flags.dirty;
836
821
  flags.resetValue = true;
837
822
  return component.setValue(component.defaultValue, flags);
@@ -841,6 +826,13 @@ export default class NestedComponent extends Field {
841
826
  if (!value) {
842
827
  return false;
843
828
  }
829
+ // If the value is equal to the empty value, then this means we need to reset the values.
830
+ if (_.isEqual(value, this.emptyValue)) {
831
+ // TO-DO: For a future major release, we need to investigate removing the need for the
832
+ // "resetValue" flag. This seems like a hack that is no longer necessary and the renderer
833
+ // may behave more deterministically without it.
834
+ flags.resetValue = true;
835
+ }
844
836
  return this.getComponents().reduce((changed, component) => {
845
837
  return this.setNestedValue(component, value, flags, changed) || changed;
846
838
  }, false);
@@ -3,11 +3,9 @@ export default class NestedDataComponent extends NestedComponent {
3
3
  hasChanged(newValue: any, oldValue: any): boolean;
4
4
  get allowData(): boolean;
5
5
  get emptyValue(): {};
6
- get shouldAddDefaultValue(): boolean;
7
6
  componentContext(): any;
8
7
  getValueAsString(value: any, options: any): string;
9
8
  getDataValueAsTable(value: any, options: any): string;
10
- everyComponent(fn: any, options?: {}): void;
11
9
  /**
12
10
  * Get the value of this component.
13
11
  * @returns {any} - Return the value of this component.
@@ -90,17 +90,6 @@ export default class NestedDataComponent extends NestedComponent {
90
90
  `);
91
91
  return result;
92
92
  }
93
- everyComponent(fn, options = {}) {
94
- if (options?.email) {
95
- if (options.fromRoot) {
96
- delete options.fromRoot;
97
- }
98
- else {
99
- return;
100
- }
101
- }
102
- return super.everyComponent(fn, options);
103
- }
104
93
  /**
105
94
  * Get the value of this component.
106
95
  * @returns {any} - Return the value of this component.
@@ -36,12 +36,21 @@ export default class AddressComponent extends ContainerComponent {
36
36
  get autocompleteMode(): boolean;
37
37
  get manualMode(): boolean;
38
38
  get manualModeEnabled(): boolean;
39
+ restoreComponentsContext(): void;
39
40
  get isMultiple(): boolean;
40
41
  set address(value: any);
41
42
  get address(): any;
42
43
  isValueInLegacyFormat(value: any): any;
43
44
  normalizeValue(value: any): any;
44
45
  get modeSwitcher(): any;
46
+ get providerOptions(): {
47
+ params: any;
48
+ url: any;
49
+ queryProperty: any;
50
+ responseProperty: any;
51
+ displayValueProperty: any;
52
+ autocompleteOptions: any;
53
+ };
45
54
  get removeValueIcon(): any;
46
55
  get searchInput(): any;
47
56
  get addRowButton(): any;
@@ -20,7 +20,6 @@ export default class AddressComponent extends ContainerComponent {
20
20
  key: 'address',
21
21
  switchToManualModeLabel: 'Can\'t find address? Switch to manual mode.',
22
22
  provider: '',
23
- providerOptions: {},
24
23
  manualModeViewString: '',
25
24
  hideLabel: false,
26
25
  disableClearIcon: false,
@@ -113,20 +112,33 @@ export default class AddressComponent extends ContainerComponent {
113
112
  NestedComponent.prototype.addComponents.call(this, this.manualMode ? this.address : {});
114
113
  }
115
114
  Field.prototype.init.call(this);
115
+ // Added for backwards compatibility
116
+ if (this.component.providerOptions) {
117
+ const { params, url, queryProperty, responseProperty, displayValueProperty } = this.component.providerOptions;
118
+ const key = params?.key;
119
+ const autocompleteOptions = params?.autocompleteOptions;
120
+ delete this.component.providerOptions;
121
+ this.component.url = url;
122
+ this.component.queryProperty = queryProperty;
123
+ this.component.responseProperty = responseProperty;
124
+ this.component.displayValueProperty = displayValueProperty;
125
+ this.component.apiKey = key;
126
+ this.component.autocompleteOptions = autocompleteOptions;
127
+ }
128
+ let provider = this.component.provider;
129
+ const providerOptions = this.providerOptions;
130
+ const map = this.component.map;
116
131
  if (!this.builderMode) {
117
- if (this.component.provider) {
118
- const { provider, providerOptions, } = this.component;
132
+ if (provider) {
119
133
  if (_.get(providerOptions, 'params.subscriptionKey')) {
120
134
  _.set(providerOptions, "params['subscription-key']", _.get(providerOptions, 'params.subscriptionKey'));
121
135
  _.unset(providerOptions, 'params.subscriptionKey');
122
136
  }
123
137
  this.provider = this.initializeProvider(provider, providerOptions);
124
138
  }
125
- else if (this.component.map) {
139
+ else if (map) {
126
140
  // Fallback to legacy version where Google Maps was the only provider.
127
- this.component.provider = GoogleAddressProvider.name;
128
- this.component.providerOptions = this.component.providerOptions || {};
129
- const { map, provider, providerOptions, } = this.component;
141
+ provider = this.component.provider = GoogleAddressProvider.name;
130
142
  const { key, region, } = map;
131
143
  if (key) {
132
144
  _.set(providerOptions, 'params.key', key);
@@ -258,6 +270,16 @@ export default class AddressComponent extends ContainerComponent {
258
270
  ? (this.refs[AddressComponent.modeSwitcherRef] || null)
259
271
  : null;
260
272
  }
273
+ get providerOptions() {
274
+ return {
275
+ params: { subscriptionKey: this.component.subscriptionKey, key: this.component.apiKey, ...this.component.params },
276
+ url: this.component.url,
277
+ queryProperty: this.component.queryProperty,
278
+ responseProperty: this.component.responseProperty,
279
+ displayValueProperty: this.component.displayValueProperty,
280
+ autocompleteOptions: this.component.autocompleteOptions
281
+ };
282
+ }
261
283
  get removeValueIcon() {
262
284
  return this.refs
263
285
  ? (this.refs[AddressComponent.removeValueIconRef] || null)
@@ -371,7 +393,8 @@ export default class AddressComponent extends ContainerComponent {
371
393
  const result = ((this.builderMode || this.manualMode) ? super.attach : Field.prototype.attach).call(this, element);
372
394
  if (!this.builderMode) {
373
395
  if (!this.provider && this.component.provider) {
374
- const { provider, providerOptions, } = this.component;
396
+ const provider = this.component.provider;
397
+ const providerOptions = this.providerOptions;
375
398
  this.provider = this.initializeProvider(provider, providerOptions);
376
399
  }
377
400
  }