やりたいこと
Formの項目の選択状態により必須・非必須を変えたい。
例えばペットを飼っていれば、ペットの名前を必須としたい。飼ってなければ必須にはしない。
そもそもInputを消せって話はあるが、裏で値が必須に定義されているとバリデーションを通過できないでエラーになるので、バリデーションをいじる意味はある。
やり方
Yup.lazy()関数というのがあり、値の状況で条件分岐とかできる仕組みを利用すればできるみたい。
validationSchema={Yup.lazy(values => {
if (values.pet === 'noPet') {
return Yup.object().shape({
email: Yup.string().required(),
pet: Yup.string().required(),
});
} else {
return Yup.object().shape({
email: Yup.string().required(),
pet: Yup.string().required(),
petName: Yup.string().required(),
});
}
})}
実装
formikとかいろいろわかってる想定。
create-react-app formik-test
cd formik-test
npm install --save bootstrap reactstrap formik yup
とか。index.jsでbootstrap.min.css読み込んだりする。
で、サンプルを書く。
App.js
import React from 'react';
import './App.css';
import { Form, FormGroup, Label, Input, Button, FormFeedback } from 'reactstrap';
import { Formik } from 'formik';
import * as Yup from 'yup';
class App extends React.Component {
handleOnSubmit = (values) => {
alert(JSON.stringify(values));
}
render() {
return (
<div className="container">
<h3 className="my-5">動的バリデーションテスト</h3>
<Formik
initialValues={{ email: '', pet: '', petName: '' }}
onSubmit={(values) => this.handleOnSubmit(values)}
validationSchema={Yup.lazy(values => {
if (values.pet === 'noPet') {
return Yup.object().shape({
email: Yup.string().required(),
pet: Yup.string().required(),
});
} else {
return Yup.object().shape({
email: Yup.string().required(),
pet: Yup.string().required(),
petName: Yup.string().required(),
});
}
})}
>
{
({ handleSubmit, handleChange, handleBlur, values, errors, touched, setFieldValue }) => (
<Form>
<FormGroup>
<Label>Email</Label>
<Input
type="email"
name="email"
value={values.email}
onChange={handleChange}
onBlur={handleBlur}
invalid={Boolean(errors.email && touched.email)}
/>
<FormFeedback>
{errors.email}
</FormFeedback>
</FormGroup>
<FormGroup>
<legend className="col-form-label">犬を飼っていますか?</legend>
<FormGroup inline check>
<Label check>
飼っている:
<Input
type="radio"
name="pet"
value="havePet"
onChange={handleChange}
/>
</Label>
</FormGroup>
<FormGroup inline check>
<Label check>
飼っていない:
<Input
type="radio"
name="pet"
value="noPet"
onChange={handleChange}
/>
</Label>
</FormGroup>
<span className="text-danger small">{touched.pet && errors.pet ? errors.pet : null}</span>
</FormGroup>
<FormGroup>
<Label>ペットの名前</Label>
<Input
type="text"
name="petName"
value={values.petName}
onChange={handleChange}
onBlur={handleBlur}
invalid={Boolean(errors.petName && touched.petName)}
/>
<FormFeedback>
{errors.petName}
</FormFeedback>
</FormGroup>
<FormGroup></FormGroup>
<Button onClick={handleSubmit}>申し込む</Button>
</Form>
)
}
</Formik>
</div>
);
}
}
export default App;
便利。