@formio/js 5.0.0-dev.5896.56bf2bd → 5.0.0-dev.5902.bf899bf

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.
@@ -115,6 +115,13 @@ declare class Component extends Element {
115
115
  */
116
116
  parent: Component;
117
117
  _path: string;
118
+ /**
119
+ * Determines if this component is conditionally hidden. Should generally not be set outside of conditional logic pipeline.
120
+ * This is necessary because of clearOnHide behavior that only clears when conditionally hidden - we need to track
121
+ * conditionallyHidden separately from "regular" visibility.
122
+ */
123
+ _parentConditionallyHidden: any;
124
+ _conditionallyHidden: any;
118
125
  /**
119
126
  * Determines if this component is visible, or not.
120
127
  */
@@ -207,6 +214,14 @@ declare class Component extends Element {
207
214
  * @returns {boolean} - Whether the component is visible or not.
208
215
  */
209
216
  get visible(): boolean;
217
+ get conditionallyHidden(): any;
218
+ /**
219
+ * Evaluates whether the component is conditionally hidden (as opposed to intentionally hidden, e.g. via the `hidden` component schema property).
220
+ * @param {object} data - The data object to evaluate the condition against.
221
+ * @param {object} row - The row object to evaluate the condition against.
222
+ * @returns {boolean} - Whether the component is conditionally hidden.
223
+ */
224
+ checkConditionallyHidden(data?: object, row?: object): boolean;
210
225
  set currentForm(instance: any);
211
226
  get currentForm(): any;
212
227
  _currentForm: any;
@@ -345,11 +345,18 @@ class Component extends Element_1.default {
345
345
  this._path = '';
346
346
  // Needs for Nextgen Rules Engine
347
347
  this.resetCaches();
348
+ /**
349
+ * Determines if this component is conditionally hidden. Should generally not be set outside of conditional logic pipeline.
350
+ * This is necessary because of clearOnHide behavior that only clears when conditionally hidden - we need to track
351
+ * conditionallyHidden separately from "regular" visibility.
352
+ */
353
+ this._parentConditionallyHidden = this.options.hasOwnProperty('parentConditionallyHidden') ? this.options.parentConditionallyHidden : false;
354
+ this._conditionallyHidden = this.checkConditionallyHidden(null, data) || this._parentConditionallyHidden;
348
355
  /**
349
356
  * Determines if this component is visible, or not.
350
357
  */
351
358
  this._parentVisible = this.options.hasOwnProperty('parentVisible') ? this.options.parentVisible : true;
352
- this._visible = this._parentVisible && this.conditionallyVisible(null, data);
359
+ this._visible = this._parentVisible && (this.hasCondition() ? !this._conditionallyHidden : !this.component.hidden);
353
360
  this._parentDisabled = false;
354
361
  /**
355
362
  * The reference attribute name for this component
@@ -418,7 +425,7 @@ class Component extends Element_1.default {
418
425
  if (this.allowData && this.key) {
419
426
  this.options.name += `[${this.key}]`;
420
427
  // If component is visible or not set to clear on hide, set the default value.
421
- if (this.visible || !this.component.clearOnHide) {
428
+ if (!(this.conditionallyHidden && this.component.clearOnHide)) {
422
429
  if (!this.hasValue()) {
423
430
  if (this.shouldAddDefaultValue) {
424
431
  this.dataValue = this.defaultValue;
@@ -494,7 +501,8 @@ class Component extends Element_1.default {
494
501
  init() {
495
502
  var _a;
496
503
  this.disabled = this.shouldDisabled;
497
- this._visible = this.conditionallyVisible(null, null);
504
+ this._conditionallyHidden = this.checkConditionallyHidden();
505
+ this._visible = (this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden);
498
506
  if ((_a = this.component.addons) === null || _a === void 0 ? void 0 : _a.length) {
499
507
  this.component.addons.forEach((addon) => this.createAddon(addon));
500
508
  }
@@ -613,7 +621,6 @@ class Component extends Element_1.default {
613
621
  return;
614
622
  }
615
623
  this._visible = value;
616
- this.clearOnHide();
617
624
  this.redraw();
618
625
  }
619
626
  }
@@ -634,6 +641,21 @@ class Component extends Element_1.default {
634
641
  }
635
642
  return this._visible && this._parentVisible;
636
643
  }
644
+ get conditionallyHidden() {
645
+ return this._conditionallyHidden || this._parentConditionallyHidden;
646
+ }
647
+ /**
648
+ * Evaluates whether the component is conditionally hidden (as opposed to intentionally hidden, e.g. via the `hidden` component schema property).
649
+ * @param {object} data - The data object to evaluate the condition against.
650
+ * @param {object} row - The row object to evaluate the condition against.
651
+ * @returns {boolean} - Whether the component is conditionally hidden.
652
+ */
653
+ checkConditionallyHidden(data = null, row = null) {
654
+ if (!this.hasCondition()) {
655
+ return false;
656
+ }
657
+ return !this.conditionallyVisible(data, row);
658
+ }
637
659
  get currentForm() {
638
660
  return this._currentForm;
639
661
  }
@@ -1801,7 +1823,7 @@ class Component extends Element_1.default {
1801
1823
  rebuild() {
1802
1824
  this.destroy();
1803
1825
  this.init();
1804
- this.visible = this.conditionallyVisible(null, null);
1826
+ this.visible = this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden;
1805
1827
  return this.redraw();
1806
1828
  }
1807
1829
  /**
@@ -1868,8 +1890,8 @@ class Component extends Element_1.default {
1868
1890
  conditionallyVisible(data, row) {
1869
1891
  data = data || this.rootValue;
1870
1892
  row = row || this.data;
1871
- if (this.builderMode || this.previewMode || !this.hasCondition()) {
1872
- return !this.component.hidden;
1893
+ if (this.builderMode || this.previewMode) {
1894
+ return true;
1873
1895
  }
1874
1896
  data = data || (this.root ? this.root.data : {});
1875
1897
  return this.checkCondition(row, data);
@@ -1899,8 +1921,14 @@ class Component extends Element_1.default {
1899
1921
  if (!this.builderMode & !this.previewMode && this.fieldLogic(data, row)) {
1900
1922
  this.redraw();
1901
1923
  }
1902
- // Check advanced conditions
1903
- const visible = this.conditionallyVisible(data, row);
1924
+ // Check advanced conditions (and cache the result)
1925
+ const isConditionallyHidden = this.checkConditionallyHidden(data, row) || this._parentConditionallyHidden;
1926
+ if (isConditionallyHidden !== this._conditionallyHidden) {
1927
+ this._conditionallyHidden = isConditionallyHidden;
1928
+ this.clearOnHide();
1929
+ }
1930
+ // Check visibility
1931
+ const visible = (this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden);
1904
1932
  if (this.visible !== visible) {
1905
1933
  this.visible = visible;
1906
1934
  }
@@ -2010,6 +2038,12 @@ class Component extends Element_1.default {
2010
2038
  FormioUtils.setActionProperty(newComponent, action, result, row, data, this);
2011
2039
  const property = action.property.value;
2012
2040
  if (!lodash_1.default.isEqual(lodash_1.default.get(this.component, property), lodash_1.default.get(newComponent, property))) {
2041
+ // Advanced Logic can modify the component's hidden property; because we track conditionally hidden state
2042
+ // separately from the component's hidden property, and technically this Advanced Logic conditionally hides
2043
+ // a component, we need to set _conditionallyHidden to the new value
2044
+ if (property === 'hidden') {
2045
+ this._conditionallyHidden = newComponent.hidden;
2046
+ }
2013
2047
  changed = true;
2014
2048
  }
2015
2049
  break;
@@ -2023,7 +2057,7 @@ class Component extends Element_1.default {
2023
2057
  component: newComponent,
2024
2058
  result,
2025
2059
  });
2026
- if (!lodash_1.default.isEqual(oldValue, newValue) && !(this.component.clearOnHide && !this.visible)) {
2060
+ if (!lodash_1.default.isEqual(oldValue, newValue) && !(this.component.clearOnHide && this.conditionallyHidden)) {
2027
2061
  this.setValue(newValue);
2028
2062
  if (this.viewOnly) {
2029
2063
  this.dataValue = newValue;
@@ -2056,7 +2090,7 @@ class Component extends Element_1.default {
2056
2090
  component: newComponent,
2057
2091
  result,
2058
2092
  }, 'value');
2059
- if (!lodash_1.default.isEqual(oldValue, newValue) && !(this.component.clearOnHide && !this.visible)) {
2093
+ if (!lodash_1.default.isEqual(oldValue, newValue) && !(this.component.clearOnHide && this.conditionallyHidden)) {
2060
2094
  this.setValue(newValue);
2061
2095
  if (this.viewOnly) {
2062
2096
  this.dataValue = newValue;
@@ -2167,7 +2201,7 @@ class Component extends Element_1.default {
2167
2201
  this.component.clearOnHide !== false &&
2168
2202
  !this.options.readOnly &&
2169
2203
  !this.options.showHiddenFields) {
2170
- if (!this.visible) {
2204
+ if (this.conditionallyHidden) {
2171
2205
  this.deleteValue();
2172
2206
  }
2173
2207
  else if (!this.hasValue() && this.shouldAddDefaultValue) {
@@ -2426,7 +2460,7 @@ class Component extends Element_1.default {
2426
2460
  */
2427
2461
  get dataValue() {
2428
2462
  if (!this.key ||
2429
- (!this.visible && this.component.clearOnHide && !this.rootPristine)) {
2463
+ (this.conditionallyHidden && this.component.clearOnHide && !this.rootPristine)) {
2430
2464
  return this.emptyValue;
2431
2465
  }
2432
2466
  if (!this.hasValue() && this.shouldAddDefaultValue) {
@@ -2445,7 +2479,7 @@ class Component extends Element_1.default {
2445
2479
  set dataValue(value) {
2446
2480
  if (!this.allowData ||
2447
2481
  !this.key ||
2448
- (!this.visible && this.component.clearOnHide && !this.rootPristine)) {
2482
+ (this.conditionallyHidden && this.component.clearOnHide && !this.rootPristine)) {
2449
2483
  return;
2450
2484
  }
2451
2485
  if ((value !== null) && (value !== undefined)) {
@@ -2766,7 +2800,7 @@ class Component extends Element_1.default {
2766
2800
  // If no calculated value or
2767
2801
  // hidden and set to clearOnHide (Don't calculate a value for a hidden field set to clear when hidden)
2768
2802
  const { clearOnHide } = this.component;
2769
- const shouldBeCleared = !this.visible && clearOnHide;
2803
+ const shouldBeCleared = this.conditionallyHidden && clearOnHide;
2770
2804
  const allowOverride = lodash_1.default.get(this.component, 'allowCalculateOverride', false);
2771
2805
  if (shouldBeCleared) {
2772
2806
  // remove calculated value so that the value is recalculated once component becomes visible
@@ -3405,7 +3439,7 @@ class Component extends Element_1.default {
3405
3439
  // If component definition changed, replace it.
3406
3440
  if (!lodash_1.default.isEqual(this.component, newComponent)) {
3407
3441
  this.component = newComponent;
3408
- const visible = this.conditionallyVisible(null, null);
3442
+ const visible = this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden;
3409
3443
  const disabled = this.shouldDisabled;
3410
3444
  // Change states which won't be recalculated during redrawing
3411
3445
  if (this.visible !== visible) {
@@ -133,10 +133,10 @@ exports.default = [
133
133
  {
134
134
  weight: 700,
135
135
  type: 'checkbox',
136
- label: 'Clear Value When Hidden',
136
+ label: 'Omit Value From Submission Data When Conditionally Hidden',
137
137
  key: 'clearOnHide',
138
138
  defaultValue: true,
139
- tooltip: 'When a field is hidden, clear the value.',
139
+ tooltip: 'When a field is conditionally hidden, omit the value from the submission data.',
140
140
  input: true
141
141
  },
142
142
  utils_1.default.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>'),
@@ -84,17 +84,26 @@ class NestedComponent extends Field_1.default {
84
84
  const visibilityChanged = this._visible !== value;
85
85
  this._visible = value;
86
86
  const isVisible = this.visible;
87
+ const isConditionallyHidden = this.checkConditionallyHidden();
87
88
  const forceShow = this.shouldForceShow();
88
89
  const forceHide = this.shouldForceHide();
89
- this.components.forEach(component => {
90
+ this.components.forEach((component) => {
90
91
  // Set the parent visibility first since we may have nested components within nested components
91
92
  // and they need to be able to determine their visibility based on the parent visibility.
92
93
  component.parentVisible = isVisible;
93
- const conditionallyVisible = component.conditionallyVisible();
94
- if (forceShow || conditionallyVisible) {
94
+ component._parentConditionallyHidden = isConditionallyHidden;
95
+ let visible;
96
+ if (component.hasCondition()) {
97
+ component._conditionallyHidden = component.checkConditionallyHidden() || component._parentConditionallyHidden;
98
+ visible = !component.conditionallyHidden;
99
+ }
100
+ else {
101
+ visible = !component.component.hidden;
102
+ }
103
+ if (forceShow || visible) {
95
104
  component.visible = true;
96
105
  }
97
- else if (forceHide || !isVisible || !conditionallyVisible) {
106
+ else if (forceHide || !isVisible || !visible) {
98
107
  component.visible = false;
99
108
  }
100
109
  // If hiding a nested component, clear all errors below.
@@ -103,7 +112,6 @@ class NestedComponent extends Field_1.default {
103
112
  }
104
113
  });
105
114
  if (visibilityChanged) {
106
- this.clearOnHide();
107
115
  this.redraw();
108
116
  }
109
117
  }
@@ -384,6 +392,7 @@ class NestedComponent extends Field_1.default {
384
392
  data = data || this.data;
385
393
  options.parent = this;
386
394
  options.parentVisible = this.visible;
395
+ options.parentConditionallyHidden = this.conditionallyHidden;
387
396
  options.root = (options === null || options === void 0 ? void 0 : options.root) || this.root || this;
388
397
  options.localRoot = this.localRoot;
389
398
  options.skipInit = true;
@@ -642,7 +651,7 @@ class NestedComponent extends Field_1.default {
642
651
  clearOnHide(show) {
643
652
  super.clearOnHide(show);
644
653
  if (this.component.clearOnHide) {
645
- if (this.allowData && !this.hasValue() && !(this.options.server && !this.visible)) {
654
+ if (this.allowData && !this.hasValue() && !this.conditionallyHidden) {
646
655
  this.dataValue = this.defaultValue;
647
656
  }
648
657
  if (this.hasValue()) {
@@ -671,7 +680,7 @@ class NestedComponent extends Field_1.default {
671
680
  }
672
681
  calculateValue(data, flags, row) {
673
682
  // Do not iterate into children and calculateValues if this nested component is conditionally hidden.
674
- if (!this.conditionallyVisible()) {
683
+ if (this.conditionallyHidden) {
675
684
  return false;
676
685
  }
677
686
  return this.getComponents().reduce((changed, comp) => comp.calculateValue(data, flags, row) || changed, super.calculateValue(data, flags, row));
@@ -75,7 +75,7 @@ class DataMapComponent extends DataGrid_1.default {
75
75
  }
76
76
  get dataValue() {
77
77
  if (!this.key ||
78
- (!this.visible && this.component.clearOnHide)) {
78
+ (this.conditionallyHidden && this.component.clearOnHide)) {
79
79
  return this.emptyValue;
80
80
  }
81
81
  if (!this.hasValue() && this.shouldAddDefaultValue) {
@@ -1151,7 +1151,7 @@ class EditGridComponent extends NestedArrayComponent_1.default {
1151
1151
  }
1152
1152
  }
1153
1153
  const changed = this.hasChanged(value, this.dataValue);
1154
- if (this.parent && !this.options.server) {
1154
+ if (this.parent) {
1155
1155
  this.parent.checkComponentConditions();
1156
1156
  }
1157
1157
  this.dataValue = value;
@@ -1184,10 +1184,7 @@ class EditGridComponent extends NestedArrayComponent_1.default {
1184
1184
  this.editRows = this.editRows.slice(0, dataLength);
1185
1185
  this.openWhenEmpty();
1186
1186
  this.updateOnChange(flags, changed);
1187
- // do not call checkData with server option, it is called when change is triggered in updateOnChange
1188
- if (!this.options.server) {
1189
- this.checkData();
1190
- }
1187
+ this.checkData();
1191
1188
  this.changeState(changed, flags);
1192
1189
  return changed;
1193
1190
  }
@@ -421,10 +421,10 @@ class FormComponent extends Component_1.default {
421
421
  return this.subFormReady;
422
422
  }
423
423
  hideSubmitButton(component) {
424
- const isSubmitButton = (component.type === 'button') &&
425
- ((component.action === 'submit') || !component.action);
424
+ const isSubmitButton = component.type === 'button' && (component.action === 'submit' || !component.action);
426
425
  if (isSubmitButton) {
427
426
  component.hidden = true;
427
+ component.customConditional = 'show = false';
428
428
  }
429
429
  }
430
430
  /**
@@ -434,7 +434,7 @@ class FormComponent extends Component_1.default {
434
434
  */
435
435
  loadSubForm(fromAttach) {
436
436
  var _a, _b, _c, _d, _e;
437
- if (this.builderMode || this.isHidden() || (this.isSubFormLazyLoad() && !fromAttach)) {
437
+ if (this.builderMode || this.conditionallyHidden || (this.isSubFormLazyLoad() && !fromAttach)) {
438
438
  return Promise.resolve();
439
439
  }
440
440
  if (this.hasLoadedForm && !this.isRevisionChanged &&
@@ -518,7 +518,7 @@ class FormComponent extends Component_1.default {
518
518
  * @returns {*|boolean} - TRUE if the subform should be submitted, FALSE if it should not.
519
519
  */
520
520
  get shouldSubmit() {
521
- return this.subFormReady && (!this.component.hasOwnProperty('reference') || this.component.reference) && !this.isHidden();
521
+ return this.subFormReady && (!this.component.hasOwnProperty('reference') || this.component.reference) && !this.conditionallyHidden;
522
522
  }
523
523
  /**
524
524
  * Returns the data for the subform.
@@ -56,9 +56,21 @@ class HTMLComponent extends Component_1.default {
56
56
  }
57
57
  checkRefreshOn(changed) {
58
58
  super.checkRefreshOn(changed);
59
- if (!this.builderMode && this.component.refreshOnChange && this.element &&
60
- !lodash_1.default.isUndefined(changed) && ((lodash_1.default.isBoolean(changed) && changed) || !lodash_1.default.isEmpty(changed)) &&
61
- this.conditionallyVisible(this.data, this.row)) {
59
+ let visible;
60
+ if (this.hasCondition()) {
61
+ this._conditionallyHidden = this.checkConditionallyHidden();
62
+ visible = !this.conditionallyHidden;
63
+ }
64
+ else {
65
+ visible = !this.component.hidden;
66
+ }
67
+ const shouldSetContent = !this.builderMode
68
+ && this.component.refreshOnChange
69
+ && this.element
70
+ && !lodash_1.default.isUndefined(changed)
71
+ && ((lodash_1.default.isBoolean(changed) && changed) || !lodash_1.default.isEmpty(changed))
72
+ && visible;
73
+ if (shouldSetContent) {
62
74
  this.setContent(this.element, this.renderContent());
63
75
  }
64
76
  }
@@ -295,12 +295,12 @@ exports.checkSimpleConditional = checkSimpleConditional;
295
295
  */
296
296
  function getComponentActualValue(compPath, data, row) {
297
297
  let value = null;
298
- if (row) {
299
- value = (0, formUtils_1.getValue)({ data: row }, compPath);
300
- }
301
- if (data && lodash_1.default.isNil(value)) {
298
+ if (data) {
302
299
  value = (0, formUtils_1.getValue)({ data }, compPath);
303
300
  }
301
+ if (row && lodash_1.default.isNil(value)) {
302
+ value = (0, formUtils_1.getValue)({ data: row }, compPath);
303
+ }
304
304
  // FOR-400 - Fix issue where falsey values were being evaluated as show=true
305
305
  if (lodash_1.default.isNil(value) || (lodash_1.default.isObject(value) && lodash_1.default.isEmpty(value))) {
306
306
  value = '';
@@ -115,6 +115,13 @@ declare class Component extends Element {
115
115
  */
116
116
  parent: Component;
117
117
  _path: string;
118
+ /**
119
+ * Determines if this component is conditionally hidden. Should generally not be set outside of conditional logic pipeline.
120
+ * This is necessary because of clearOnHide behavior that only clears when conditionally hidden - we need to track
121
+ * conditionallyHidden separately from "regular" visibility.
122
+ */
123
+ _parentConditionallyHidden: any;
124
+ _conditionallyHidden: any;
118
125
  /**
119
126
  * Determines if this component is visible, or not.
120
127
  */
@@ -207,6 +214,14 @@ declare class Component extends Element {
207
214
  * @returns {boolean} - Whether the component is visible or not.
208
215
  */
209
216
  get visible(): boolean;
217
+ get conditionallyHidden(): any;
218
+ /**
219
+ * Evaluates whether the component is conditionally hidden (as opposed to intentionally hidden, e.g. via the `hidden` component schema property).
220
+ * @param {object} data - The data object to evaluate the condition against.
221
+ * @param {object} row - The row object to evaluate the condition against.
222
+ * @returns {boolean} - Whether the component is conditionally hidden.
223
+ */
224
+ checkConditionallyHidden(data?: object, row?: object): boolean;
210
225
  set currentForm(instance: any);
211
226
  get currentForm(): any;
212
227
  _currentForm: any;
@@ -308,11 +308,18 @@ export default class Component extends Element {
308
308
  this._path = '';
309
309
  // Needs for Nextgen Rules Engine
310
310
  this.resetCaches();
311
+ /**
312
+ * Determines if this component is conditionally hidden. Should generally not be set outside of conditional logic pipeline.
313
+ * This is necessary because of clearOnHide behavior that only clears when conditionally hidden - we need to track
314
+ * conditionallyHidden separately from "regular" visibility.
315
+ */
316
+ this._parentConditionallyHidden = this.options.hasOwnProperty('parentConditionallyHidden') ? this.options.parentConditionallyHidden : false;
317
+ this._conditionallyHidden = this.checkConditionallyHidden(null, data) || this._parentConditionallyHidden;
311
318
  /**
312
319
  * Determines if this component is visible, or not.
313
320
  */
314
321
  this._parentVisible = this.options.hasOwnProperty('parentVisible') ? this.options.parentVisible : true;
315
- this._visible = this._parentVisible && this.conditionallyVisible(null, data);
322
+ this._visible = this._parentVisible && (this.hasCondition() ? !this._conditionallyHidden : !this.component.hidden);
316
323
  this._parentDisabled = false;
317
324
  /**
318
325
  * The reference attribute name for this component
@@ -381,7 +388,7 @@ export default class Component extends Element {
381
388
  if (this.allowData && this.key) {
382
389
  this.options.name += `[${this.key}]`;
383
390
  // If component is visible or not set to clear on hide, set the default value.
384
- if (this.visible || !this.component.clearOnHide) {
391
+ if (!(this.conditionallyHidden && this.component.clearOnHide)) {
385
392
  if (!this.hasValue()) {
386
393
  if (this.shouldAddDefaultValue) {
387
394
  this.dataValue = this.defaultValue;
@@ -455,7 +462,8 @@ export default class Component extends Element {
455
462
  }
456
463
  init() {
457
464
  this.disabled = this.shouldDisabled;
458
- this._visible = this.conditionallyVisible(null, null);
465
+ this._conditionallyHidden = this.checkConditionallyHidden();
466
+ this._visible = (this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden);
459
467
  if (this.component.addons?.length) {
460
468
  this.component.addons.forEach((addon) => this.createAddon(addon));
461
469
  }
@@ -573,7 +581,6 @@ export default class Component extends Element {
573
581
  return;
574
582
  }
575
583
  this._visible = value;
576
- this.clearOnHide();
577
584
  this.redraw();
578
585
  }
579
586
  }
@@ -594,6 +601,21 @@ export default class Component extends Element {
594
601
  }
595
602
  return this._visible && this._parentVisible;
596
603
  }
604
+ get conditionallyHidden() {
605
+ return this._conditionallyHidden || this._parentConditionallyHidden;
606
+ }
607
+ /**
608
+ * Evaluates whether the component is conditionally hidden (as opposed to intentionally hidden, e.g. via the `hidden` component schema property).
609
+ * @param {object} data - The data object to evaluate the condition against.
610
+ * @param {object} row - The row object to evaluate the condition against.
611
+ * @returns {boolean} - Whether the component is conditionally hidden.
612
+ */
613
+ checkConditionallyHidden(data = null, row = null) {
614
+ if (!this.hasCondition()) {
615
+ return false;
616
+ }
617
+ return !this.conditionallyVisible(data, row);
618
+ }
597
619
  get currentForm() {
598
620
  return this._currentForm;
599
621
  }
@@ -1764,7 +1786,7 @@ export default class Component extends Element {
1764
1786
  rebuild() {
1765
1787
  this.destroy();
1766
1788
  this.init();
1767
- this.visible = this.conditionallyVisible(null, null);
1789
+ this.visible = this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden;
1768
1790
  return this.redraw();
1769
1791
  }
1770
1792
  /**
@@ -1831,8 +1853,8 @@ export default class Component extends Element {
1831
1853
  conditionallyVisible(data, row) {
1832
1854
  data = data || this.rootValue;
1833
1855
  row = row || this.data;
1834
- if (this.builderMode || this.previewMode || !this.hasCondition()) {
1835
- return !this.component.hidden;
1856
+ if (this.builderMode || this.previewMode) {
1857
+ return true;
1836
1858
  }
1837
1859
  data = data || (this.root ? this.root.data : {});
1838
1860
  return this.checkCondition(row, data);
@@ -1862,8 +1884,14 @@ export default class Component extends Element {
1862
1884
  if (!this.builderMode & !this.previewMode && this.fieldLogic(data, row)) {
1863
1885
  this.redraw();
1864
1886
  }
1865
- // Check advanced conditions
1866
- const visible = this.conditionallyVisible(data, row);
1887
+ // Check advanced conditions (and cache the result)
1888
+ const isConditionallyHidden = this.checkConditionallyHidden(data, row) || this._parentConditionallyHidden;
1889
+ if (isConditionallyHidden !== this._conditionallyHidden) {
1890
+ this._conditionallyHidden = isConditionallyHidden;
1891
+ this.clearOnHide();
1892
+ }
1893
+ // Check visibility
1894
+ const visible = (this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden);
1867
1895
  if (this.visible !== visible) {
1868
1896
  this.visible = visible;
1869
1897
  }
@@ -1973,6 +2001,12 @@ export default class Component extends Element {
1973
2001
  FormioUtils.setActionProperty(newComponent, action, result, row, data, this);
1974
2002
  const property = action.property.value;
1975
2003
  if (!_.isEqual(_.get(this.component, property), _.get(newComponent, property))) {
2004
+ // Advanced Logic can modify the component's hidden property; because we track conditionally hidden state
2005
+ // separately from the component's hidden property, and technically this Advanced Logic conditionally hides
2006
+ // a component, we need to set _conditionallyHidden to the new value
2007
+ if (property === 'hidden') {
2008
+ this._conditionallyHidden = newComponent.hidden;
2009
+ }
1976
2010
  changed = true;
1977
2011
  }
1978
2012
  break;
@@ -1986,7 +2020,7 @@ export default class Component extends Element {
1986
2020
  component: newComponent,
1987
2021
  result,
1988
2022
  });
1989
- if (!_.isEqual(oldValue, newValue) && !(this.component.clearOnHide && !this.visible)) {
2023
+ if (!_.isEqual(oldValue, newValue) && !(this.component.clearOnHide && this.conditionallyHidden)) {
1990
2024
  this.setValue(newValue);
1991
2025
  if (this.viewOnly) {
1992
2026
  this.dataValue = newValue;
@@ -2019,7 +2053,7 @@ export default class Component extends Element {
2019
2053
  component: newComponent,
2020
2054
  result,
2021
2055
  }, 'value');
2022
- if (!_.isEqual(oldValue, newValue) && !(this.component.clearOnHide && !this.visible)) {
2056
+ if (!_.isEqual(oldValue, newValue) && !(this.component.clearOnHide && this.conditionallyHidden)) {
2023
2057
  this.setValue(newValue);
2024
2058
  if (this.viewOnly) {
2025
2059
  this.dataValue = newValue;
@@ -2130,7 +2164,7 @@ export default class Component extends Element {
2130
2164
  this.component.clearOnHide !== false &&
2131
2165
  !this.options.readOnly &&
2132
2166
  !this.options.showHiddenFields) {
2133
- if (!this.visible) {
2167
+ if (this.conditionallyHidden) {
2134
2168
  this.deleteValue();
2135
2169
  }
2136
2170
  else if (!this.hasValue() && this.shouldAddDefaultValue) {
@@ -2392,7 +2426,7 @@ export default class Component extends Element {
2392
2426
  */
2393
2427
  get dataValue() {
2394
2428
  if (!this.key ||
2395
- (!this.visible && this.component.clearOnHide && !this.rootPristine)) {
2429
+ (this.conditionallyHidden && this.component.clearOnHide && !this.rootPristine)) {
2396
2430
  return this.emptyValue;
2397
2431
  }
2398
2432
  if (!this.hasValue() && this.shouldAddDefaultValue) {
@@ -2411,7 +2445,7 @@ export default class Component extends Element {
2411
2445
  set dataValue(value) {
2412
2446
  if (!this.allowData ||
2413
2447
  !this.key ||
2414
- (!this.visible && this.component.clearOnHide && !this.rootPristine)) {
2448
+ (this.conditionallyHidden && this.component.clearOnHide && !this.rootPristine)) {
2415
2449
  return;
2416
2450
  }
2417
2451
  if ((value !== null) && (value !== undefined)) {
@@ -2731,7 +2765,7 @@ export default class Component extends Element {
2731
2765
  // If no calculated value or
2732
2766
  // hidden and set to clearOnHide (Don't calculate a value for a hidden field set to clear when hidden)
2733
2767
  const { clearOnHide } = this.component;
2734
- const shouldBeCleared = !this.visible && clearOnHide;
2768
+ const shouldBeCleared = this.conditionallyHidden && clearOnHide;
2735
2769
  const allowOverride = _.get(this.component, 'allowCalculateOverride', false);
2736
2770
  if (shouldBeCleared) {
2737
2771
  // remove calculated value so that the value is recalculated once component becomes visible
@@ -3367,7 +3401,7 @@ export default class Component extends Element {
3367
3401
  // If component definition changed, replace it.
3368
3402
  if (!_.isEqual(this.component, newComponent)) {
3369
3403
  this.component = newComponent;
3370
- const visible = this.conditionallyVisible(null, null);
3404
+ const visible = this.hasCondition() ? !this.conditionallyHidden : !this.component.hidden;
3371
3405
  const disabled = this.shouldDisabled;
3372
3406
  // Change states which won't be recalculated during redrawing
3373
3407
  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>'),