
Laravelでプルダウンを書いているけど、optionをたくさん書く方法しかわからない….もっと簡単に修正に強い書き方はないかな….

セレクトボックスを作成し、ソートもさせたい
こんな疑問を解決します。
記事の前半では、実務で使えるプルダウンの書き方や編集画面の書き方を解説します。
いつまでも初心者のようなコードを書いていても成長はありません。
今回は、optionをたくさん書かずに、foreachを使ってプルダウンをスマートに書く方法を現役エンジニアが解説します。
記事の後半では、セレクトボックスを作成し、ソートまでさせる書き方を解説します。
①セレクトボックスを選択する
②選択したセレクトボックスが例えば価格が低い順なら、価格が低い順にソートさせ、価格が高い順を選べば、価格が高い順にデータをソートさせる
③画面の表示
結論、セレクトボックス変更時にフォームをsubmitし、選択したセレクトボックスの値で条件分岐させればOKです。
- スマートにプルダウンを書く方法がわかる
- クソコードから脱却できる
- セレクトボックスを作成しソートさせたい


休日で空いた時間の暇つぶしを探せるアプリを公開しています。
プルダウンとセレクトボックスを作成する開発環境
Docker 20.10.7
PHP 7.4.22
Laravel 8.53.1
mySQL 5.7
データベースのツール phpmyadmin
dockerで動作確認をしておりますが、基本的にMAMP環境とかでも動くと思います。
また、Laravelのバージョンが8なので6系を使っていたら多少記述が違ってくると思います。
ex.ルーティングの書き方やApp\Book→App\Models\Bookなど
Laravelのプルダウンで想定するもの
本を管理するアプリを想定しており、「カテゴリーのプルダウンを作成してほしい」という依頼がきたとします。
プルダウンは以下を想定
その場合、初心者でありがちなのがoptionタグをひたすら書いてしまうこと。これだと順番が入れ替わったりしたときに修正が大変です。
なので、optionタグをひたすら書くというクソコードから脱却してforeachなどを使ってみましょう。
初心者が書きがちなプルダウンのコード例
<!-- カテゴリープルダウン -->
<div class="form-group">
<label for="category-id">{{ __('カテゴリー') }}<span class="badge badge-danger ml-2">{{ __('必須') }}</span></label>
<select class="form-control" id="category-id" name="category_id">
<option value="1">PHP</option>
<option value="2">Ruby</option>
<option value="3">Laravel</option>
<option value="4">Java</option>
<option value="5">jQuery</option>
</select>
</div>
こんな感じでoptionを増やしがちです。
サンプルコードのように5個ぐらいならこれでも問題ないのですが、データが1000個とかになったら1000こoption描かなくちゃいけないし、数字が変わったらメンテナンスも大変です。
なので、実務では絶対NGなクソコードになります。
ちなみにclass名にform-controllとかbadge-dangerとかありますが、これはbootstrapを導入したときに以下のように認識してくれます。
実務で使えるプルダウンの書き方
事前準備としてカテゴリーテーブルを作成する必要があります。
var/www/html/tests_app# php artisan make:migration create_categories_table --create=categories
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCategoriesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->id('category_id');
$table->string('category_name', 255);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('categories');
}
}
$table->id(‘category_id’);ですがlaravel7以降から導入された記述方法です。laravel6系の場合は、$table->bigIncrements(‘category_id’);としてください。
あとはマイグレートを実行して、カテゴリーテーブルを作成しましょう。
var/www/html/tests_app# php artisan migrate
準備はできたので、早速プルダウンでスマートに書く方法の解説です。まずはコードから。
foreachを使って以下のように書くのがシンプルでおすすめです。
<!-- カテゴリープルダウン -->
<div class="form-group">
<label for="category-id">{{ __('カテゴリー') }}<span class="badge badge-danger ml-2">{{ __('必須') }}</span></label>
<select class="form-control" id="category-id" name="category_id">
@foreach ($categories as $category)
<option value="{{ $category->category_id }}">{{ $category->category_name }}</option>
@endforeach
</select>
</div>
解説します。
先程のoptionたくさん状態からforeachを使ってoptionは一つだけになりました。
これでも同様の結果が得られます。
一番気になるのが、ここでしょう。
@foreach ($categories as $category)
<option value="{{ $category->category_id }}">{{ $category->category_name }}</option>
@endforeach
やってることとして、コントローラーで$categoriesを定義し、それをビューにわたします。
$categoriesには、カテゴリーテーブルにあるデータが全て取得されるようにして、それをforeachで一つずつデータを取り出しています。
valueには取得したcategory_id、表示名にはcategory_nameを書くことでオッケーです。
$categoriesはコントローラーで定義しましょう。
コントローラー
public function __construct()
{
$this->category = new Category();
}
/**
* 登録画面
*/
public function create(Request $request)
{
$categories = $this->category->get();
return view('book.create', compact('categories'));
}
// 解説
get()で取得したいデータを全てコレクションとして取り出せます。
詳しくはlaravel公式ドキュメントのgetを参照ください。
compact関数で、ビューに変数を渡せます。
compact('$をなくした変数名')って感じで使えます。
withを使う場合は、
with('categories',$categories)と書けばいいのですが、私はが書く量が少ないのでcompact関数をいつも使っています。
プルダウンを作成中にconfigファイルを使う場合
今回はタグのプルダウンをconfigを使って作成する予定です。
config配下にファイル名はなんでもいいですがわかりやすいようにtag.phpを作成しましょう。
config>tag.phpになります。
(config>tag.php)
<?php
return [
'tag_name' => [
1 => '面白い',
2 => '最高',
3 => 'つまらない'
]
];
<!-- タグープルダウン -->
<div class="form-group">
<label for="tag-id">{{ __('タグ') }}<span class="badge badge-danger ml-2">{{ __('必須') }}</span></label>
<select class="form-control" id="tag-id" name="tag_id">
@foreach (Config::get('tag.tag_name') as $key => $val)
<option value="{{ $key }}">{{ $val }}</option>
@endforeach
</select>
</div>
ポイントは、以下の部分です。
@foreach (Config::get('tag.tag_name') as $key => $val)
<option value="{{ $key }}">{{ $val }}</option>
@endforeach
Config::get(‘configファイル名.キー名’)をfoeaechでキーと値を一つずつ取り出すことで、value値にはそれぞれの値が入り(1,2,3)、{{ $val }}で対応する表示名を出力できます。
このようにプルダウンを作成する際は、変数を使ってスマートに書いていきましょう!!
もしわかりずらいところなどがあればコメントにてお知らせください。
編集画面で初期表示はDBの値、エラー時はoldの値を保持するには?
編集画面で、
- プルダウンの初期表示はDBの値を表示させる
- プルダウンを変更したときにバリデーションに引っかかってしまった場合は、oldの値を保持させて選択した値にしておく
こんな感じの実装をする場合は以下のように書けます。
<div class="form-group">
<label for="post_code">{{ __('投稿番号') }}<span class="badge badge-secondary ml-2">{{ __('任意') }}</span></label>
<select class="form-control{{ $errors->has('post_code') ? ' is-invalid' : '' }}" name="post_code" id="post-code">
<option></option>
@foreach ($posts as $post)
@if (!is_null(old('post_code')))
<!-- バリデーションエラー等による再表示時 -->
@if ($post->post_code == old('post_code'))
<option value="{{ $post->post_code }}" selected>{{ $post->post_name }}</option>
@else
<option value="{{ $post->post_code }}">{{ $post->post_name }}</option>
@endif
@else
<!-- 初期表示時 -->
@if ($post->post_code == $user->code)
<option value="{{ $post->post_code }}" selected>{{ $post->post_name }}</option>
@else
<option value="{{ $post->post_code }}">{{ $post->post_name }}</option>
@endif
@endif
@endforeach
</select>
@if($errors->has('post_code'))
<div class="invalid-feedback">
{{ $errors->first('post_code') }}
</div>
@endif
</div>
Laravelでセレクトボックスを作成する
マイグレーションはこんな感じで作りました。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateItemsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('items', function (Blueprint $table) {
$table->id();
$table->string('name', 50);
$table->integer('price');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('items');
}
}
セレクトボックスのソート条件をかく
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Item;
class ItemController extends Controller
{
public function index(Request $request)
{
// セレクトボックスで選択した値
$select = $request->price;
// セレクトボックスの値に応じてソート
switch ($select) {
case '1':
//「指定なし」はID順
$items = Item::get();
break;
case '2':
// 「価格が低い順」でソート
$items = Item::orderBy('price', 'asc')->get();
break;
case '3':
// 「価格が高い順」でソート
$items = Item::orderBy('price', 'desc')->get();
break;
default :
// デフォルトはID順
$items = Item::get();
break;
}
return view('item.index', compact('items', 'select'));
}
}
画面側は以下のように書きます。
※jQueryを使うので、CDNを読み込みましょう。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>セレクトボックスでソート</title>
{{-- JQUeryをCDNで読み込む --}}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
</head>
<body>
<form id="form">
<select name="price" id="price">
<option value="1" {{ $select == '1' ? 'selected': '' }}>指定なし</option>
<option value="2" {{ $select == '2' ? 'selected': '' }}>価格が低い順</option>
<option value="3" {{ $select == '3' ? 'selected': '' }}>価格が高い順</option>
</select>
</form>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
@foreach ($items as $item)
<tr>
<td>{{ $item->id }}</td>
<td>{{ $item->name }}</td>
<td>{{ $item->price }}</td>
</tr>
@endforeach
</tbody>
</table>
<script>
$(function() {
$('#price').change(function () {
$('#form').submit();
});
});
</script>
</body>
</html>
「指定なし」→ID順でソートされる

「価格が低い順」→priceが低い順でソートされる

「価格が高い順」→priceが高い順でソートされる



休日で空いた時間の暇つぶしを探せるアプリを公開しています。
コメント