kaliberjs / forms Goto Github PK
View Code? Open in Web Editor NEWForms for React
License: MIT License
Forms for React
License: MIT License
Removing an array item through the helper method returned by useArrayFormField
can lead to duplicate field names.
This happens when:
Both child fields will now have the name form1.arrayfield[1]
Is it possible to show a validation error of a checkbox on blur?
See the following test case:
import { useBooleanFormField, useForm } from '@kaliber/forms'
function needsToBeChecked(x) {
return x !== true && { id: 'needsToBeChecked' }
}
export function Form() {
const { form: { fields }, submit } = useForm({
initialValues: { tos: false },
fields: { tos: needsToBeChecked },
onSubmit: x => { console.log(x) },
})
return (
<form onSubmit={submit}>
<FormCheckbox label='I agree with the Terms of Service' field={fields.tos} />
<button type='submit'>Submit</button>
</form>
)
}
function FormCheckbox({ label, field }) {
const { name, state, eventHandlers } = useBooleanFormField(field)
const { showError, error, value } = state
console.log(showError, error)
return (
<>
<div>
<label htmlFor={name}>{label}</label>
<input id={name} type='checkbox' checked={value || false} {...{ name }} {...eventHandlers} />
</div>
{showError && <p>{error.id}</p>}
</>
)
}
I would expect the error to be shown as soon as we uncheck the checkbox. However,showError
is always false
until we submit the form.
I try to make a form with a required checkbox, for example 'I agree with the terms of service'. See the reduced test case below:
import { useBooleanFormField, useForm } from '@kaliber/forms'
import { required } from '@kaliber/forms/validation'
export function Form() {
const { form: { fields }, submit } = useForm({
initialValues: { tos: false },
fields: { tos: required },
onSubmit: x => { console.log(x) },
})
return (
<form onSubmit={submit}>
<FormCheckbox label='I agree with the Terms of Service' field={fields.tos} />
<button type='submit'>Submit</button>
</form>
)
}
function FormCheckbox({ label, field }) {
const { name, state, eventHandlers } = useBooleanFormField(field)
const { showError, error, value } = state
console.log(showError, error)
return (
<>
<div>
<label htmlFor={name}>{label}</label>
<input id={name} type='checkbox' checked={value || false} {...{ name }} {...eventHandlers} />
</div>
{showError && <p>{error.id}</p>}
</>
)
}
However this will not work, because the required
validation function explicitly allows false
as a value. Meaning that there will never be an error
.
We could solve this by writing our own validation function:
function needsToBeChecked(x) {
return x !== true && { id: 'needsToBeChecked' }
}
export function Form() {
const { form: { fields }, submit } = useForm({
initialValues: { tos: false },
fields: { tos: needsToBeChecked },
onSubmit: x => { console.log(x) },
})
...
Is this the correct way to deal with this?
Say I want to do something effectful with the formState, every time it changes (e.g. store the values in localStorage, so the form can be restored on a reload). What would be the best way to do this?
The initial thought may be to use useFormFieldValue(form)
, but this will of-course re-render the whole form onChange (which is what this library explicitly wants to prevent.
Right now, we made a separate component, which uses this hook and calls a callback prop whenever the value changes. Maybe it would make sense to add an onChange
property to the useForm
config?
Example:
const { form: { fields }, submit } = useForm({
initialValues: {}
fields: {},
// handle form change
onChange: handleChange,
// handle form submit
onSubmit: handleSubmit,
})
It would be nice to have a validation rule (and accompanying example) for a checkbox group, with a required value.
For example:
export const number = x => Number(x) !== x && error('number')
If x
is empty it will report a number
error. This makes optional
number fields impossible.
Would be nicer to use input type="email"
I'm running into problems using the FormFieldValid component with the following setup:
function NewsletterForm({ form, formSubmitting, onSubmit }) {
const { fields } = form
return (
<form {...{ onSubmit }}>
<Fields {...{ fields }} />
<FormFieldValid field={form} render={valid => (
<Button
type="submit"
disabled={formSubmitting || !valid}
loading={formSubmitting}
>
Meld je aan
</Button>
)} />
</form>
)
}
In the code changes in formSubmitting are never picked up, because the render result is memoized based on the validity.
All fixes I could think of have some kind of drawback:
export function FormFieldValid({ field, props = [], render }) {
const { invalid } = useFormFieldSnapshot(field)
return React.useMemo(() => render(!invalid, ...props) || null, [invalid, ...props])
}
Seems unelegant. Might be difficult if the render component return a big portion of form which uses a lot of props.
export function FormFieldValid({ field, render }) {
const { invalid } = useFormFieldSnapshot(field)
return React.useMemo(() => render(!invalid) || null, [invalid, render])
}
I think this would make it impossible to render the whole form in one place, because the useCallback cannot be done inline.
@EECOLOR What do you think?
Line 17 in b937d87
FormFieldValid
is now implemented with useSnapshot
which means it will render on keystrokes. We could add another hook that prevents these unneeded renders, something like this:
function useFormFieldInvalid(field) {
const [formFieldInvalid, setFormFieldInvalid] = React.useState(() => snapshot.get(field).invalid)
React.useEffect(
() => {
setFormFieldInvalid(snapshot.get(field).invalid)
return snapshot.subscribe(field, x => setFormFieldInvalid(x.invalid))
},
[field]
)
return formFieldInvalid
}
When using two or more forms on the same page in PHP, I'm getting the following message:
Warning: Prop `id` did not match. Server: "form1.email" Client: "form2.email"
in input (created by FormFieldText)
in div (created by FormFieldText)
in FormFieldText (created by EmailForm)
in form (created by EmailForm)
in EmailForm (created by NewsletterFormApp)
in div (created by NewsletterFormApp)
in NewsletterFormApp
[DOM] Found 2 elements with non-unique id #form1.email:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.