\r\n\r\n\r\n\r\n\r\n\r\n(javascript)\r\n\r\n\r\n'use strict'\r\n\r\nlet add = document.getElementById(\"add\");\r\n\r\nadd.addEventListener(\"click\", function(){\r\n\r\n let tbody = document.getElementById(\"addlist\");\r\n\r\n let tr = tbody.firstElementChild.cloneNode(\"true\");\r\n\r\n tbody.insertBefore(tr, tbody.lastChild)\r\n})\r\n\r\n\r\n\r\n\r\nlet remove = document.getElementById(\"remove\");\r\n\r\nremove.addEventListener(\"click\", function(){\r\n\r\n let tbody = document.getElementById(\"addlist\");\r\n\r\n let tr = remove.parentNode.parentNode;\r\n\r\n tbody.removeChild(tr);\r\n})","answerCount":2,"upvoteCount":0,"datePublished":"2019-11-23T00:46:29.584Z","dateModified":"2019-11-23T00:46:29.584Z","acceptedAnswer":{"@type":"Answer","text":"複製した行の削除ボタンに削除用のイベントハンドラが設定されていないからです。\r\n追加するたびに毎回ハンドラを設定してもいいですが、こういう場合、要素を先祖方向に遡って、追加や削除されない不動の要素(tbodyやtable、bodyなど)にイベントを設定するとよいと思います。([イベントデリゲーション](https://developer.mozilla.org/ja/docs/Web/API/Event/target#Example))\r\n\r\n具体的には以下の部分を…\r\n```JavaScript\r\nlet remove = document.getElementById(\"remove\");\r\n\r\nremove.addEventListener(\"click\", function() {\r\n let tbody = document.getElementById(\"addlist\");\r\n let tr = remove.parentNode.parentNode;\r\n tbody.removeChild(tr);\r\n});\r\n```\r\n以下のコードに書き換えれば動きます。\r\n```JavaScript\r\naddlist.addEventListener(\"click\", function() {\r\n if (event.target.id === 'remove') {\r\n let tr = event.target.parentNode.parentNode;\r\n this.removeChild(tr); \r\n }\r\n});\r\n```\r\n本来複数の要素が同じidを持つのは良くないので、そこは今後見直したほうがよいと思います。","dateModified":"2019-11-23T02:10:45.543Z","datePublished":"2019-11-23T02:10:45.543Z","upvoteCount":3,"url":"https://teratail.com/questions/224961#reply-329139"},"suggestedAnswer":[{"@type":"Answer","text":"こんにちは\r\n\r\n\r\nご質問に挙げられているコードを、意図した動作をするものに修正するにあたって留意すべき点は、[cloneNodeの説明](https://developer.mozilla.org/ja/docs/Web/API/Node/cloneNode)に書かれている、以下の2点、\r\n\r\n> 注記\r\nノードを複製すると、そのノードのすべての属性とその値がコピーされます。つまり、HTML属性のイベントを含みます。addEventListener() を使用したものや、要素のプロパティに代入されたもの (例: node.onclick = fn;) は複製されません。 \r\n\r\nと、\r\n\r\n> 注意: cloneNode() を使用すると、ドキュメント内で要素の id が重複する可能性があります。\r\n\r\n\r\nです。これらに沿って修正点としては、以下の2点になります。\r\n\r\n(1) 新しい行に含まれる削除ボタンクリック時の処理のための修正。これは以下の2つのいずれかが考えられます。\r\n- A: 行が追加される時点のその都度、新しい行に含まれる削除ボタンのクリックハンドラを設定する。\r\n- B: 行の追加、削除の影響を受けない、上位階層の要素にクリックハンドラを設定して、event.target が削除ボタンだったときに、行削除を行うようにする。\r\n\r\n(2) 現状、`\"remove\"` が削除ボタンのidになっているのをclassに変更\r\n\r\n\r\n以下は上記の修正点を反映したコード例です。以下では、上記の(1)については、 A のほうを採用して、削除ボタンに設定するクリックハンドラを個別の関数にしています。\r\n\r\n```html\r\n\r\n```\r\n```javascript\r\ndocument.addEventListener('DOMContentLoaded', function() {\r\n\r\n let addCount = 0; // 追加行カウンタ\r\n \r\n function removeRow(event) {\r\n const tr = event.target.parentNode.parentNode; \r\n const tbody = document.getElementById(\"addlist\");\r\n tbody.removeChild(tr);\r\n }\r\n \r\n const add = document.getElementById(\"add\");\r\n\r\n add.addEventListener(\"click\", function() {\r\n const tbody = document.getElementById(\"addlist\");\r\n const tr = tbody.firstElementChild.cloneNode(true);\r\n tbody.insertBefore(tr, tbody.lastChild);\r\n \r\n const remove = tr.querySelector(\".remove\");\r\n remove.addEventListener(\"click\", removeRow);\r\n \r\n // 追加された行の左端のtdに追加行番号を入れる。\r\n tr.querySelector(\"td\").textContent = ++addCount;\r\n })\r\n\r\n const remove = document.querySelector(\".remove\");\r\n remove.addEventListener(\"click\", removeRow);\r\n\r\n});\r\n```\r\n- **動作確認用CodePen: **[https://codepen.io/jun68ykt/pen/pooBOWv?editors=1010](https://codepen.io/jun68ykt/pen/pooBOWv?editors=1010)\r\n\r\nなお、上記では、補足として以下の2点も修正、追加しています。\r\n\r\n- `let` にする必要のない変数は `const`にしています。\r\n- 追加された行の左端の``に追加行番号を入れる。(※これは、削除ボタンがクリックされたときに、そのボタンを含む行が削除されるのを、目視で確認できるようにするためです)\r\n\r\n以上、参考になれば幸いです。\r\n\r\n### 備考\r\n上記の回答に書いた、修正点(1) の\r\n\r\n\r\n- B: 行の追加、削除の影響を受けない、上位階層の要素にクリックハンドラを設定して、event.target が削除ボタンだったときに、行削除を行うようにする。\r\n\r\n\r\nについては、shinji709さんが分かり易いご回答を書かれていますので、そちらを参考にされてください。","dateModified":"2019-11-23T02:29:52.013Z","datePublished":"2019-11-23T01:34:08.005Z","upvoteCount":3,"url":"https://teratail.com/questions/224961#reply-329134","comment":[{"@type":"Comment","text":"clonenodeの説明を挙げてくれるなど、とても勉強になりました。次回これらのメソッドの使用する時に気をつけたいと思います。ありがとうございました。","datePublished":"2019-11-23T02:29:26.200Z","dateModified":"2019-11-23T02:29:26.200Z"},{"@type":"Comment","text":"また\r\nlet にする必要のない変数は constにしています。\r\n追加された行の左端のに追加行番号を入れる。(※これは、削除ボタンがクリックされたときに、そのボタンを含む行が削除されるのを、目視で確認できるようにするためです)\r\nこの辺気を付けます。本当に参考になりました。\r\nありがとうございました!","datePublished":"2019-11-23T02:46:43.131Z","dateModified":"2019-11-23T02:46:43.131Z"},{"@type":"Comment","text":"どういたしまして。解決したようでよかったです????","datePublished":"2019-11-23T02:46:58.146Z","dateModified":"2019-11-23T02:46:58.146Z"}]}],"breadcrumb":{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"トップ","url":"https://teratail.com"},{"@type":"ListItem","position":2,"name":"JavaScriptに関する質問","url":"https://teratail.com/tags/JavaScript"},{"@type":"ListItem","position":3,"name":"JavaScript","url":"https://teratail.com/tags/JavaScript"}]}}}
質問するログイン新規登録
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

