final-form / final-form

🏁 Framework agnostic, high performance, subscription-based form state management

Home Page:https://final-form.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Feature request: new meta for submit prevented due to validation errors

santino opened this issue · comments

Thanks for the great library; been using this for the last week and fell literally in love with it.

I believe I'm could do with some additional metadata that could allow more fine tuning for displaying error messages, especially in combination with conditional fields.

My use case:

  1. Fields are immediately validated so we want to display field errors when field has been touched using meta.touched
  2. User can click submit button if they didn't touch all fields; at which point FinalForm would mark all fields as touched and so validation errors would be displayed out of the box
  3. At this stage we want to disable submit button until user clear all validation errors displayed; this can be achieved by using meta.submitFailed and meta.hasValidationErrors on the submit button.

So far so good; now onto the extra bit:

  • Form contains a conditional field. After submission user fixed all validation errors but decides to change value for parent field causing a re-render of conditional field. At this point FinalForm sees the conditional field as pristine; so meta.touched is false and validation error is not shown (f.i. required field).
  • Due to point 3 above my submit button is still disabled; all fields errors identified during last submit have been cleared but newly rendered conditional field, which is required, has not a filled and so contains a validation error which is not displayed given field is pristine.
  • At this stage user is stuck, cannot attempt submission anymore since the logic of "form has been submitted" and "form has validation errors" still applies; but we're not showing error which might not be obvious to user.

One way to fix this would be to add extra logic on the disabled state for submit button.
For instance I might simply decide to shift left and re-enable submit button to allow users to attempt submission another time at which stage all fields will be marked as touched naturally displaying error message for conditional field.
I could achieve this by changing my button disable rule from using meta.submitFailed and meta.hasValidationErrors to using a new property such as meta.submitPreventedValidation in combination with meta.dirtySinceLastSubmit.

In this case my logic for disabling the button due to validation errors would change
from: listening for a submit failure (which could be due to a number of reason other than validation) and checking if form has any validation error (which is true also for fields that have not been touched and so wouldn't have error messages displayed)
to: checking if form could have not actually be submitted because there were validation errors and checking if any value has changed since then (and so since last submission); which would allow me to re-enable the submit button as soon as any value is updated; but still keeping error messages for touched buttons displayed (to continue signalling user that these should be fixed anyway before attempting validation again).

Please shout if anyone has any idea to achieve this functionality with currently available meta data.
Again current logic works really well for standard forms; issues arise only when dealing with conditional fields which due to re-rendering are interpreted as pristine.

My current workaround to not get user stuck is to change field logic to display error message from meta.touched && meta.error to (meta.touched || meta.submitFailed) && meta.error.
This technically allow me to display an error message to any field that has a validation error even if it wasn't touched as long as a form submission had failed (again failure in this case could be due to a number of reasons other than just validation).

The reason why I consider this a workaround is that when my user changes the parent field value, causing a re-render for the conditional field which is then interpreted as pristine; they would see immediately an error message on this field; even if they didn't actually interact at all with it and they are planning to do it.
Effectively this means blaming users for an error they didn't even have the chance to cause; hence why shift left to me is more appropriate as it would allow user to fill the field and then attempt submission again or try to submit without filling the conditional field and so explicitly causing the validation error which at that stage would actually be their fault.

Another reason why the workaround is not great is that it pushes logic to the Field component due to a combination of circumstances mostly dictated by the Button component.
Current story is: as a Field I need to know that my button will be disabled if last submit failed and there are still validation errors; so I need to message the validation error to the user even if I am pristine.

This fails separation of concerns; the logic should live in the button only; changing the story to: as a Button I want to be disabled if last attempt to submit failed because of validation errors and user didn't change values.
Again more fine tuning could be added by also comparing meta.touched and meta.errors to make sure that all errors on fields that had been touched (so including all untouched fields before submission attempt that have been marked as touched by FinalForm as a result of the submission attempt, but still excluding pristine conditional fields) have been fixed.
This is probably an example of extreme logic incurring into extra computation with potential performance impact but the great fact is that FinalForm allows a lot of fine tuning like this; and I believe adding this bit of additional metadata further increases the fine tuning opportunities.