1
1

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 3 years have passed since last update.

入力エラー時にテキストボックスの枠を赤くしたい

Posted at

はじめに

入力エラー時にテキストボックスの枠を赤くしようとしたのですが、実装に苦労したので投稿します。

環境

OS: macOS Catalina 10.15.6
JDK:14.0.1
Spring Boot 2.3.3
jquery 3.3.1-1
bootstrap 4.2.1

①入力チェックにあたって

入力チェック(バリデーション)を行うにあたって、作者は下記のようにクラスを作成しました。

■コントローラークラス

SignupController.java
package com.example.demo.login.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

import com.example.demo.login.domain.model.GroupOrder;
import com.example.demo.login.domain.model.SignupForm;
import com.example.demo.login.domain.model.User;
import com.example.demo.login.domain.service.UserService;

//ユーザー新規登録用コントローラー
@Controller
public class SignupController {

	@Autowired
	private UserService userService;

	//ユーザー登録画面へ遷移
	@PostMapping("/signup")
	public String postSignUp(@ModelAttribute SignupForm form, Model model) {

		return "signup/signup";
	}

	//ユーザー新規登録実行用メソッド
	@PostMapping("/signupUser") //「GroupOrder」で設定した順序でバリデーションを実行
	public String postSignUp(@ModelAttribute @Validated(GroupOrder.class) SignupForm form, BindingResult bindingResult, Model model) {

		//バインディングでエラー発生(バリデーションエラー含む)した場合、ユーザー登録画面へ遷移
		if (bindingResult.hasErrors()) {
			return postSignUp(form, model);

		}

		//新規登録した内容をコンソールへ表示
		System.out.println(form);

		//Userインスタンスの作成
		User user = new User();

		//登録フォームに入力した内容をUserクラスにセット
		user.setUserId(form.getUserId());
		user.setMailAddress(form.getMailAddress());
		user.setPassword(form.getPassword());

		//フォーム入力内容をセットした「User」を引数にサービスクラスへ処理を投げる
		boolean result = userService.insertOne(user);

		//登録作業の実行結果をコンソールに表示
		if (result == true) {
			System.out.println("insert成功");
		} else {
			System.out.println("insert失敗");
		}

		//ログイン画面へ遷移
		return "redirect:/login";

	}

}

■バリデーショングループ

GroupOrder.java
package com.example.demo.login.domain.model;

import javax.validation.GroupSequence;

//ユーザー新規登録とユーザー登録情報更新の際に「ValidGroup1」「ValidGroup2」の順番にバリデーションを実行
@GroupSequence({ValidGroup1.class, ValidGroup2.class})
public interface GroupOrder {


}
ValidGroup1.java
package com.example.demo.login.domain.model;

//ValidGroup1のインターフェース
public interface ValidGroup1 {

}
ValidGroup2.java
package com.example.demo.login.domain.model;

//ValidGroup2のインターフェース
public interface ValidGroup2 {

}

■入力フォームのクラス

SignupForm.java

package com.example.demo.login.domain.model;


import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;

import org.hibernate.validator.constraints.Length;

import lombok.Data;


//ユーザー新規登録フォームで使用するSignupForm
@Data
public class SignupForm {

	/*
	 * null 半角スペース 空文字の場合エラー発生(ValidGroup1に分類)
	 * 3字以上20字以内(ValidGroup2に分類)
	 */
	@NotBlank(groups = ValidGroup1.class)
	@Length(min = 3, max = 20, groups = ValidGroup2.class)
	private String userId;

	/*
	 * null 半角スペース 空文字の場合エラー発生(ValidGroup1に分類)
	 * メールアドレスの形式でないとエラー発生(ValidGroup2に分類)
	 */
	@NotBlank(groups = ValidGroup1.class)
	@Email(groups = ValidGroup2.class)
	private String mailAddress;

	/*
	 * null 半角スペース 空文字の場合エラー発生(ValidGroup1に分類)
	 *  3字以上20字以内(ValidGroup2に分類)
	 *  英数字のみ(ValidGroup2に分類)
	 */
	@NotBlank(groups = ValidGroup1.class)
	@Length(min = 3, max = 20, groups = ValidGroup2.class)
	@Pattern(regexp = "^[a-zA-Z0-9]+$", groups = ValidGroup2.class)
	private String password;

}

■エラーメッセージ

messages.properties
#バリデーションエラーメッセージ
signupForm.userId=ユーザーID
NotBlank.signupForm.userId={0}を入力してください
Length.signupForm.userId={0}は、{2}字以上{1}字以下で入力してください

signupForm.mailAddress=メールアドレス
NotBlank.signupForm.mailAddress={0}を入力してください
Email.signupForm.mailAddress=メールアドレス形式で入力してください

signupForm.password=パスワード
NotBlank.signupForm.password={0}を入力してください
Length.signupForm.password={0}は、{2}字以上{1}字以下で入力してください
Pattern.signupForm.password={0}は半角英数字で入力してください

searchForm.keyword=キーワード
NotBlank.searchForm.keyword={0}を入力してください

#ログインエラーメッセージをカスタマイズ
AbstractUserDetailsAuthenticationProvider.badCredentials=ログインIDまたはパスワードが間違っています。

②入力フォームの作成(修正前)

当初、下記のように入力フォームのhtmlを作成しました。

signup.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	  xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout/template}">
<head>
	<meta charset="UTF-8"></meta>
    <title>SignUp</title>

</head>
<!-- ユーザー登録画面 -->
<body>
    <div layout:fragment="content">
		<div class="col-sm-4 offset-sm-4">
			<div class="page-header">
				<h1>ユーザー登録画面</h1>
			</div>
			<form method="post" th:action="@{/signupUser}" th:object="${signupForm}">

				<table class="table table-bordered table-hover">
				<tr>
					<td> <!-- modelオブジェクト「signupForm」の「userId」フィールドでエラーが発生したら、class属性に「has-error」を追加し、テキストボックスの周りを赤くする
