Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upSupport debounce for expensive validation functions on form fields #40
Conversation
thomashoneyman
added some commits
Nov 27, 2018
thomashoneyman
added
the
enhancement
label
Nov 27, 2018
thomashoneyman
added this to the 0.5.0 milestone
Nov 27, 2018
thomashoneyman
self-assigned this
Nov 27, 2018
thomashoneyman
added some commits
Nov 27, 2018
This comment has been minimized.
This comment has been minimized.
|
I've added a minimal async example which can be built locally with yarn && yarn build-all && open dist/index.htmlAn example of the It reveals some issues:
@dariooddenino I'd be curious to hear your experiences with this for your problem in #37. |
This comment has been minimized.
This comment has been minimized.
dariooddenino
commented
Nov 28, 2018
|
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? |
This comment has been minimized.
This comment has been minimized.
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 |
This comment has been minimized.
This comment has been minimized.
dariooddenino
commented
Nov 28, 2018
|
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 |

thomashoneyman commentedNov 27, 2018
•
edited
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
asyncSetValidateorasyncModifyValidate. You can still cause validation to run immediately if you usemodifyValidate,setValidateorvalidatedirectly. 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.
Refto avoid unnecessary state updatesMajor changes and caveats
You can now debounce async validation on a field when using the
ModifyValidatequery, 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.Typesfile and a corresponding implementation change inInternal.TransformandComponent.There are now new helpers called
asyncModifyValidate,asyncSetValidate, which let you assign n milliseconds to debounce the given field.Modify,Validate,ValidateAlldo not run with a debouncer. The existingmodifyValidateandsetValidatefunctions run as usual. This is a change in theQueryfile.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 liketoMaybeandfromEither. 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
resultfield because of these changes. When updating theFormlessexamples I just had to update a singleshowErrorhelper function.The
Initializequery is now actually used for initialization, andLoadFormis 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.