react
react copied to clipboard
[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 install
and thennpm start
to 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.jsx
file) 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
submission
parameter ofonChange
function hasisValid
flag correctly set tofalse
:
This is so far correct.
- Now click on "Form with number" button. This button does nothing more than changing the
form
prop of theForm
component 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) withisValid
flag:
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!