From 59d7da6f5b67522acefef4aa3bd9960a64decc50 Mon Sep 17 00:00:00 2001 From: Valentin Serra Date: Wed, 10 Apr 2024 20:21:32 +0200 Subject: [PATCH] chore: cleanup logic using `formFieldInstanceRegistry` Related to #1142 --- packages/form-js-viewer/src/Form.js | 111 ++++-------------- .../expressionLanguage/ConditionChecker.js | 7 +- 2 files changed, 28 insertions(+), 90 deletions(-) diff --git a/packages/form-js-viewer/src/Form.js b/packages/form-js-viewer/src/Form.js index 5fcaae12f..1fe2a46ed 100644 --- a/packages/form-js-viewer/src/Form.js +++ b/packages/form-js-viewer/src/Form.js @@ -204,64 +204,38 @@ export class Form { * @returns {Errors} */ validate() { - const formFields = this.get('formFields'), - formFieldRegistry = this.get('formFieldRegistry'), - pathRegistry = this.get('pathRegistry'), + const formFieldRegistry = this.get('formFieldRegistry'), + formFieldInstanceRegistry = this.get('formFieldInstanceRegistry'), validator = this.get('validator'); const { data } = this._getState(); + const errors = {}; - const getErrorPath = (field, indexes) => [ field.id, ...Object.values(indexes || {}) ]; + const getErrorPath = (id, indexes) => [ id, ...Object.values(indexes || {}) ]; - function validateFieldRecursively(errors, field, indexes) { - const { disabled, type, isRepeating } = field; - const { config: fieldConfig } = formFields.get(type); + formFieldInstanceRegistry.getAllKeyed().forEach(({ id, valuePath, indexes }) => { + + const field = formFieldRegistry.get(id); // (1) Skip disabled fields - if (disabled) { + if (field.disabled) { return; } // (2) Validate the field - const valuePath = pathRegistry.getValuePath(field, { indexes }); - const valueData = get(data, valuePath); - const fieldErrors = validator.validateField(field, valueData); + const value = get(data, valuePath); + const fieldErrors = validator.validateField(field, value); if (fieldErrors.length) { - set(errors, getErrorPath(field, indexes), fieldErrors); - } - - // (3) Process parents - if (!Array.isArray(field.components)) { - return; + set(errors, getErrorPath(field.id, indexes), fieldErrors); } - // (4a) Recurse repeatable parents both across the indexes of repetition and the children - if (fieldConfig.repeatable && isRepeating) { - - if (!Array.isArray(valueData)) { - return; - } - - valueData.forEach((_, index) => { - field.components.forEach((component) => { - validateFieldRecursively(errors, component, { ...indexes, [field.id]: index }); - }); - }); - - return; - } - - // (4b) Recurse non-repeatable parents only across the children - field.components.forEach((component) => validateFieldRecursively(errors, component, indexes)); - } + }); - const workingErrors = {}; - validateFieldRecursively(workingErrors, formFieldRegistry.getForm()); - const filteredErrors = this._applyConditions(workingErrors, data, { getFilterPath: getErrorPath, leafNodeDeletionOnly: true }); - this._setState({ errors: filteredErrors }); + this._setState({ errors }); - return filteredErrors; + // @ts-ignore + return errors; } /** @@ -442,59 +416,24 @@ export class Form { */ _getSubmitData() { const formFieldRegistry = this.get('formFieldRegistry'); - const formFields = this.get('formFields'); - const pathRegistry = this.get('pathRegistry'); + const formFieldInstanceRegistry = this.get('formFieldInstanceRegistry'); const formData = this._getState().data; - function collectSubmitDataRecursively(submitData, formField, indexes) { - const { disabled, type } = formField; - const { config: fieldConfig } = formFields.get(type); + const submitData = {}; - // (1) Process keyed fields - if (!disabled && fieldConfig.keyed) { - const valuePath = pathRegistry.getValuePath(formField, { indexes }); - const value = get(formData, valuePath); - set(submitData, valuePath, value); - } - - // (2) Process parents - if (!Array.isArray(formField.components)) { - return; - } - - // (3a) Recurse repeatable parents both across the indexes of repetition and the children - if (fieldConfig.repeatable && formField.isRepeating) { - - const valueData = get(formData, pathRegistry.getValuePath(formField, { indexes })); - - if (!Array.isArray(valueData)) { - return; - } - - valueData.forEach((_, index) => { - formField.components.forEach((component) => { - collectSubmitDataRecursively(submitData, component, { ...indexes, [formField.id]: index }); - }); - }); + formFieldInstanceRegistry.getAllKeyed().forEach((formFieldInstance) => { + const { id, valuePath } = formFieldInstance; + const { disabled } = formFieldRegistry.get(id); + if (disabled) { return; } - // (3b) Recurse non-repeatable parents only across the children - formField.components.forEach((component) => collectSubmitDataRecursively(submitData, component, indexes)); - } - - const workingSubmitData = {}; - collectSubmitDataRecursively(workingSubmitData, formFieldRegistry.getForm(), {}); - return this._applyConditions(workingSubmitData, formData); - } + const value = get(formData, valuePath); + set(submitData, valuePath, value); + }); - /** - * @internal - */ - _applyConditions(toFilter, data, options = {}) { - const conditionChecker = this.get('conditionChecker'); - return conditionChecker.applyConditions(toFilter, data, options); + return submitData; } /** diff --git a/packages/form-js-viewer/src/features/expressionLanguage/ConditionChecker.js b/packages/form-js-viewer/src/features/expressionLanguage/ConditionChecker.js index e5f89281d..9b8482e89 100644 --- a/packages/form-js-viewer/src/features/expressionLanguage/ConditionChecker.js +++ b/packages/form-js-viewer/src/features/expressionLanguage/ConditionChecker.js @@ -28,8 +28,7 @@ export class ConditionChecker { const workingData = clone(data); const { - getFilterPath = (field, indexes) => this._pathRegistry.getValuePath(field, { indexes }), - leafNodeDeletionOnly = false + getFilterPath = (field, indexes) => this._pathRegistry.getValuePath(field, { indexes }) } = options; const _applyConditionsWithinScope = (rootField, scopeContext, startHidden = false) => { @@ -60,7 +59,7 @@ export class ConditionChecker { context.isHidden = startHidden || context.isHidden || (conditional && this._checkHideCondition(conditional, localExpressionContext)); // if a field is repeatable and visible, we need to implement custom recursion on its children - if (isRepeatable && (!context.isHidden || leafNodeDeletionOnly)) { + if (isRepeatable && (!context.isHidden)) { // prevent the regular recursion behavior of executeRecursivelyOnFields context.preventRecursion = true; @@ -93,7 +92,7 @@ export class ConditionChecker { } // if we have a hidden repeatable field, and the data structure allows, we clear it directly at the root and stop recursion - if (context.isHidden && !leafNodeDeletionOnly && isRepeatable) { + if (context.isHidden && isRepeatable) { context.preventRecursion = true; this._cleanlyClearDataAtPath(getFilterPath(field, indexes), workingData); }