neoform
neoform copied to clipboard
Validation is out of sync with input
It seems that validation and input aren't synchronized
See also this gist
- Original demo: onBlur validation.
- onChange validation: Validation out of sync with input.
- onChange validation: Now validation in sync with input.
- onBlur/onChange validation: Validation in sync with input.
Proposed solution setTimeout(() => validate(), 0)
: perform validation at the next turn of event loop.
It would be nice to solve the out of sync issue
inside the neoform package.
It's hard to know from inside of NeoForm should we postpone validation till the next tick or not, what do you think about something like onChange(e.target.value, validate)
as a special case workaround? The value flow is async because input is controlled, i.e. we have an onChange
↔︎ value
loop using state.
Another option is to always and explicitly pass values like validate(value)
in most cases and validate(e.target.value)
in case of onChange
.
@deepsweet
Thank you for the analysis. You are right, the next tick
looks like a hack. In our opinion, the second option (to pass e.target.value
in case of onChange
) is more preferable. More over, the pending pull request #13 allows easily detect the event type change
. Below is a possible implementation of this idea, based on #13:
- Module
fieldValidation.js
. In methodvalidate
, along withname
, pass an extra propertyvalue: event.target.value
into form validation handler:
validate(event) {
if (this.props.validator) {
const type = event ? event.type : 'unknown';
const value = (event && event.target) ? event.target.value : null;
this.context.neoform.validate({ name: this.props.name, value }, type);
}
}
- Module
formValidation.js
. In methodvalidateField
perfom validation, using passed event's value only in case of thechange
type. Otherwise, validate a value from the state:
validateField({ name, value: eventValue }, type) {
const validator = this.validators[name];
const value = (type === 'change') ? eventValue : this.context.neoform.getValue(name);
validator(value, type)
.then((message) => {
// ...
This is an example of the input component, with validation of state value on blur
and event value on change
:
const MyInput = ({
value='',
onChange,
validate,
validationStatus,
validationMessage,
...props
}) => (
<span>
<input
{...props}
value={value}
onBlur={validate}
onChange={e => {
onChange(e.target.value)
if (validationStatus === false) {
validate(e)
}
}}
/>
{renderError(validationStatus, validationMessage)}
</span>
)