4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-02-22

チェックボックスはオフの時に値を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を一括置換するだけで済むので。

4
3
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
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?