WordPressのCustom Fieldのような、ユーザーが自分でinput要素を追加したり削除したりできるフォームのUIを、Vanilla JSで作る方法です。
input要素が1つしかない場合は削除できないようにします。
HTML
HTMLには一般的なフォームを設置。ポイントは、
- input要素はユーザーが追加・削除するので、全て
name=content[]
のように同じname属性を設定しておいて、POSTした先で配列として受け取り処理します。 - input要素とそれを削除するボタンをセットにして、
<tr class="inputField">
でマークアップ。 - JavaScript側でこのtr要素を追加・削除できるように、親要素のtable要素に
inputFields
クラスを付与しておく。
の3点です。
<form method="POST" action="/">
<table class="inputFields">
<tr class="inputField">
<th>
<input type="text" name="content[]" placeholder="バリュー"></th>
<td>
<!--input要素を削除するボタン-->
<button class="deleteFieldBtn">入力欄を削除</button></td>
</tr>
</table>
<!--input要素を追加するボタン-->
<button class="addFieldBtn">入力欄を追加</button>
<input type="submit" name="submit" value="送信">
</form>
JavaScript
イベントリスナーで、form上で起こる全てのclickイベントを監視し、
- クリックされた要素に
addFieldBtn
クラスが含まれていた場合は、input要素をDOMに追加 - クリックされた要素に
deleteFieldBtn
クラスが含まれていた場合、親要素ごとDOMから削除
という形で条件分岐します。
//イベントリスナーでform上の全てのclickイベントを監視する
document.forms[0].addEventListener("click", function (e) {
var inputFielsContainer = e.target.parentNode.querySelector(".inputFields");
// クリックされた要素に、addFieldBtnが含まれていたら
if (e.target.classList.contains("addFieldBtn")) {
e.preventDefault();
var field = document.createElement("tr");
field.classList.add("inputField");
field.innerHTML = `
<th><input type="text" name="content[]" placeholder="バリュー"></th>
<td><button class="deleteFieldBtn">入力欄を削除</button></td>
`;
var clone = field.cloneNode(true);
inputFielsContainer.appendChild(clone);
}
// クリックされた要素に、deleteFieldBtnクラスが含まれていたら
else if (e.target.classList.contains("deleteFieldBtn")) {
e.preventDefault();
var deleteFieldBtns = document.querySelectorAll(".deleteFieldBtn");
//deleteFieldBtクラスを持つ要素がDOM上に1つしかない場合は削除できないようにする
if(deleteFieldBtns.length == 1){
alert("入力欄は最低1つ必要です");
return;
}else{
var field = e.target.parentNode.parentNode;
field.remove();
}
}
});
//エンターキー押下でinput要素が追加されないようにする
document.addEventListener("keypress", function (e) {
if (e.key === "Enter") {
e.preventDefault();
}
});
e.target.classList.contains("hoge")
で、クリックイベントが発生した要素が、hoge
というクラスを持っているか否かを判別できます。要素を追加する場合はinnerHTML
で、削除する場合はremove()
で親要素ごと削除します。
ここで重要なのが、各条件分岐の中のe.preventDefault();
で、これは、クリックイベントが伝播して、入力欄の追加/削除ボタンが押された際に、フォームの送信ボタンも一緒にクリックされないようにするために必要です。
試しに条件分岐の中の2つのe.preventDefault();
をコメントアウトしてフォームを実行してみると、イベントが伝播して送信ボタンも押されてしまうのが分かります。
コードの末尾にある、
document.addEventListener("keypress", function (e) {
if (e.key === "Enter") {
e.preventDefault();
}
});
も同様に、エンターキーが押された時にイベントが伝播して、勝手にinput要素が増えないようにするために必要です。
完成形のコードはこちら
https://codepen.io/outsider-kithy/details/OJGeKve