フォームを作っていると、すべての必須項目を入力してから完了ボタンを押すように実装することが多い。
しかし入力フォームが空か否かの判定だけを行ってしまうと、フォームにフォーカスを充てている時(入力中のとき)はイベントは発火することはできない。
つまり入力フォームに文字が入った瞬間に判定することはできず、ユーザーは入力、フォームからフォーカスを外す(どこか適当にクリック)というワンテンポ面倒なステップを踏むことになるのだ。
今回はその問題を解決する方法をメモとして残しておく。要件と完成イメージは下記の通りだ。
- ①4項目あるinput(textarea含む)を全部入力したら送信ボタンを活性化+クリック可能にする
②入力欄に文字を入力した瞬間に判定を行う(ここ重要)
③一個でも入力欄が空になったら再びボタンを非活性
See the Pen Untitled by Tomizawa (@masaya_coding) on CodePen.
Table of Contents
HTML
HTMLはごく一般的なformタグを用いた書き方で行う。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<script src="https://t-creative-works.com/js/jquery-3.5.0.min.js"></script>
</head>
<body>
<form action="">
<div class="form_in">
<label>
<span>タイトル</span>
<input name="title" type="text" value="" required="" placeholder="タイトル" id="name01">
</label>
<label>
<span>日付</span>
<input name="date" type="date" value="" required="" id="name02">
</label>
<label>
<span>備考</span>
<input name="caution" type="text" value="" required="" placeholder="備考" id="name03">
</label>
</div>
<label>
<span>本文</span>
<textarea name="text" required="" id="name04"></textarea>
</label>
<button type="submit">保存</button>
</form>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
念頭に置いといてもらいたい事としては、各input要素に割り振られて「id=”」だ。これは後ほどJSでも使うことになる。
CSS
CSSは特に凝る必要はないが、入力フォームが全て埋まったらbuttonタグに「active」というクラスが付与される予定なので、分かりやすいように色付けをしている。
form label {
margin-bottom: 40px;
display: block;
}
.active {
color: #fff;
background-color: #0067c0;
}
JS
ここからはJSの処理を書いていくが、まずは全体像としては下記のようなコードとなる。
const $submitBtn = $('button'); //変数にボタン要素をセット
$submitBtn.prop('disabled', true); //ボタンは最初はdisabledでクリックできない状態に
var name01 = document.querySelector("#name01"); //それぞれの入力フォームを変数化
var name02 = document.querySelector("#name02");
var name03 = document.querySelector("#name03");
var name04 = document.querySelector("#name04");
//「もし各入力欄が空だったら」という内容を関数としてセット
function judge() {
if (
$(name01).val() !== "" &&
$(name02).val() !== "" &&
$(name03).val() !== "" &&
$(name04).val() !== ""
) {
$submitBtn.prop('disabled', false); //空じゃなかったらボタンを活性化し、activeクラスをつける
$submitBtn.addClass('active');
} else {
$submitBtn.prop('disabled', true);
$submitBtn.removeClass('active');
}
}
//先ほどの関数をここで使いまわす
name01.addEventListener("input", function() { //第一引数にイベントの種類としてchangeではなくinputを記述
judge();
});
name02.addEventListener("input", function() {
judge();
});
name03.addEventListener("input", function() {
judge();
});
name04.addEventListener("input", function() {
judge();
});
$submitBtn.click(function() {
alert("完了!");
});
分かりやすいように、上記のコードを小分けにして解説したいと思う。
ボタンと各フォームを変数に変更
ここでは各フォーム要素、ボタンを変数として格納し、ボタンにはdisbledを掛けてクリックできないようにしておく。
const $submitBtn = $('button');
$submitBtn.prop('disabled', true);
var name01 = document.querySelector("#name01");
var name02 = document.querySelector("#name02");
var name03 = document.querySelector("#name03");
var name04 = document.querySelector("#name04");
要素内に文字があるか否かの判定
function judge() {
if (
$(name01).val() !== "" &&
$(name02).val() !== "" &&
$(name03).val() !== "" &&
$(name04).val() !== ""
) {
$submitBtn.prop('disabled', false);
$submitBtn.addClass('active');
} else {
$submitBtn.prop('disabled', true);
$submitBtn.removeClass('active');
}
}
もし変数の中身(input)が空じゃなかったらというif文を作り、trueならボタンにactiveクラスをつけてdisableも取り除く。
「addEventListnere」で変更されたら即時反映
先ほどinputが空か否かの判定を作ったが、それらにイベントが発生(文字が入力されたとき)に発火させていく。
name01.addEventListener("input", function() {
judge();
});
name02.addEventListener("input", function() {
judge();
});
name03.addEventListener("input", function() {
judge();
});
name04.addEventListener("input", function() {
judge();
});
$submitBtn.click(function() {
alert("完了!");
});
この部分は説明することが多いので、まとめると下記のような解釈となる
- ①inputとtextareaが格納されているname01~name04の変数一つ一つに「addEventListener」というメソッドを使う
- ②先ほどのif文をまとめた関数「judge();」を呼び出す
- ③name~の全てのジャッジが完了するとボタンのdisabledも消えるので、「alert(“完了!”);」を表示できる
繰り返しになるが、「addEventListener」は入力、クリックなど様々なイベント処理に使うことができる。
「addEventListnere」ではなく「onchange」を使うとどうなる?
冒頭でも伝えた通り、今回はフォームに文字が入った瞬間に判定を行い、ボタンをactive状態にするという処理が目的だ。
これをもしonchangeで行うと「入力した後に入力欄以外の箇所をクリックしてフォーカスを外さなければならい」という重大な欠点に遭遇した。
See the Pen onchangeでのフォーム判定 by Tomizawa (@masaya_coding) on CodePen.
上記のようにaddEventListnereを使わない場合、全てのフォームを埋める+フォームからフォーカスを外す必要があるので注意が必要だ。