diff --git a/packages/bonito-core/src/form/__tests__/form.spec.ts b/packages/bonito-core/src/form/__tests__/form.spec.ts index ff632f1c12..1a0d0f21ab 100644 --- a/packages/bonito-core/src/form/__tests__/form.spec.ts +++ b/packages/bonito-core/src/form/__tests__/form.spec.ts @@ -51,34 +51,35 @@ describe("Form tests", () => { }); test("Dynamic parameters", () => { - type HelloWorldFormValues = { - hideMessage: boolean; - message: string; - }; + const { form, hideMessageParam, messageParam } = + createDynamicParamsForm(); - const form = createForm({ - values: { - hideMessage: false, - message: "Hello world!", - }, - }); + // Test dynamic property evaluation + expect(messageParam.hidden).toBe(false); + expect(messageParam.label).toEqual("Not evaluated yet"); + form.evaluate(); + expect(messageParam.hidden).toBe(false); + expect(messageParam.label).toEqual("Visible message"); + hideMessageParam.value = true; + expect(messageParam.hidden).toBe(true); + expect(messageParam.label).toEqual("Hidden message"); + }); - const hideMessageParam = form.param("hideMessage", BooleanParameter); - const messageParam = form.param("message", StringParameter, { - label: "Not evaluated yet", - dynamic: { - hidden: (values) => values.hideMessage, - label: (values) => - values.hideMessage == true - ? "Hidden message" - : "Visible message", + test("Subform dynamic parameters", () => { + const { form, hideMessageParam, messageParam } = + createDynamicParamsForm(); + + const parentForm = createForm({ + values: { + child: {}, }, }); + parentForm.subForm("child", form); // Test dynamic property evaluation expect(messageParam.hidden).toBe(false); expect(messageParam.label).toEqual("Not evaluated yet"); - form.evaluate(); + parentForm.evaluate(); expect(messageParam.hidden).toBe(false); expect(messageParam.label).toEqual("Visible message"); hideMessageParam.value = true; @@ -761,3 +762,35 @@ class ParkParameter< return new ValidationStatus("ok"); } } + +function createDynamicParamsForm() { + type HelloWorldFormValues = { + hideMessage: boolean; + message: string; + }; + + const form = createForm({ + values: { + hideMessage: false, + message: "Hello world!", + }, + }); + + const hideMessageParam = form.param("hideMessage", BooleanParameter); + const messageParam = form.param("message", StringParameter, { + label: "Not evaluated yet", + dynamic: { + hidden: (values) => values.hideMessage, + label: (values) => + values.hideMessage == true + ? "Hidden message" + : "Visible message", + }, + }); + + return { + form, + hideMessageParam, + messageParam, + }; +} diff --git a/packages/bonito-core/src/form/internal/form-impl.ts b/packages/bonito-core/src/form/internal/form-impl.ts index 57fd44eb79..f5d0c3b36c 100644 --- a/packages/bonito-core/src/form/internal/form-impl.ts +++ b/packages/bonito-core/src/form/internal/form-impl.ts @@ -187,7 +187,16 @@ export class FormImpl implements Form { } evaluate(): boolean { - const propsChanged = this._updateDynamicProperties(this.values); + let propsChanged = false; + + for (const e of this.allEntries()) { + if (e instanceof SubForm) { + propsChanged = e.evaluate() || propsChanged; + } + } + propsChanged = + propsChanged || this._updateDynamicProperties(this.values); + if (propsChanged) { this._emitChangeEvent(this.values, this.values); } diff --git a/packages/bonito-ui/src/hooks/use-form.ts b/packages/bonito-ui/src/hooks/use-form.ts index 7d38ee5c39..bb5a5fe470 100644 --- a/packages/bonito-ui/src/hooks/use-form.ts +++ b/packages/bonito-ui/src/hooks/use-form.ts @@ -47,16 +47,11 @@ export function useForm( form.evaluate(); const changeHandler = form.on("change", (newValues, oldValues) => { - const changed = form.evaluate(); - // Don't do anything if evaluating the form resulted in - // changes, since another change event will be fired - if (!changed) { - setValues(newValues); - if (onFormChange) { - onFormChange(newValues, oldValues); - } - form.validate(); + setValues(newValues); + if (onFormChange) { + onFormChange(newValues, oldValues); } + form.validate(); }); const validationHandler = form.on("validate", (snapshot) => {