Mantine入門6 ブログ概要入力フォームを作成しよう

前回のカード内容(タイトル、日付、タグ、概要)と、カードからリンクされる記事本体へのリンクを設定するフォームのページを作成します。
カードの内容は違う記事だとしても同じJSONファイルに記載していきます。カードをタグや日付で並べ替えたり、切り替えたりします。

(記事の一時保存、記事作成ページは、後で追加します。記事自体は、記事ごとに個別にJSONファイルに保存します。)

フォームの作成

タイトルはTextInput、タグはMultiSelect、概要はTextArea
日付、ブログ本体のファイル名(リンク先)は自動入力とします。

import { Paper, TextInput, MultiSelect,Textarea } from "@mantine/core";
import { NextPage } from "next";

const data = [
    { value: 'react', label: 'React' },
    { value: 'next', label: 'Next.js' },
    { value: 'python', label: 'python' },
  ];


const WriteBlog:NextPage = () =>{

    return(
        <>
            <Paper shadow="md" m="md" p="sm">
                <TextInput mt="sm"
                    label="タイトル" withAsterisk
                    placeholder="タイトルを入力してください"
                />
                <MultiSelect mt="sm"
                    label="カテゴリ"
                    placeholder="タグを選択してください。(複数可)"
                    data={data}
                />
                <Textarea mt="sm"
                    label="概要"
                    placeholder="概要(目的と結果)を記載してください"
                    autosize
                    minRows={2}
                />
            </Paper>
            <Group position="right">
                    <Button mt="sm" >送信</Button>
            </Group>
            
        
        </>
    )
}
export default WriteBlog

以下のようなフォームができました。

文字の制限や抜け漏れなどを確認するuseFormを使っていきます。

準備

import { useForm } from "@mantine/form";
....

const WriteBlog:NextPage = () =>{

    const cardform = useForm(
        {
            initialValues:{
                title:'',//TextInputのvalueは文字列
                tag:[''],//MultiSelectのvalueは文字列の配列
                abstract:'',//Inputareaのvalueは文字列
            },
        }
    )
......

まずは、上記のように最終的にフォームから入手したいJSONフォーマットをinitalValuesに定義します。コレをuseFormの関数に渡してformオブジェクトを生成します。

Inputとの紐付け

次に、先ほど定義したJsonフォーマットを含んだuseFormオブジェクトformと、InputText,MultiSelect,Textareaと紐付けします。下記のように、それぞれのJSXタグの中に、…from.getInputProps('jsonキー’)のスプレッド構文を埋め込みます。

               <TextInput mt="sm"
                    label="タイトル" withAsterisk
                    placeholder="タイトルを入力してください"
                    {...cardform.getInputProps('title')}
                />
                <MultiSelect mt="sm"
                    label="カテゴリ"
                    placeholder="タグを選択してください。(複数可)"
                    data={data}
                    {...cardform.getInputProps('tag')}
                />
                <Textarea mt="sm"
                    label="概要"
                    placeholder="概要(目的と結果)を記載してください"
                    autosize
                    minRows={2}
                    {...cardform.getInputProps('abstract')}
                />

コレで、useFormのさまざまな関数をInputに反映できます。

値のセット

たとえば、フォームの値を設定できます。
以下のようなボタンイベントハンドラ内でsetFieldValue関数を使ってみます。ただ、この機能はあまり使わないでしょう。パスワードの自動割り当てなどで使う用途があるかもしれません。

    const buttonHandler = () =>{
        cardform.setFieldValue('title',"aaaa")
        cardform.setFieldValue('tag',["next","python"])
        cardform.setFieldValue('abstract','setFieldValueで入力')
    }
・・・
        <Button mt="sm" onClick={buttonHandler}>送信</Button>

値のリセット

reset関数でinitialValuesの値をセットし、入力エラーを解除します。間違えて押した時のことを考えると、これもあまり使わないかもしれません。

<Button mt="sm" onClick={()=>{cardform.reset()}}>リセット</Button>

値のバリデーション

フォームのバリデーションは、以下のように、useFormの中に、validateオブジェクトを定義します。定義の方法は、initalValuesの中で定義した変数をキーとして、値として、valueを受け取り、正常時にはnullを返し、異常時には文字列を返す関数を設定します。正常、異常の条件はスクリプトで記述します。
タイトルには下記のようなシンプルな3項演算子でバリデーションを定義します。

    const cardform = useForm(
        {
            initialValues:{
                title:'',//TextInputのvalueは文字列
                tag:[''],//MultiSelectのvalueは文字列の配列
                abstract:'',//Inputareaのvalueは文字列
            },
            validate:{
                title:(value) => (
                    value.length < 1 
                    ? '必須入力です。' 
                    : null),
            },
        }
    )

複雑な条件の時は、関数にすることもできます。useFomeにvalidateInputOnChange: true を加えると、valueが変わるたびに評価されます。

const validnum = (value:string) => {
    let ret = null
    if(value.length < 10)
    {
        ret = "10文字以上で入力してください'"
    }
    if(value.length > 300)
    {
        ret = "300文字以下で入力してください。"
    }
    return ret
}

const WriteBlog:NextPage = () =>{

    const cardform = useForm(
        {
            initialValues:{
                title:'',//TextInputのvalueは文字列
                tag:[''],//MultiSelectのvalueは文字列の配列
                abstract:'',//Inputareaのvalueは文字列
            },
            validate:{
                title:(value) => (
                    value.length < 1 
                    ? '必須入力です。' 
                    : null),
                abstract:(value)=>(validnum(value)),
            },
            validateInputOnChange: true ,
        }
    )

バリデーションを実行するタイミングは、通常、formタグ内に定義しtype="submit"のボタンがクリックされた時です。

const WriteBlog:NextPage = () =>{

    const cardform = useForm(
        {
            initialValues:{
                title:'',//TextInputのvalueは文字列
                tag:[''],//MultiSelectのvalueは文字列の配列
                abstract:'',//Inputareaのvalueは文字列
            },
            validate:{
                title:(value) => (
                    value.length < 1 
                    ? '必須入力です。' 
                    : null),
                abstract:(value)=>(validnum(value)),
            },
            validateInputOnChange: true ,
        }
    )

    return(
        <>
            <Paper shadow="md" m="md" p="sm">
                <form onSubmit={cardform.onSubmit((value)=>console.log(value))}>
            
                    <TextInput mt="sm"
                        label="タイトル" withAsterisk
                        placeholder="タイトルを入力してください"
                        {...cardform.getInputProps('title')}
                    />
                    <MultiSelect mt="sm"
                        label="カテゴリ"
                        placeholder="タグを選択してください。(複数可)"
                        data={data}
                        {...cardform.getInputProps('tag')}
                    />
                    <Textarea mt="sm"
                        label="概要" withAsterisk
                        placeholder="概要(目的と結果)を記載してください"
                        autosize
                        minRows={2}
                        {...cardform.getInputProps('abstract')}
                    />
                    <Group position="right">
                        <Button mt='sm' type="submit">送信</Button>
                    </Group>
                </form>
            </Paper>
        
        </>
    )
}
export default WriteBlog

バリデーションに引っ掛かっていると、
<form onSubmit={cardform.onSubmit((value)=>console.log(value))}>
のログ出力が出てきません。バリデーションに引っ掛かっていないければ、ログに値が表示されます。ここでデータベースなどに情報を書き込む流れ(バックエンド処理)になります。


この記事が気に入ったらサポートをしてみませんか?