割り勘額を計算してくれる簡易Webアプリを作成中に学習したことを書き留めておく。
当方、初学者のため記事の内容に間違いや改善点などございましたら、ぜひコメントでご指摘ください。
#要件
「追加」ボタンをクリックし、名前、年齢、性別を入力するフォームを複製したい。(最大8人)
⇓
##フォームのHTML
フォームから値を受け取って計算をする予定なので、inputタグのname属性にインデント番号を付与し、
複製するタイミングで1ずつ足していく。
<!DOCTYPE HTML>
<html lang="ja">
<head>
<meta charset="utf-8">
<script type="text/javascript" src="addForm.js"></script>
</head>
<body>
<div class="input-form" id="input-form">
<div class="member" id="member">
<!--入力した値を計算したいのでname属性にインデント番号を付与-->
<input type="text" size="20" name="name-1" placeholder="名前">
<input type="text" size="3" name="age-1" placeholder="年齢">
<label for="male">
<input type="radio" value="男性" id="male">男性
</label>
<label for="female">
<input type="radio" value="女性" id="female">女性
</label>
</div>
</div>
<div class="bt_addForm">
<!--ボタンをクリックしたらJavascriptファイル内の関数addForm()を実行する-->
<input type="button" value="追加" onclick="addForm()">
</div>
</body>
</html>
#createElement()を使って要素を複製
##createElement()とは
JavaScript で HTML 要素を複製するメソッド。引数にtrueを指定すれば、子ノードごと複製できる。
//複製する要素を取得
const element = document.getElementById("id");
//要素を複製
const newelement = element.cloneNode(true);
##実装
// cloneNodeで要素を複製し、追加する
//インデント番号を設定
let i = 2
function addForm() {
// 8人以上なら処理を終了する
if (i > 8) {
return true;
} else {
// 複製するHTML要素を取得
const element = document.getElementById("member");
// 要素を複製
const newelement = element.cloneNode(true);
// 子要素を指定しname属性の値を変更
const newelement_name = newelement.children[0];
newelement_name.name = 'name-'+i;
const newelement_age = newelement.children[1];
newelement_age.name = 'age-'+i;
//親要素を取得し 複製した要素を追加
const parent = document.getElementById("input-form");
parent.appendChild(newelement);
//インデント番号を更新
i++;
}
}
#まとめ
当初はcreateElement()で一つずつ要素を作成し、DOMを組み上げてからHTMLに追加する方法をとっていたが、その方法ではコードが冗長になる上に、複製したい要素に変更が加わった場合Jsファイルも書き換えなければいけなくなる。
一方、cloneNode()を使用した場合は元のHTML要素を構造を保ったまま複製し、必要な部分だけ書き換えればよいので、書くコードが短くなり、複製したい要素に変更を加えた場合もJsファイルをほとんどいじらなくてよい。
###※(2021年12月24日追記)
上記コードは一番最初のフォームをそのままcloneNode()で複製する処理になっているので、最上部のフォームにテキストを入力してから「追加」ボタンを押した場合、追加されたフォームにも入力したテキストが入ってしまう。
複製したフォームを関数内で初期化してから追加してもよいが、それだと無駄な処理が増えてしまいそう。
なので、HTMLのtemplateタグを使用して初期化されたフォームのテンプレートを作成し、それを複製、追加する方法に書き換えました。
templateタグを使ってフォームを複製