-
-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support debounce for expensive validation functions on form fields #40
Conversation
I've added a minimal async example which can be built locally with yarn && yarn build-all && open dist/index.html An example of the It reveals some issues:
@dariooddenino I'd be curious to hear your experiences with this for your problem in #37. |
Hi! Of your points, n.2 doesn't look like a real issue: debouce times are probably going to be in the range of a few hundred milliseconds most of the time. So, while this might not be optimal (e.g. not getting errors while typing), it's hardly a deal breaker. Point n.1 is obviously worse. Having a loading gif appear while typing (without anything actually happening) is bad. Another possibly-impossible idea: what if the async/debouncer status is carried by the validators and not by the field? |
Fixed! Requires one extra state modification. I think this solves n.1:
The problem is that the validators aren't able to update the state of the form component. They receive it as an argument and can transform things however they like, but they must simply return either an error or a successful validation. I thought about using the validators at first, but this would require giving them the full capability of modifying state ("set this field to validating, run validation, set field to validated"). I'd like to avoid that because:
In the end, it's not fantastic to have to stick a debounce time on the |
Well since you solved that issue I think it wouldn't be necessary anyways! Great work! I need to write that blog post before it becomes obsolete :D |
What does this pull request do?
As proposed, would close #37 by giving users the ability to debounce successive modifications to a form field's input. They choose the number of milliseconds that must elapse before the validation runs on the field.
This implementation allows you to set a debounce time directly on a field using
asyncSetValidate
orasyncModifyValidate
. You can still cause validation to run immediately if you usemodifyValidate
,setValidate
orvalidate
directly. Validation will not be debounced if you usevalidateAll
, either -- all validations are immediately triggered.I went with this implementation so that the impact on those not using async fields don't have to do anything differently. You can tell this is the case because none of the examples needed to change.
Ref
to avoid unnecessary state updatesMajor changes and caveats
You can now debounce async validation on a field when using the
ModifyValidate
query, which has been updated to (optionally) take a number of milliseconds for debouncing. This lets you selectively debounce expensive validation. This is a change in theComponent.Types
file and a corresponding implementation change inInternal.Transform
andComponent
.There are now new helpers called
asyncModifyValidate
,asyncSetValidate
, which let you assign n milliseconds to debounce the given field.Modify
,Validate
,ValidateAll
do not run with a debouncer. The existingmodifyValidate
andsetValidate
functions run as usual. This is a change in theQuery
file.There is now a new data type for result field:
FormFieldResult
. This type lets you inspect whether the field isNotValidated
,Validating
(use this to show a spinner, if you’d like),Error
, orSuccess
. The type includes instances forFunctor
,Apply
,Applicative
,Bind
, etc.; prisms to access the two constructors containing data, and helper functions liketoMaybe
andfromEither
. This is a new file atData.FormFieldResult
.Due to the new result type, the prisms for accessing a form field have been updated and renamed to
_FieldInput
,_FieldResult
, etc instead of_Input
,_Result
. This is necessary because some prisms have the same name and would cause conflicts when exported. The outer functions are unchanged, so almost all code should work as before.Users will probably have to update helper functions that operate on the
result
field because of these changes. When updating theFormless
examples I just had to update a singleshowError
helper function.The
Initialize
query is now actually used for initialization, andLoadForm
is used to load a new form remotely.How should this be manually tested?
I plan to put together an example using the new support for async fields, but it may be a while before I can get to it, so I'm opening this PR right away. I'll update with the example as soon as I can. In the meantime, if you have a project using a custom-built async solution, try replacing it!
Other Notes:
Unfortunately, this introduces even more query helpers (the
async*
variations), which is turning the query helpers file into an absolute monster. I'm not a fan, but because of the pervasive newtypes, I just don't see an ergonomic solution without these helpers.