2回答

2790閲覧

javascriptで行と列の複製と削除

HO.

総合スコア5

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2019/11/23 00:46

0

0

javascriptでエクセルみたいなユーザーが打ち込める行列を作成しています。
1行目で右端に追加ボタンで行を生成、各行の右端のセルで自身の行を削除というような機能を持たせたくて以下のようなプログラムにしましたが追加は動きますが、最初の行しかできません。
考えとしては、複成した行は、削除できない事から複成が上手くいっていないのかなと思いますが、解決策がわかりません。どうぞよろしくお願いします。

(html)

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> </head> <body> <table border="1"> <thead> <tr> <td>1</td> <td>2</td> <td>3</td> <td>4</td> <td>5</td> <td>6</td> <td>7</td> <td>8</td> <td>9</td> <td>10</td> <td><input type="button" value="追加" id="add"></td> </td> </tr> </thead> <tbody contenteditable="true" id="addlist"> <tr> <td></td> <td></td> <td></td> <td></td> <td></td> <td></td> <td></td> <td></td> <td></td> <td></td> <td> <input type="button" value="削除" id="remove"> </td> </tr> </tbody> </table> <script src="js/test.js"></script> </body> </html>

(javascript)

'use strict'

let add = document.getElementById("add");

add.addEventListener("click", function(){

let tbody = document.getElementById("addlist"); let tr = tbody.firstElementChild.cloneNode("true"); tbody.insertBefore(tr, tbody.lastChild)

})

let remove = document.getElementById("remove");

remove.addEventListener("click", function(){

let tbody = document.getElementById("addlist"); let tr = remove.parentNode.parentNode; tbody.removeChild(tr);

})

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

