Skip to content

Commit

Permalink
Merge pull request #174 from formio/FIO-9189-fixed-conditions-with-se…
Browse files Browse the repository at this point in the history
…lect-resource

FIO-9189: fixed an issue where data is lost after submission for the conditionally visible field when the condition is based on select resource
  • Loading branch information
brendanbond authored Oct 18, 2024
2 parents 225746c + 9a3c6ec commit bef8aa0
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 5 deletions.
130 changes: 130 additions & 0 deletions src/process/__tests__/process.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3910,6 +3910,136 @@ describe('Process Tests', function () {
});
});

it('Should not unset value of the conditionally visible component when condtiion is based on select resource with save as ref', function () {
const form = {
_id: '670f638c362eca5264b5dc94',
title: 'test fire',
name: 'testFire',
path: 'testfire',
type: 'form',
display: 'form',
owner: '637b2e6b48c1227e60b1f910',
components: [
{
label: 'Select',
widget: 'choicesjs',
tableView: true,
dataSrc: 'resource',
data: {
resource: '670f62df362eca5264b5d812',
},
template: '<span>{{ item.data.textField }}</span>',
validateWhenHidden: false,
key: 'select',
type: 'select',
input: true,
noRefreshOnScroll: false,
addResource: false,
reference: true,
},
{
label: 'Text Field Show on test1',
applyMaskOn: 'change',
tableView: true,
validateWhenHidden: false,
key: 'textFieldShowOnTest1',
conditional: {
show: true,
conjunction: 'all',
conditions: [
{
component: 'select',
operator: 'isEqual',
value: {
data: {
textField: 'test1',
},
},
},
],
},
type: 'textfield',
input: true,
},
{
label: 'Text Area Not Show on test1',
applyMaskOn: 'change',
autoExpand: false,
tableView: true,
validateWhenHidden: false,
key: 'textAreaNotShowOnTest1',
conditional: {
show: true,
conjunction: 'all',
conditions: [
{
component: 'select',
operator: 'isNotEqual',
value: {
data: {
textField: 'test1',
},
},
},
],
},
type: 'textarea',
input: true,
},
{
type: 'button',
label: 'Submit',
key: 'submit',
disableOnInvalid: true,
input: true,
tableView: false,
},
],
project: '66f66c655879bf08113cf465',
};

const submission = {
data: {
select: {
_id: '670f62e5362eca5264b5daf9',
form: '670f62df362eca5264b5d812',
owner: '637b2e6b48c1227e60b1f910',
data: { textField: 'test1', submit: true },
project: '66f66c655879bf08113cf465',
state: 'submitted',
created: '2024-10-16T06:53:25.603Z',
modified: '2024-10-16T06:53:25.604Z',
},
submit: true,
textFieldShowOnTest1: 'test',
},
};

const errors: any = [];
const conditionals: any = [];
const context = {
form,
submission,
data: submission.data,
components: form.components,
processors: ProcessTargets.submission,
scope: { errors, conditionals },
config: {
server: true,
},
};

processSync(context);
submission.data = context.data;
context.processors = ProcessTargets.evaluator;
processSync(context);
console.log(111, context.data, context.scope.conditionals);
assert.deepEqual(context.data.textFieldShowOnTest1, 'test');
context.scope.conditionals.forEach((cond: any) => {
assert.equal(cond.conditionallyHidden, cond.path !== 'textFieldShowOnTest1');
});
});

describe('Required component validation in nested form in DataGrid/EditGrid', function () {
const nestedForm = {
key: 'form',
Expand Down
64 changes: 64 additions & 0 deletions src/utils/formUtil/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
trim,
isBoolean,
omit,
every,
} from 'lodash';
import { compare, applyPatch } from 'fast-json-patch';

Expand All @@ -38,6 +39,7 @@ import {
JSONConditional,
SimpleConditional,
AddressComponent,
SelectComponent,
} from 'types';
import { Evaluator } from '../Evaluator';
import { eachComponent } from './eachComponent';
Expand Down Expand Up @@ -1010,4 +1012,66 @@ export function isComponentDataEmpty(
return isValueEmpty(component, value);
}

/**
* Returns the template keys inside the template code.
* @param {string} template - The template to get the keys from.
* @returns {Array<string>} - The keys inside the template.
*/
export function getItemTemplateKeys(template: any) {
const templateKeys: Array<string> = [];
if (!template) {
return templateKeys;
}
const keys = template.match(/({{\s*(.*?)\s*}})/g);

if (keys) {
keys.forEach((key: string) => {
const propKey = key.match(/{{\s*item\.(.*?)\s*}}/);
if (propKey && propKey.length > 1) {
templateKeys.push(propKey[1]);
}
});
}

return templateKeys;
}

/**
* Returns if the component is a select resource with an object for its value.
* @param {Component} comp - The component to check.
* @returns {boolean} - TRUE if the component is a select resource with an object for its value; FALSE otherwise.
*/
export function isSelectResourceWithObjectValue(comp: any = {}) {
const { reference, dataSrc, valueProperty } = comp;
return reference || (dataSrc === 'resource' && (!valueProperty || valueProperty === 'data'));
}

/**
* Compares real select resource value with expected value in condition.
* @param {any} value - current value of selectcomponent.
* @param {any} comparedValue - expocted value of select component.
* @param {SelectComponent} conditionComponent - select component on which the condtion is based.
* @returns {boolean} - TRUE if the select component current value is equal to the expected value; FALSE otherwise.
*/
export function compareSelectResourceWithObjectTypeValues(
value: any,
comparedValue: any,
conditionComponent: SelectComponent,
) {
if (!value || !isPlainObject(value)) {
return false;
}

const { template, valueProperty } = conditionComponent;

if (valueProperty === 'data') {
value = { data: value };
comparedValue = { data: comparedValue };
}

return every(getItemTemplateKeys(template) || [], (k) =>
isEqual(get(value, k), get(comparedValue, k)),
);
}

export { eachComponent, eachComponentData, eachComponentAsync, eachComponentDataAsync };
12 changes: 12 additions & 0 deletions src/utils/operators/IsEqualTo.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import {
compareSelectResourceWithObjectTypeValues,
isSelectResourceWithObjectValue,
} from 'utils/formUtil';
import ConditionOperator from './ConditionOperator';
import { isString, isEqual, get } from 'lodash';

Expand Down Expand Up @@ -29,6 +33,14 @@ export default class IsEqualTo extends ConditionOperator {
}
}

if (
conditionComponent &&
isSelectResourceWithObjectValue(conditionComponent) &&
conditionComponent.template
) {
return compareSelectResourceWithObjectTypeValues(value, comparedValue, conditionComponent);
}

return isEqual(value, comparedValue);
}
}
9 changes: 4 additions & 5 deletions src/utils/operators/IsNotEqualTo.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import ConditionOperator from './ConditionOperator';
import { isEqual } from 'lodash';
import IsEqualTo from './IsEqualTo';

export default class IsNotEqualTo extends ConditionOperator {
export default class IsNotEqualTo extends IsEqualTo {
static get operatorKey() {
return 'isNotEqual';
}
Expand All @@ -10,7 +9,7 @@ export default class IsNotEqualTo extends ConditionOperator {
return 'Is Not Equal To';
}

execute({ value, comparedValue }) {
return !isEqual(value, comparedValue);
execute(options) {
return !super.execute(options);
}
}

0 comments on commit bef8aa0

Please sign in to comment.