Help us understand the problem. What is going on with this article?

laravel5 チェックボックスで「オフの時は0、オンの時は1をpost」はどう書くのが気持ちいいか

チェックボックスはオフの時に値をpostしません。
登録のみなら構わないのですが、編集時はオフの時に値をpostされないと、チェック状態が外せなくなります。

hiddenを埋め込む

いくつか方法はある(プログラム側でなんとかするとか、jsでなんとかするとか)のですが、
今回はhiddenを埋め込む方法でやってみます。

<input name="cb1" type="hidden" value="0">
<input name="cb1" type="checkbox" value="1">

このようにチェックボックスの前にhiddenで0を埋め込んでおくと

  • チェックボックスがオンの時はvalueの1がpostされる
  • チェックボックスがオフの時はhiddenの0がpostされる

のです。

formヘルパーで実装

ネットで検索すると
formヘルパーを使った

{{ Form::hidden('cb1', 0) }}
{{ Form::checkbox('cb1', 1, $data['cb1'] ?? '') }}

のような書き方が散見されます。
確かにhiddenもcheckboxもこれで配置されますが、
この方法はひとつ落とし穴があります。
Form::hiddenはoldの影響を受けるのです。

検証

qiita20190222_1.png

このようなフォームがあって
チェックボックスには先ほどの

{{ Form::hidden('cb1', 0) }}
{{ Form::checkbox('cb1', 1, $data['cb1'] ?? '') }}

という記述をしているとします。
テキストにはフォームリクエストバリデーションで必須を指定しています。

この時点では
qiita20190222_2.png
期待した通りの状態になっています。

では、チェックボックスをオンにして、テキストには何も入力せずにpostしてみましょう。

qiita20190222_3.png

テキストのバリデーションエラーで入力画面に戻りました。
この状況でhiddenの値がどうなっているかというと…

qiita20190222_4.png
hiddenのvalueが1になってしまいました。

チェックボックスをオンにしたため、cb1=1としてpostされ、
old('cb1')は1になります。
バリデーションエラーで戻ってきた入力画面では、Form::hiddenはこの値を使用して
valueの値を変更します。

というわけで、formヘルパーでhiddenを埋め込むと
valueを0に固定できません。
まぁ、

<input name="cb1" type="hidden" value="0">
{{ Form::checkbox('cb1', 1, $data['cb1'] ?? '') }}

と書けば解決するんですが、
あまりテンションの上がらない書き方です。

「チェックしたままpostしてバリデーションエラーで戻されてからチェックを外す」
という状況でしか問題にならないから別にええやないか、とも言えますが、
やっぱりあまりテンションは上がらない感じになります。

ないなら作る

LaravelのFormヘルパーはマクロを自作できます。

というわけで
チェックボックスの前に自動でhiddenの値を埋め込んでくれる
Form::booleanboxを自作します。

$ php artisan make:provider FormMacroServiceProvider
app/Providers/FormMacroServiceProvider.php
class FormMacroServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        require app_path().'/Libs/FormMacro.php';
    }
}

config/app.php
    'providers' => [
        App\Providers\FormMacroServiceProvider::class,
    ],
app/Libs/FormMacro.php
\Form::macro("booleanbox", function($name, $value = 1, $checked = null, $options = array()){
    return $this->toHtmlString("<input type=\"hidden\" name=\"{$name}\" value=\"0\">". \Form::checkbox($name, $value, $checked, $options));
});

あとは

{{ Form::booleanbox('cb1', 1, $data['cb1'] ?? '') }}

と書けば
Form::checkboxと
全く同じように使えるようになります。

とはいえ

新規案件でしたら
vue / react なんかで
ページ遷移とかoldとかを気にしない作りにしてしまうのが
一番気持ちいいとは思います。

古いプロジェクトの修正をする必要がある場合なんかにどうぞ。
これならForm::checkboxを一括置換するだけで済むので。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away