1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Chakra UI Checkbox 少なくとも1つを選択するバリデーション設定の仕方

Posted at

はじめに

Checkboxのどれか1つでも選択することを必須とするバリデーションの設定に苦慮したため、そちらの解決方法を共有させていただきます。


このようにCheckboxにrequired={true}を記述していました。これだと全ての項目にrequiredが付与されてしまい、全て選択するが必須になってしまいます。

.Register.tsx

import { Box, Button, Card, CardBody, CardHeader, Checkbox, CheckboxGroup, FormLabel, Heading, Input, Radio, RadioGroup, Stack, Text, Textarea, useFormErrorStyles } from "@chakra-ui/react"
import { Controller, useForm } from "react-hook-form";

import { useSkills } from "../hooks/useSkills";
import { UserParams } from "../domain/users";

export const Register = () => {
  const { register, handleSubmit, control, formState: { errors } } = useForm<UserParams>();

  const { skillsData } = useSkills();


  return (
    <div>
      <Box display="flex" justifyContent="center" alignItems="center" height="100vh" bg="#e4e4e7">
      <Card pl={5} pr={5}>
        <CardHeader textAlign="center">
          <Heading size='lg'>新規名刺登録</Heading>
        </CardHeader>
        <Text ml={6} fontSize= "13px" as="span" color="#CC6666">* は必須項目です</Text>
        <Stack>
          <CardBody>
            <Box textAlign="center">
              <form onSubmit={handleSubmit((data) => {
                console.log("dataの中身", data);
              })}>

                 {/* ユーザーID */}
                <FormLabel fontWeight={"bold"}>ユーザーID <Text as="span" color="#CC6666">*</Text></FormLabel>
                  <Input type="text" placeholder="ユーザーIDを入力してください" {...register("user_id", { required: true})} />
                    <Box textAlign="left">{errors.user_id && <Text as="span" fontSize="14px" color="red">入力必須です</Text>}</Box>
                
                {/* 名前 */}
                <FormLabel fontWeight={"bold"} mt={2}>名前 <Text as="span" color="#CC6666">*</Text></FormLabel>
                  <Input type="text" placeholder="名前を入力してください" {...register("name", { required: true})} />
                    <Box textAlign="left">{errors.name && <Text as="span" fontSize= "14px" color="red">入力必須です</Text>}</Box>
                
                {/* 自己紹介 */}
                <FormLabel fontWeight={"bold"} mt={2}>自己紹介 <Text as="span" color="#CC6666">*</Text></FormLabel>
                  <Textarea placeholder="自己紹介文を入力してください。HTMLタグも使えます" {...register("description", { required: true})} />
                    <Box textAlign="left">{errors.description && <Text as="span" fontSize= "14px" color="red">入力必須です</Text>}</Box>
                
                {/* 好きな技術 */}
                <FormLabel fontWeight={"bold"} mt={2}>好きな技術 <Text as="span" color="#CC6666">*</Text></FormLabel>
                <Controller // controller使用しないと制御できない
                  name="skills" // どのフィールドを管理するか指定 フォーム送信時にここで指定した値がオブジェクトのキーとして扱われる
                  defaultValue={[]} // デフォルトの値
                  control={control} // usFormから取得したcontrolを渡している。これによりコンポーネントがフォームの状態管理に接続される
                  render={({ field }) => { // fieldという決まった名称のオブジェクト
                    return (
                      <CheckboxGroup value={field.value} onChange={(values) => field.onChange(values.map(Number))}> {/* Chakra uiのGroup Hook Formのデフォルトの値文字列から数値に変換が必要*/}

                        {skillsData.map((skill) => (
                          <Checkbox ml={1} mr={1} key={skill.id} value={skill.id} required={true}>{skill.name}</Checkbox>
                        ))}

                      </CheckboxGroup>
                    );
                  }}
                />

                 {/* GitHub ID */}
                <FormLabel mt={2}>GitHub ID</FormLabel>
                <Input placeholder="IDを入力してください" {...register("github_id")} />

                {/* Qiita ID */}
                <FormLabel mt={2}>Qiita ID</FormLabel>
                <Input placeholder="IDを入力してください" {...register("qiita_id")} />

                {/* X ID */}
                <FormLabel mt={2}>X ID</FormLabel>
                <Input placeholder="IDを入力してください" {...register("x_id")} />

                {/* 登録ボタン */}
                <Button mt={3} colorScheme='teal' type="submit">登録</Button>
              </form>
            </Box>
          </CardBody>
        </Stack>
      </Card>
      </Box>

    </div >
  )

}

解決方法

Controllerにrulesを設定する

