React Form Binding via StatedBean
# yarn
yarn add stated-bean yup stated-form-bean
yarn add @types/yup -D
# npm
npm i stated-bean yup stated-form-bean
npm i @types/yup -D
FormModel
import { StatedBean, Stated } from 'stated-bean';
import { Valid, FormModel } from 'stated-form-bean';
import * as yup from 'yup';
export interface User {
name: string;
age: number;
}
@StatedBean()
export class UserModel extends FormModel<UserModel> {
@Stated()
@Valid(
yup.object().shape({
name: yup.string().required(),
age: yup
.number()
.min(10)
.max(99)
.required(),
}),
{ validOnChange: false },
)
user: Partial<User> = { age: 15 };
setUser(u: Partial<User>) {
this.user = {
...this.user,
...u,
};
}
}
React Form
import { useStatedBean } from 'stated-bean';
import { UserModel } from './UserModel';
import * as React from 'react';
export const UserForm = () => {
const model = useStatedBean(UserModel);
const { errors } = model.getFormField('user');
const handleSubmit = React.useCallback(
async e => {
e.preventDefault();
console.log(model);
const valid = await model.validate('user');
if (valid) {
alert('valid success');
}
},
[model],
);
return (
<div>
<form>
<div>
<label>UserName:</label>
<input
type="text"
value={model.user.name || ''}
onChange={e => model.setUser({ name: e.target.value })}
/>
<span>{errors && errors.name}</span>
</div>
<div>
<label>Age:</label>
<input
type="number"
min={10}
max={99}
value={model.user.age}
onChange={e => model.setUser({ age: Number(e.target.value) })}
/>
<span>{errors && errors.age}</span>
</div>
<button type="submit" onClick={handleSubmit}>
Submit
</button>
</form>
</div>
);
};
FormValidatorInterceptor
const app = new StatedBeanApplication();
app.setInterceptors(new FormValidateInterceptor());
const App = () => {
return (
<StatedBeanProvider application={app} types={[]}>
<UserForm />
</StatedBeanProvider>
);
};