@MOhshima

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Javascriptのfor文とテーブルのコードミスについて

解決したいこと

ここに解決したい内容を記載してください。

javascriptでHTMLに5行2列のテーブルを作ります。
既にtableタグid=tbl

の部分は作ってありまして、
その下にを4行入れていくものです。
その際1列目のにはselectを、2列目のにはinputをそれぞれ同じ内容で入れて4行作りたいのですが、下のコードを試すと最初の3行はtdの中が空っぽで最終行だけ入っています。
何がいけないのか教えて欲しいのです。

###コード
(HTML)

商品選択 注文数

var Arr = ['商品を選んで下さい','商品A','商品B','商品C'];
var slc = document.createElement('select');
Arr.forEach((item)=>{
var op = document.createElement('option');
op.text=item;
slc.add(op);
});
var tbl = document.getElementById('tbl');
var inp = document.createElement('input');
inp.type='tel';
inp.placeholder = '注文数を『単位』で入力';

for(var rw=1;rw<5;rw++){console.log(rw);
var tr = document.createElement('tr');
var td = document.createElement('td');
td.appendChild(slc);
tr.appendChild(td);
var td = document.createElement('td');
td.appendChild(inp);
tr.appendChild(td);
tbl.appendChild(tr);
}

自分で試したこと

順番を入れ替えたりしたのですが全然だめでした。

0 likes

2Answer

指定された子ノードが文書内の既存のノードへの参照である場合、 appendChild() はそのノードを現在の位置から新しい位置に移動させます。つまり、あるノードが文書内の2点に同時に存在することはできません。新しい親の下にノードを追加する前に、ノードのコピーを作成するには Node.cloneNode() メソッドを使用することができます。

ということなので、appendChildに追加する要素は事前に cloneNode() しましょう

https://developer.mozilla.org/ja/docs/Web/API/Node/cloneNode
slcは子要素を持つので cloneNode(true) にする必要があります

for(var rw=1;rw<5;rw++){
    console.log(rw);
    var tr = document.createElement('tr');
    var td = document.createElement('td');
    td.appendChild(slc.cloneNode(true));
    tr.appendChild(td);
    var td = document.createElement('td');
    td.appendChild(inp.cloneNode());
    tr.appendChild(td);
    tbl.appendChild(tr);
}

See the Pen Untitled by amate (@amate-the-vuer) on CodePen.

0Like

Markdownでコードはブロック内に正しく書いてください。非常に見にくいです。

2点押さえておきたいところがあります。

まず、createElementで作られたエレメントは使い回しが効きません。コレが原因の1つです(cloneNodeでもアリですが、idなどの様々な重複事故を未然に防ぐという意味でおすすめしません)。

<table>タグ内は本来、<thead><tbody>が必要ですが、これらの記載を省略するとブラウザが勝手に追加してくれます。この時点で追加されない要因の、もう1つの原因を作っています。

https://developer.mozilla.org/ja/docs/Web/HTML/Reference/Elements/thead
https://developer.mozilla.org/ja/docs/Web/HTML/Reference/Elements/tbody

そして、<tbody>の件(勝手に作られる)が絡んでくると、JSの最後のtbl.appendChild(tr);のアプローチが間違っています。

document.getElementById('tbl')はidがtblとなっているテーブルエレメントを返すので変数tblHTMLTableElementに化けます。

このHTMLTableElementにはtBodiesというプロパティを持っているので、最初の0個目(<tbody>は複数の記載が認められるため)を指定してからappendChildしなければなりません。つまり

tbl.tBodies.item(0).appendChild(tr);

となります。

そういったトラブルを少なくするにはHTML側も正しく記載する必要があります。

<div id="main">
	<table id="tbl">
		<thead>
			<tr>
				<th>商品選択</th><th>注文数</th>
			</tr>
		</thead>
		<tbody>
		</tbody>
	</table>
</div>

手直しするとこういう感じにはなります。

See the Pen Untitled by えむ a.k.a. STSynthe (@stsynthe) on CodePen.

const itemList = [
	'商品を選んで下さい',
	'商品A',
	'商品B',
	'商品C'
];

const createSelectElement = () => {
	const select = document.createElement('select');
	for (const text of itemList) {
		const option = document.createElement('option');
		option.text = text;
		select.add(option);
	}
	return select;
};

const createInputElement = () => {
	const input = document.createElement('input');
	input.type = 'tel';
	input.placeholder = '注文数を『単位』で入力';
	return input;
};

const tbl = document.getElementById('tbl');

for (let i = 0; i <= 4; i++) {
	const tr = document.createElement('tr');
	const tdLeft = document.createElement('td');
	const tdRight = document.createElement('td');

	tdLeft.appendChild(createSelectElement());
	tdRight.appendChild(createInputElement());

	tr.appendChild(tdLeft);
	tr.appendChild(tdRight);

	tbl.tBodies.item(0).appendChild(tr);
}

あと、変数宣言にvarの使用はできるだけ避けるべきです(事故の元になりやすい)。

0Like

Your answer might help someone💌