🚀
【Laravel6】Bootstrapで横並びにしたラジオボタンのバリデーションメッセージを表示する時の落とし穴
概要
Laravelアプリでコンテンツ登録時にBootstrapで作成したラジオボタンのバリデーションメッセージが表示されない事態に陥りました。
本記事ではその解決方法の一例を紹介します。
※Laravelアプリで発生しましたが、原因はBootstrapだったのでLaravel特有なものではないです。
環境
$ composer -V
Composer version 1.10.20 2021-01-27 15:41:06
$ php artisan --version
Laravel Framework 6.20.16
前提
バリデーションメッセージは各入力項目の下に分けて表示させる。
(「カテゴリーは必ず指定してください。」がバリデーションメッセージです)
よくLaravel教材で採用されているのは、画面上部に全てのバリデーションメッセージを箇条書きで表示する方法で以下のコード。
(公式ドキュメントより)
<!-- /resources/views/post/create.blade.php -->
<h1>ポスト作成</h1>
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<!-- ポスト作成フォーム -->
今回はこちらのコード(例)を採用します。
(こちらも公式ドキュメントより)
<!-- /resources/views/post/create.blade.php -->
<label for="title">Post Title</label>
<input id="title" type="text" class="@error('title') is-invalid @enderror">
@error('title')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
Bootstrapで横並びにしたラジオボタンのバリデーションメッセージを表示する時の落とし穴の解決方法
解決済みのコード
create.balde.php
{{-- 略 --}}
<div class="form-group mb-4">
<p for="exampleInputPassword1">カテゴリー<span class="text-danger">(※)</span></p>
{{-- ラジオボタン --}}
<div class="form-check form-check-inline is-invalid">
<input class="form-check-input form-check-inline is-invalid " type="radio" name="category_id" id="category1" value="1" >
<label class="form-check-label" for="category1">Laravel</label>
</div>
<div class="form-check form-check-inline is-invalid">
<input class="form-check-input form-check-inline is-invalid " type="radio" name="category_id" id="category2" value="2" >
<label class="form-check-label" for="category2">PHP</label>
</div>
<div class="form-check form-check-inline is-invalid">
<input class="form-check-input form-check-inline is-invalid" type="radio" name="category_id" id="category3" value="3" >
<label class="form-check-label" for="category3">Docker</label>
</div>
<div class="form-check form-check-inline is-invalid">
<input class="form-check-input form-check-inline is-invalid" type="radio" name="category_id" id="category4" value="4" >
<label class="form-check-label" for="category4">web基礎</label>
</div>
{{-- バリデーションメッセージ --}}
<span class="invalid-feedback" role="alert">
<strong>カテゴリーは必ず指定してください。</strong>
</span>
</div>
{{-- 略 --}}
落とし穴にハマった時のコード
create.balde.php
{{-- 略 --}}
<div class="form-group mb-4">
<p for="exampleInputPassword1">カテゴリー<span class="text-danger">(※)</span></p>
{{-- ラジオボタン --}}
<div class="form-check form-check-inline">
<input class="form-check-input form-check-inline is-invalid" type="radio" name="category_id" id="category1" value="1" >
<label class="form-check-label" for="category1">Laravel</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input form-check-inline is-invalid" type="radio" name="category_id" id="category2" value="2" >
<label class="form-check-label" for="category2">PHP</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input form-check-inline is-invalid" type="radio" name="category_id" id="category3" value="3" >
<label class="form-check-label" for="category3">Docker</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input form-check-inline is-invalid" type="radio" name="category_id" id="category4" value="4" >
<label class="form-check-label" for="category4">web基礎</label>
</div>
{{-- バリデーションメッセージ --}}
<span class="invalid-feedback" role="alert">
<strong>カテゴリーは必ず指定してください。</strong>
</span>
</div>
{{-- 略 --}}
これだとバリデーションメッセージが表示されません。
違いと解決理由
違い
1つ1つのラジオボタン(input
タグのtype=radio
)の親のクラスにdiv
タグにis-invalid
がつけているかついていないか
バリデーションメッセージが表示される
<div class="form-check form-check-inline is-invalid">
バリデーションメッセージが表示されない
<div class="form-check form-check-inline>
解決理由
バリデーションエラー時に入力フォームを赤くして、メッセージを表示させるには以下のルールがあったのですが、シンプルにそれを満たしていなかっただけでした。
- ラジオボタンのinputタグのクラスに
is-invalid
がついている - バリデーションメッセージを表示するDOMの兄弟要素(同じ階層)のタグのクラスにそれぞれ
is-invalid
、invalid-feedback
がついている
こんな感じでinput
タグとspan
タグを兄弟要素にするとバリデーションメッセージが表示されますが、レイアウトがうまくできませんでした。。
{{-- 略 --}}
<input class="form-check-input form-check-inline is-invalid" type="radio" name="category_id" id="category4" value="4" >
<label class="form-check-label" for="category4">web基礎</label>
{{-- バリデーションメッセージ --}}
<span class="invalid-feedback" role="alert">
<strong>カテゴリーは必ず指定してください。</strong>
</span>
補足
実際のコードはLaravelで
-
@error
ディレクティブでバリデーションメッセージの有無を判定 - ラジオボタンの選択肢データをDBにマスターデータとして保持して取得する(カテゴリーの追加を楽にするため)
をしているため実際のコードは以下の通りです。
Viewファイル
create.blade.php
{{-- 略 --}}
<div class="form-group mb-4">
<p for="exampleInputPassword1">カテゴリー<span class="text-danger">(※)</span></p>
{{-- ラジオボタン --}}
@foreach ($categoryForRadioButton as $index => $categoryName)
<div class="form-check form-check-inline @error('category_id') is-invalid @enderror">
<input class="form-check-input form-check-inline @error('category_id') is-invalid @enderror" type="radio" name="category_id" id="category{{ $index }}" value="{{ $index }}" {{ old('category_id') == $index ? 'checked': '' }}>
<label class="form-check-label" for="category{{ $index }}">{{ $categoryName }}</label>
</div>
@endforeach
{{-- バリデーションメッセージ --}}
@error('category_id')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
{{-- 略 --}}
ラジオボタンの選択肢取得用
Category.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
/**
* ラジオボタン用の配列データを作成
*
* @return array
*/
public function getAll(): array
{
$categoryForRadioButton = [];
$allCategories = $this->all();
foreach ($allCategories as $index => $category) {
$categoryForRadioButton[$index + 1] = $category->name;
}
return $categoryForRadioButton;
}
}
Discussion