[JavaScript] ボタン押下で動的に要素をコピーし追加(ラジオボタン)

投稿者: | 2021年2月14日

前々回の記事で、JavaScriptを用いて動的に要素をコピーし追加する方法について書き、

前回の記事で、セレクトメニューの場合は一工夫必要であることに触れましたが

単純に要素をコピーするだけだと、ラジオボタンの場合も上手くいきません。

ラジオボタンで値を選択し、その状態で要素を追加しても

このように、ラジオボタンの場合は、値がおかしなことになってしまいます。

一行目のラジオボタンの選択が、消えてしまっていることがわかりますね。

これは、ラジオボタンのグルーピングで使用している name 属性までが、コピーされているために起こる事象です。

同じ name 属性を持っているタグが4つできてしまうために、グルーピングがおかしくなってしまうのですね。

(もちろん、行を追加していく度に、同じ name 属性を持つタグは、6つ、8つ、・・・と増えていきます)

この問題を回避する方法は幾つかありますが、今回は name 属性を動的に変更することで対処していきます。

ラジオボタン要素の作成

まずコピー対象のラジオボタン要素の作成です。

既に上で登場していますが、このようにhtmlを記述していきます。

<input type="radio" name="yn" value="Yes" checked="checked">Yes
<input type="radio" name="yn" value="No" >No

name 属性を “yn” としています。要素をコピーするときには、この値を変更していきます。

name属性の変更

name属性の変更は単純に、1ずつ増加する数字を追加することで対応します。

追加用数字の変数を一つ定義しておき、要素コピーの関数が呼び出される都度インクリメントしたうえで、setAttribute メソッドにより name 属性にセットします。

let cnt = 1; // 追加用数字の変数を定義
(中略)

function addExample() {
  ++cnt; // 追加用数字をインクリメント

  // 要素をコピー
  let elements = document.getElementById("target");
  let copied = elements.lastElementChild.cloneNode(true);
    
  // コピー先ラジオボタンのname属性を変更
  copied.children[3].setAttribute("name", "yn" + cnt);
  copied.children[4].setAttribute("name", "yn" + cnt);
  
  elements.appendChild(copied);
}

children[] で、指定した子要素を取得できます。今回は2つあるラジオボタンが各々4番目と5番目の子要素なので、配列の指定値としては3と4を設定しています。

サンプルコード

動作確認用の全体のサンプルコードはこんな感じ。

前回の記事で入れた、セレクトメニューの値コピーも含まれたコードです。)

<html>
	<head>
	</head>
	<body>
		<button id="add">Add!</button>
		
		<div id="target">
			<div>
				<select>
					<option>A</option>
					<option>B</option>
					<option>C</option>
				</select>
				<input type="text">
				<input type="checkbox">
				<input type="radio" name="yn" value="Yes" checked="checked">Yes
				<input type="radio" name="yn" value="No" >No
				<button>here</button>
			</div>
		</div>
		
		<script type="text/javascript">
			let cnt = 1;
			const btn = document.getElementById("add");
			
			function addExample() {
				++cnt;
				let elements = document.getElementById("target");
				let copied = elements.lastElementChild.cloneNode(true);
				
				// セレクトメニューの値をコピー
				let val = elements.lastElementChild.firstElementChild.selectedIndex;
				copied.firstElementChild.selectedIndex = val;
				
				// コピー先ラジオボタンのname属性を編集
				copied.children[3].setAttribute("name", "yn" + cnt);
				copied.children[4].setAttribute("name", "yn" + cnt);
				
				elements.appendChild(copied);
			}
			
			btn.addEventListener("click", addExample, false);
			
		</script>
	</body>
</html>

動作確認

これまでの処理を追加することで、選択したラジオボタンの値も

前要素に影響を及ぼすことなく、コピーすることができました。

要素をタグで確認すると、確かに name 属性が変更されていることが分かります。