[BUG] isValid flag on submission is set wrongly when number field is added to the form
Environment
Please provide as many details as you can:
- Hosting type
- [] Form.io
- [x] Local deployment
- Version: N/A
- Formio.js version: 4.13.9
- Frontend framework: React
- Browser: Google Chrome
- Browser version: Version 95.0.4638.69 (Official Build) (64-bit)
Steps to Reproduce
-
Download the sample create-react-app project with reproducible example: formio-validation-number.zip
-
In the app main catalog, execute
npm installand thennpm startto start the web app. -
On the web app, you can see a form. By default, it renders a form (both forms' JSONs are hard-coded in
formView.jsxfile) with one text area and one checkbox. You can see that the text area control is required:

The text area has no value filled, so the whole form is invalid and shouldn't be submitted (it contains validation errors).
- Open dev tools (F12) and see that when clicking on "Form without number" button (which simply re-renders this form), the
submissionparameter ofonChangefunction hasisValidflag correctly set tofalse:

This is so far correct.
- Now click on "Form with number" button. This button does nothing more than changing the
formprop of theFormcomponent to the one with one additional control - a field of type number. When you click this button once, see what happens in the devtools console (F12) withisValidflag:

This is wrong. The isValid flag on submission object should still be false. Validation of the form is still not passing (form is still in an invalid state).
Expected behavior
When changing the form on Form component, the isValid flag on submission object passed in onChange callback function should not change. It should always reflect the actual validation status of the form.
Observed behavior
submission.isValid flag changes from false to true when only form definition is changed (number control is added).
I also noticed that it doesn't happen with all controls. If you add another text area, this problem doesn't occur.
More info
It might be related to #411 It's very important to fix that. It makes it impossible to block saving/submitting of the form when it has some validation errors, and you are using a custom submit button (not the FormIO's default one defined in form JSON as a component). It's not reliable at all and users of our application are getting frustrated with these strange validation issues.
I'm having the same sort of issue with the isValid flag. For me, the isValid flag is reporting that the form is valid on initial render, but the Form's internal state seems to contradict that state since the included Submit button is disabled still. Without access to the form's ref (#407), this makes using a custom submit button almost impossible with this library since I can't manually call the checkValidity function either.
@mm-dsibinski Did you manage to find any workaround to this isValid issue in the meantime?
Thanks!
@crcollver unfortunately no... Validation in FormIO component is totally unreliable. We've already done many "haxes" in the JSONs of the forms/submission objects for different things, because FormIO is veeery buggy, but haven't found any solution for validation issues.
For me I just went ahead and coded my own check.
// data
const { o_form, o_submission } = props; // feed your own stuff
const [construct] = React.useState( o_form ); // the formio json definition from database / etc.
const [originalSubmission] = React.useState( {data: o_submission } ); // initial form data to load.
const [canSubmit, setCanSubmit] = React.useState(true);
const [formReady, setFormReady] = React.useState(false);
const [submission, setSubmission] = React.useState({}); // value fed back from FormIO upon change.
// reactive events
const onChange = (submission) => {
setSubmission(submission);
};
const onFormReady = (instance) => {
setFormReady(true);
};
React.useEffect(() => {
if (formReady) {
let valid = submission.isValid;
if (valid) { // isValid is seemingly flawed @ initialization: https://github.com/formio/react/issues/415
valid = checkValidity(submission);
}
setCanSubmit(valid);
}
}, [submission]);
// if any required field is blank, obviously the form isn't really valid. Supplemental fix for an issue #415.
const checkValidity = (data, _default) => {
let valid = _default;
for (let comp of construct.components) {
if (comp.validate && comp.validate.required) {
var checkForAnythingAtAll = data[comp.key];
if (!checkForAnythingAtAll || checkForAnythingAtAll === '') {
valid = false;
break;
}
}
}
return valid;
};
// display
return (
<React.Fragment>
<Form
form={construct}
submission={originalSubmission}
formReady={onFormReady}
onChange={onChange}
/>
<Button disabled={ !canSubmit }>
Weee!
</Button>
</React.Fragment>
);
React renders the form, then it triggers formReady, then it triggers onChange with initial empty(or default or provisioned) values for the form.
So it's 3 render cycles. 1st cycle: isValid=false. Same for 2nd. 3rd cycle, isValid=true.
1st cycle is obviously the initial render. 2nd is caused by the form ready listener.
3rd is some sort of internal onChange callback occurring, perhaps due to the 2nd render cycle serving up props to the <Form> (even though they are unchanged from 1st).
In the OP's post above, perhaps you do not have 3 render cycles. The workaround still applies. Just explaining the internal flow here.
So idea in above is simply to override the isValid boolean with our own logic for the "initial" (3rd) render cycle.
You could supplement your own logic for checkValidity, if you don't have any required fields..
After that, the onChange event properly sends us isValid without any custom code needed (it starts working again).
Without a ref, perhaps we need some utility functions (execute: validate(data) ) exposed via using hooks to comply with react. something like...
import {Form, useFormIO} from '@formio/react';
const {utility} = useFormIO();
.... code from above ...
valid = utility.Validate(submission);
Now that would be a proper workaround until a deep dive is possible by author and staff. Mine above is janky but it does the job for me.
Easier said than done I know. Just a suggestion. If I had time I'd dig into it and help, but i have none. I shouldn't even be here right now typing this.
We're currently addressing a backlog of GitHub issues. Closing this thread as it is outdated. Please re-open if it is still relevant. Thank you for your contribution!