鶏口牛後な日々

心の赴くまま、やりたいことを仕事に。

Laravelのセレクトボックスでバリデーション戻ってきたとき前入力した内容をold()メソッドで表示したい

bladeの @if ディレクティブで書く

かっこいい書き方はないようで、@ifディレクティブを使って以下のように書くとできました。

<div class="form-group">
  <div class=required>必須</div>
  <label for="gender">性別を選択してください</label>
    <select name="gender">
      <option value="male" @if(old('gender')=='male') selected  @endif>男性</option>
      <option value="female" @if(old('gender')=='female') selected @endif>女性</option>
      <option value="other" @if(old('gender')=='other') selected @endif>その他</option>
    </select>
</div>

(後日追記)@json を使ってJavaScriptで書き直した

上記のような書き方で、確かにできていました。 上は、ユーザー登録の画面について作ったもので、この時はそれで問題なかったのですが、登録した情報の変更画面を作ろうとした時に、問題にぶつかりました。

selected という属性は、HTMLのタグ内でfalse を指定することができません。 selected と書くか、書かないかしかないので、 selected="false" といった書き方はできません。

となると、変更画面では、一度登録したデータをデータベースから取得して表示させます。 その後、変更する場合は変更して、submitするのが基本です。 つまり、登録しておいたデータが selected で、そのチェックを外した場合、リダイレクトして戻ってきた時には、チェックを外さないといけない。 これは、@if ディレクティブではできません。

そういう時はどうするか? というと、javascriptに、 @json で受け取って、操作するのが良いようです。

リダイレクト時の挙動をjavascriptで書く

<head>
    <script>
        var oldGender = @json(old('gender'));
        $(document).ready(function(){
            // セレクトボックスの表示(リダイレクト時)
            $('select[name="gender"] option[value="' + oldGender + '"]').prop('selected', true);
        });

こう書くことで、ソースもスッキリ書けます。

注意点としては、ページを読み込んでから操作したいので、$(document).ready(function() {}); をつけます。

初回ロード時、リダイレクト時の両方の挙動をjavascriptで書く

初回ロード時とリダイレクト時の両方の挙動をjavascriptで書くことももちろん可能です。

<head>
    <script>
        var gender = @json($gender);
        var oldGender = @json(old('gender'));
        $(document).ready(function(){
            // セレクトボックスの表示
            $('select[name="gender"] option[value="' + gender + '"]').prop('selected', true);

            // セレクトボックスの表示(リダイレクト時)
            $('select[name="gender"] option[value="' + oldGender + '"]').prop('selected', true);
        });
    </script>
</head>

bladeの記述も @if ディレクティブを各optionの行に書く必要がなく、スッキリかけるので、これはやらなきゃ損損といったところでしょうか。

@json がとっても便利ということを実感しました。

(更に後日追記)複数のセレクトに同時に対応してくれるように変数を使わない形に書き換えた

上記で問題なく動いていたのですが、セレクトボックスそれぞれについて変数を作っていたので、今後セレクトボックスが増えた時には毎回追記しないといけない・・・ということで書き直しました。

HTML
<select name="gender" data-selected="{{ old('gender', $gender) }}">
    <option value="man">男性</option>
    <option value="woman">女性</option>
    <option value="other">その他</option>
</select>
JS
// セレクトボックスの表示
$('select').each(function () {
    var select = $(this);
    var selected = $(this).data('selected');
    select.children('option[value="' + selected + '"]').prop('selected', true);
});
  • selectタグに、data-selected というカスタム属性を追記し、そこにリダイレクト時でも初回ロード時でも値が取れる old() で値を取得するようにしました。

  • js側で .data() メソッドで値を取得すれば、それに合わせてセレクトするoptionを選択することができる。

カスタム属性って今まで使いどころが良くわかっていなかったのですが、一気に理解できました。

以上。