複製した行の削除ボタンに削除用のイベントハンドラが設定されていないからです。
追加するたびに毎回ハンドラを設定してもいいですが、こういう場合、要素を先祖方向に遡って、追加や削除されない不動の要素(tbodyやtable、bodyなど)にイベントを設定するとよいと思います。(イベントデリゲーション

具体的には以下の部分を…

JavaScript

1let remove = document.getElementById("remove"); 2 3remove.addEventListener("click", function() { 4 let tbody = document.getElementById("addlist"); 5 let tr = remove.parentNode.parentNode; 6 tbody.removeChild(tr); 7});

以下のコードに書き換えれば動きます。

JavaScript

1addlist.addEventListener("click", function() { 2 if (event.target.id === 'remove') { 3 let tr = event.target.parentNode.parentNode; 4 this.removeChild(tr); 5 } 6});

本来複数の要素が同じidを持つのは良くないので、そこは今後見直したほうがよいと思います。

投稿2019/11/23 02:10

shinji709

総合スコア805

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

HO.

2019/11/23 02:34

めちゃめちゃすっきりとしたコードとと解説をありがとうございます。また 本来複数の要素が同じidを持つのは良くないので、そこは今後見直したほうがよいと思います。 気を付けます。ありがとうございました!
guest

0

こんにちは

ご質問に挙げられているコードを、意図した動作をするものに修正するにあたって留意すべき点は、cloneNodeの説明に書かれている、以下の2点、

注記
ノードを複製すると、そのノードのすべての属性とその値がコピーされます。つまり、HTML属性のイベントを含みます。addEventListener() を使用したものや、要素のプロパティに代入されたもの (例: node.onclick = fn;) は複製されません。

と、

注意: cloneNode() を使用すると、ドキュメント内で要素の id が重複する可能性があります。

です。これらに沿って修正点としては、以下の2点になります。

(1) 新しい行に含まれる削除ボタンクリック時の処理のための修正。これは以下の2つのいずれかが考えられます。

  • A: 行が追加される時点のその都度、新しい行に含まれる削除ボタンのクリックハンドラを設定する。
  • B: 行の追加、削除の影響を受けない、上位階層の要素にクリックハンドラを設定して、event.target が削除ボタンだったときに、行削除を行うようにする。

(2) 現状、"remove" が削除ボタンのidになっているのをclassに変更

以下は上記の修正点を反映したコード例です。以下では、上記の(1)については、 A のほうを採用して、削除ボタンに設定するクリックハンドラを個別の関数にしています。

html

1<input type="button" value="削除" class="remove">

javascript

1document.addEventListener('DOMContentLoaded', function() { 2 3 let addCount = 0; // 追加行カウンタ 4 5 function removeRow(event) { 6 const tr = event.target.parentNode.parentNode; 7 const tbody = document.getElementById("addlist"); 8 tbody.removeChild(tr); 9 } 10 11 const add = document.getElementById("add"); 12 13 add.addEventListener("click", function() { 14 const tbody = document.getElementById("addlist"); 15 const tr = tbody.firstElementChild.cloneNode(true); 16 tbody.insertBefore(tr, tbody.lastChild); 17 18 const remove = tr.querySelector(".remove"); 19 remove.addEventListener("click", removeRow); 20 21 // 追加された行の左端のtdに追加行番号を入れる。 22 tr.querySelector("td").textContent = ++addCount; 23 }) 24 25 const remove = document.querySelector(".remove"); 26 remove.addEventListener("click", removeRow); 27 28});

なお、上記では、補足として以下の2点も修正、追加しています。

  • let にする必要のない変数は constにしています。
  • 追加された行の左端の<td>に追加行番号を入れる。(※これは、削除ボタンがクリックされたときに、そのボタンを含む行が削除されるのを、目視で確認できるようにするためです)

以上、参考になれば幸いです。

備考

上記の回答に書いた、修正点(1) の

  • B: 行の追加、削除の影響を受けない、上位階層の要素にクリックハンドラを設定して、event.target が削除ボタンだったときに、行削除を行うようにする。

については、shinji709さんが分かり易いご回答を書かれていますので、そちらを参考にされてください。

投稿2019/11/23 01:34

編集2019/11/23 02:29
jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

HO.

2019/11/23 02:29

clonenodeの説明を挙げてくれるなど、とても勉強になりました。次回これらのメソッドの使用する時に気をつけたいと思います。ありがとうございました。
HO.

2019/11/23 02:46

また let にする必要のない変数は constにしています。 追加された行の左端の<td>に追加行番号を入れる。(※これは、削除ボタンがクリックされたときに、そのボタンを含む行が削除されるのを、目視で確認できるようにするためです) この辺気を付けます。本当に参考になりました。 ありがとうございました!
jun68ykt

2019/11/23 02:46

どういたしまして。解決したようでよかったです????
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.29%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問