diff --git a/src/components/Form.tsx b/src/components/Form.tsx index 2520b3f51..5ba9b78d6 100644 --- a/src/components/Form.tsx +++ b/src/components/Form.tsx @@ -24,7 +24,7 @@ export type FormOptions = FormClass['options'] & { export type FormType = PartialExcept; export type FormSource = string | FormType; interface FormConstructor { - new ( + new( element: HTMLElement, formSource: FormSource, options: FormOptions, @@ -136,12 +136,20 @@ const onAnyEvent = ( handlers.onCancelComponent(outputArgs[0]); break; case 'onChange': - if (handlers.onChange) + if (handlers.onChange) { + let modified = outputArgs[2]; + const flags = outputArgs[1]; + // Fixed: Check if the change is from a file component and ensure modified is true + // See https://github.com/formio/react/issues/632 + if (!modified && flags?.changed?.instance?.type === 'file') { + modified = true; + } handlers.onChange( outputArgs[0], outputArgs[1], - outputArgs[2], + modified, ); + } break; case 'onCustomEvent': if (handlers.onCustomEvent) diff --git a/src/components/__tests__/FormFileChange.test.tsx b/src/components/__tests__/FormFileChange.test.tsx new file mode 100644 index 000000000..4714d5996 --- /dev/null +++ b/src/components/__tests__/FormFileChange.test.tsx @@ -0,0 +1,49 @@ + +import { render, screen, waitFor } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { Form } from '../Form'; + +const fileForm = { + display: 'form' as const, + components: [ + { + label: 'Upload File', + key: 'file', + type: 'file', + input: true, + storage: 'base64', + }, + ], +}; + +test('onChange should report modified=true when file is changed', async () => { + const handleChange = jest.fn((value, flags, modified) => { + // console.log('onChange called', { value, flags, modified }); + }); + + let formInstance: any; + render(
formInstance = instance} />); + + await waitFor(() => { + expect(screen.getByText('Upload File')).toBeInTheDocument(); + expect(formInstance).toBeDefined(); + }); + + const fileComponent = formInstance.getComponent('file'); + const fileValue = [{ + name: 'test.png', + size: 100, + type: 'image/png', + data: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==' + }]; + + // Trigger change. Currently reproduces modified=false. + fileComponent.setValue(fileValue); + + await waitFor(() => expect(handleChange).toHaveBeenCalledTimes(1)); + const args = handleChange.mock.calls[0]; + console.log('File Change Args:', { modified: args[2] }); + + // This should PASS after the fix + expect(args[2]).toBe(true); +}, 10000);