Laravelで入力値が可変長arrayのときにwithInputしてInput::old()で取りたい時の対処法
いつものようにB'zの曲名くらい長いタイトルですが、
そのまんまです。
ここで問題です。でーでん♪
あなたは、特定のグループ、またはグループのサブグループを複数指定して、一気に絞り込み検索できる機能を追加して欲しいと言われました。
たとえばこんな感じに
愉快な仲間たち > お絵描き部
チーム★イケメン > ボル部
さて、どんなUIでどんな入力値をpostしますか?
こういうときに、指定するか分からないセレクトをいっぱい並べるのは気持ち悪いですし、グループが100個くらいあったらどうしようって感じです。
select2を使うという方法もありますが、今回はグループのサブグループを指定する際に、親グループを選択したらparent_idが親グループのサブグループのみが表示されて、それを選択したい要件があり、select2のような並列選択では具合が悪いです。
ということで、私の場合は親グループとサブグループを選択するセレクトを2つおいて、そのセットを動的に追加するボタンを設置することにしました。
これで無限にグループを指定できます。
グループを設定して絞り込むまでは良かったんですが、 ふとwithInput()で返しているInput::old()はどのように書けばいいか迷ったので、私みたいに迷ってしまう人がいそうなので、ブログにまとめておきます。
※以下はLaravel4.2のコードです。5系の人はファサードなどを適宜修正してください。
こういう感じで
<?php return Redirect::to('group_search')->withInput()
のようにすると、arrayで値を渡した場合はInput::old(‘groups.0.main’)という感じでピリオドで階層を掘って値が取得できます。
なので
@foreach (Input::old('groups') as $i => $group) <select class="form-control" name="groups[{{$i}}][main]"> <option value="">--指定なし--</option> <option value="1"{{{ (int)$group['main'] == 1) ? ' selected="selected"' : '' }}}>愉快な仲間たち</option> <option value="2"{{{ (int)$group['main'] == 2) ? ' selected="selected"' : '' }}}>チーム★イケメン</option> </select> <select class="form-control" name="groups[{{$i}}][sub]"> <option value="">--指定なし--</option> <option value="1"{{{ (int)$group['sub'] == 1) ? ' selected="selected"' : '' }}}>お絵描き部</option> <option value="2"{{{ (int)$group['sub'] == 2) ? ' selected="selected"' : '' }}}>ボル部</option> </select> @endforeach
こういう感じで、入力値とhtmlを元に戻してやることができます。
可変長なので、foreachで0の部分を$iにして回せばいいんですね。
値はキーを指定すれば取得出来ますし、Input::old(‘groups.’.$i.‘.main’)のようにしても取得できます。
Input::old(‘groups’)がないデフォルトの入力の場合は、
<?php $groups[0] = [ 'main' => null, 'sub' => null, ]; ?>
みたいな感じで1個だけ初期のセレクトをセットしてやればよいです。
実際には、selectの部分はHTMLのmacroなどを使ったりするので、もっと簡潔で動的に書けます。
動的にセレクトを増やす部分のjsは、こんな感じです。
こちらはcloneして連番部分を振り直してあげるだけです。
$(document).on('click', '.js-add-group-select', function(e){ $('.js-group-select').first() .clone() .find('option') .attr("selected",false) .end() .insertAfter('.js-group-select:last'); $('.js-group-select').each(function(i, el) { var inputs = ['main', 'sub']; var self = $(this); $.each(inputs, function(j, val){ var $select = self.find('[name*="['+ val +']"]'); var name = $select.attr('name'); var reg = new RegExp("(groups\\[)(\\d)(\\]\\["+val+"\\])", "g"); var replacer = '$1'+i+'$3'; var newName = name.replace(reg, replacer); $select.attr('name', newName); }); }); });
最後に、これを読んでくれた君に、私が崇拝するベルばらの名言より、この言葉を贈ります。
君はWebサービスの影になれ
光ある限り存在をかたちづくる影となって無言のままそいつづけるがいい
アデュー
by ベル子