Register.tsx
import { Box, Button, Card, CardBody, CardHeader, Checkbox, CheckboxGroup, Flex, FormLabel, Heading, Input, Radio, RadioGroup, Stack, Text, Textarea, useFormErrorStyles } from "@chakra-ui/react"
import { Controller, useForm } from "react-hook-form";

import { useSkills } from "../hooks/useSkills";
import { UserParams } from "../domain/users";
import { getValueTransition } from "framer-motion";

export const Register = () => {
  const { register, handleSubmit, control, formState: { errors } } = useForm<UserParams>();

  const { skillsData } = useSkills();


  return (
    <div>
      <Box display="flex" justifyContent="center" alignItems="center" height="100vh" bg="#e4e4e7">
      <Card pl={5} pr={5}>
        <CardHeader textAlign="center">
          <Heading size='lg'>新規名刺登録</Heading>
        </CardHeader>
        <Flex><Text ml={6} as="span" color="#CC6666">*</Text><Text ml={1} fontSize="13px">は必須項目です</Text></Flex>
        <Stack>
          <CardBody>
            <Box textAlign="center">
              <form onSubmit={handleSubmit((data) => {
                console.log("dataの中身", data);
              })}>

                 {/* ユーザーID */}
                <FormLabel fontWeight={"bold"}>ユーザーID <Text as="span" color="#CC6666">*</Text></FormLabel>
                  <Input type="text" placeholder="ユーザーIDを入力してください" {...register("user_id", { required: true})} />
                    <Box textAlign="left">{errors.user_id && <Text as="span" fontSize="14px" color="red">入力必須です</Text>}</Box>
                
                {/* 名前 */}
                <FormLabel fontWeight={"bold"} mt={2}>名前 <Text as="span" color="#CC6666">*</Text></FormLabel>
                  <Input type="text" placeholder="名前を入力してください" {...register("name", { required: true})} />
                    <Box textAlign="left">{errors.name && <Text as="span" fontSize= "14px" color="red">入力必須です</Text>}</Box>
                
                {/* 自己紹介 */}
                <FormLabel fontWeight={"bold"} mt={2}>自己紹介 <Text as="span" color="#CC6666">*</Text></FormLabel>
                  <Textarea placeholder="自己紹介文を入力してください。HTMLタグも使えます" {...register("description", { required: true})} />
                    <Box textAlign="left">{errors.description && <Text as="span" fontSize= "14px" color="red">入力必須です</Text>}</Box>
                
                {/* 好きな技術 */}
                <FormLabel fontWeight={"bold"} mt={2}>好きな技術 <Text as="span" color="#CC6666">*</Text></FormLabel>
                <Controller // controller使用しないと制御できない
                  name="skills" // どのフィールドを管理するか指定 フォーム送信時にここで指定した値がオブジェクトのキーとして扱われる
                  defaultValue={[]} // デフォルトの値
                  control={control} // usFormから取得したcontrolを渡している。これによりコンポーネントがフォームの状態管理に接続される
                  rules={{
                    validate: (value) => {
                      if (!value || value.length === 0 ) { // valueがnullまたはundefinedの時に||の右を評価
                        return "少なくとも1つを選択してください";
                      }
                      return true;
                    }
                  }}
                  render={({ field }) => { // fieldという決まった名称のオブジェクト
                    return (
                      <CheckboxGroup value={field.value} onChange={(values) => field.onChange(values.map(Number))}> {/* Chakra uiのGroup Hook Formのデフォルトの値文字列から数値に変換が必要*/}

                        {skillsData.map((skill) => (
                          <Checkbox ml={1} mr={1} key={skill.id} value={skill.id} >{skill.name}</Checkbox>
                        ))}

                      </CheckboxGroup>
                    );
                  }}
                />
                {/* チェックボックスのエラーメッセージ */}
                <Box textAlign="left">{errors.skills && <Text as="span" fontSize="14px" color="red">{errors.skills.message}</Text>}</Box>

                 {/* GitHub ID */}
                <FormLabel mt={2}>GitHub ID</FormLabel>
                <Input placeholder="IDを入力してください" {...register("github_id")} />

                {/* Qiita ID */}
                <FormLabel mt={2}>Qiita ID</FormLabel>
                <Input placeholder="IDを入力してください" {...register("qiita_id")} />

                {/* X ID */}
                <FormLabel mt={2}>X ID</FormLabel>
                <Input placeholder="IDを入力してください" {...register("x_id")} />

                {/* 登録ボタン */}
                <Button mt={3} colorScheme='teal' type="submit">登録</Button>
              </form>
            </Box>
          </CardBody>
        </Stack>
      </Card>
      </Box>

    </div >
  )

}

参考

おわりに

react-hook-form便利ですね。


1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?