-->
						<div class="form-group" th:classappend="${#fields.hasErrors('userId')}?'has-error'">
							<input type="text" class="form-control" placeholder="ログインID" th:field="*{userId}"/>
							<span class="text-danger"
								th:if="${#fields.hasErrors('userId')}"
								th:errors="*{userId}">
								userId error
							</span>
						</div>
					</td>
				<tr>
				<tr>
					<td> <!-- modelオブジェクト「signupForm」の「mailAddress」フィールドでエラーが発生したら、class属性に「has-error」を追加し、テキストボックスの周りを赤くする
-->
						<div class="form-group"
							th:classappend="${#fields.hasErrors('mailAddress')}?'has-error'">
							<input type="text" class="form-control" placeholder="メールアドレス" th:field="*{mailAddress}"/>
							<span class="text-danger"
								th:if="${#fields.hasErrors('mailAddress')}"
								th:errors="*{mailAddress}">
								mailAddress error
							</span>
						</div>
					</td>
				<tr>
				<tr>
					<td> <!-- modelオブジェクト「signupForm」の「password」フィールドでエラーが発生したら、class属性に「has-error」を追加し、テキストボックスの周りを赤くする
-->
						<div class="form-group"
							th:classappend="${#fields.hasErrors('password')}?'has-errors'">
							<input type="text" class="form-control" placeholder="パスワード" th:field="*{password}"/>
							<span class="text-danger"
								th:if="${#fields.hasErrors('password')}"
								th:errors="*{password}">
								password error
							</span>
						</div>
					</td>
				<tr>
				</table>
				<button class="btn btn-primary col-sm-6" type="submit">新規登録</button>
			</form>
		</div>
	</div>
</body>
</html>

html内のコメントでも記述しているように、各フィールドでエラーが発生したら、テキストボックスの枠が赤くなるよう記述したのですが、結果は下の通り枠は赤くはなりませんでした。

ちなみに「has-error」はBootstrapのclassでテキストボックスの枠を赤くしてくれるものです。

スクリーンショット 2020-10-21 13.00.49.png

「Bootstrap4移行ガイド」を確認すると下記のような記述がありました。

【Bootstrap3.xとの変更箇所】
各検証状態の表示スタイルからHTML5フォーム検証機能を使用したスタイルに変更
.has-warning, .has-error, .has-success, .has-feedback, .form-control-feedback は廃止
フォールバックとして、.is-invalid クラスと .is-valid クラスをサーバー側の検証用の疑似クラスの代わりに使用可能。.was-validated 親クラスは必要ない。

URL:https://bootstrap-guide.com/components/forms?

Bootstrap4以降「has-error」は廃止、代わりに「is-invalid」が機能として提供されているようです。

③入力フォームの修正

divタグ内ではなく、inputタグの中に記述します。

signup.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	  xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout/template}">
<head>
	<meta charset="UTF-8"></meta>
    <title>SignUp</title>

</head>
<!-- ユーザー登録画面 -->
<body>
    <div layout:fragment="content">
		<div class="col-sm-4 offset-sm-4">
			<div class="page-header">
				<h1>ユーザー登録画面</h1>
			</div>
			<form method="post" th:action="@{/signupUser}" th:object="${signupForm}">

				<table class="table table-bordered table-hover">
				<tr>
					<td>
						<div class="form-group">
							<!-- modelオブジェクト「signupForm」の「userId」フィールドでエラーが発生したら、class属性を追加し「is-invalid」でテキストボックスの周りを赤くする-->
							<input type="text" class="form-control" placeholder="ログインID" th:field="*{userId}"
							th:classappend="${#fields.hasErrors('userId')}?'is-invalid'"/>
							<span class="text-danger"
								th:if="${#fields.hasErrors('userId')}"
								th:errors="*{userId}">
								userId error
							</span>
						</div>
					</td>
				<tr>
				<tr>
					<td>
						<div class="form-group">
							<!-- modelオブジェクト「signupForm」の「mailAddress」フィールドでエラーが発生したら、class属性を追加し「is-invalid」でテキストボックスの周りを赤くする-->
							<input type="text" class="form-control" placeholder="メールアドレス" th:field="*{mailAddress}"
							th:classappend="${#fields.hasErrors('mailAddress')}?'is-invalid'"/>
							<span class="text-danger"
								th:if="${#fields.hasErrors('mailAddress')}"
								th:errors="*{mailAddress}">
								mailAddress error
							</span>
						</div>
					</td>
				<tr>
				<tr>
					<td>
						<div class="form-group">
							<!-- modelオブジェクト「signupForm」の「password」フィールドでエラーが発生したら、class属性を追加し「is-invalid」でテキストボックスの周りを赤くする-->
							<input type="text" class="form-control" placeholder="パスワード" th:field="*{password}"
							th:classappend="${#fields.hasErrors('password')}?'is-invalid'"/>
							<span class="text-danger"
								th:if="${#fields.hasErrors('password')}"
								th:errors="*{password}">
								password error
							</span>
						</div>
					</td>
				<tr>
				</table>
				<button class="btn btn-primary col-sm-6" type="submit">新規登録</button>
			</form>
		</div>
	</div>
</body>
</html>

実行すると下のように、入力エラー時テキストボックスの枠を赤くすることができました。

スクリーンショット 2020-10-21 13.28.10.png

参考:
https://www.e-pokke.com/blog/bootstrap4-invalid-feedback.html
https://learning-collection.com/thymeleaf%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9/

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?