Skip to content

Instantly share code, notes, and snippets.

@mununki
Created December 2, 2022 06:32
Show Gist options
  • Save mununki/1e9cecfcdf9d52b22aafd517b7b33df5 to your computer and use it in GitHub Desktop.
Save mununki/1e9cecfcdf9d52b22aafd517b7b33df5 to your computer and use it in GitHub Desktop.
ReForm field array validation example
module ProfileFormFields = %lenses(
type t = {
nickname: string,
age: int,
}
)
module FormFields = %lenses(
type state = {
name: string,
email: string,
profiles: array<ProfileFormFields.t>,
}
)
module Form = ReForm.Make(FormFields)
module ReFormPresenter = {
@react.component
let make = () => {
let handleSubmit = ({state}: Form.onSubmitAPI) => {
Js.log2("submit >", state.values)
None
}
let form = Form.use(
~initialState={name: "", email: "", profiles: [{nickname: "", age: 0}]},
~onSubmit=handleSubmit,
~validationStrategy=OnDemand,
~schema={
open Form.Validation
schema([string(~min=3, Name), custom(({profiles}) => {
let errors: array<ReSchema.childFieldError> =
profiles
->Array.mapWithIndex((index, profile) =>
if profile.nickname == "" || profile.age <= 0 {
let error: ReSchema.childFieldError = {
error: "Invalid profile",
index,
name: "???",
}
Some(error)
} else {
None
}
)
->Array.keepMap(x => x)
switch errors {
| [] => Valid
| _ => NestedErrors(errors)
}
}, Profiles), email(~error="Invalid email", Email)])
},
(),
)
<div>
<div>
<div> {"Sign up"->React.string} </div>
<div>
<input
placeholder="Your name"
value={form.values.name}
onChange={ReForm.Helpers.handleChange(form.handleChange(Name))}
/>
{switch Field(Name)->form.getFieldError {
| None => React.null
| Some(message) => <div> {message->React.string} </div>
}}
</div>
<div>
<input
placeholder="Your email"
value={form.values.email}
onChange={ReForm.Helpers.handleChange(form.handleChange(Email))}
/>
{switch Field(Email)->form.getFieldError {
| None => React.null
| Some(message) => <div> {message->React.string} </div>
}}
</div>
<button onClick={_ => form.arrayPush(Profiles, {nickname: "", age: 0})}>
{React.string("Add profile")}
</button>
{form.values.profiles
->Array.mapWithIndex((index, profile) =>
<div key={index->Int.toString} className=%twc("flex flex-row")>
<input
placeholder={"Your nickname"}
value={profile.nickname}
onChange={ReForm.Helpers.handleChange(nickname =>
form.arrayUpdateByIndex(~field=Profiles, ~index, {...profile, nickname})
)}
/>
{switch Field(Profiles)->form.getNestedFieldError(index) {
| None => React.null
| Some(message) => <div> {message->React.string} </div>
}}
<input
placeholder={`Your age`}
value={profile.age->Int.toString}
onChange={ReForm.Helpers.handleChange(age => {
let age = Int.fromString(age)->Belt.Option.getWithDefault(0)
form.arrayUpdateByIndex(~field=Profiles, ~index, {...profile, age})
})}
/>
{switch Field(Profiles)->form.getNestedFieldError(index) {
| None => React.null
| Some(message) => <div> {message->React.string} </div>
}}
<button onClick={_ => form.arrayRemoveByIndex(Profiles, index)}>
{React.string("Remove")}
</button>
</div>
)
->React.array}
<div>
<button
onClick={e => {
e->ReactEvent.Mouse.preventDefault
form.submit()
}}>
{"Submit"->React.string}
</button>
</div>
</div>
</div>
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment