質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

88.80%

Javascript 追加したボタンで要素を削除する方法

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 367

mikeikeikename

score 14

前提・実現したいこと

JavascriptのDOM操作で、追加したボタン要素(削除ボタン)を使って
追加したtd要素を削除したいと考えておりますが、以下のエラーコードが出てしまいます。

発生している問題・エラーメッセージ

Uncaught TypeError: Failed to execute 'addEventListener' on 'EventTarget': 2 arguments required, but only 1 present.
    at HTMLButtonElement.<anonymous> (main.js:57)

HTML

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel ="stylesheet" href="css/style.css">
  <title>Todoリスト</title>
</head>
<body>
  <h1>Todoリスト</h1>
  <p>
    <input type="radio" name="status" value="1" checked="checked">全て
    <input type="radio" name="status" value="2">作業中
    <input type="radio" name="status" value="3">完了
    </p>
<p></p>
    <table>
      <thead>
        <th>ID</th>
        <th>コメント</th>
        <th>状態</th>
        <th></th>
      </thead>
      <tbody class ="addTask-target"></tbody>
    </table>
    <h2>新規タスクの追加</h2>
    <input class="addTask-value" type="text" />
    <button class="addTask-trigger" type="button">追加</button>
  <script src="js/main.js"></script>
</body>

</script>
</html>

Javascript

        document.addEventListener('DOMContentLoaded', function() {
            const addTaskTrigger = document.getElementsByClassName('addTask-trigger')[0];
            const addTaskTarget = document.getElementsByClassName('addTask-target')[0];
            const addTaskValue = document.getElementsByClassName('addTask-value')[0];  
            let nextId = 0;
            const todos = [];

        const addTask = (task,id) => {
            //テーブル要素を生成する td要素を作る
            const tableItem = document.createElement('tr');
            const addButtonTd = document.createElement('td');
            const idSpanTd = document.createElement('td');
            const taskSpanTd = document.createElement('td');
            const removeButtonTd = document.createElement('td');

            //Button要素を生成する
            const addButton = document.createElement('button')
            const removeButton = document.createElement('button')

            //要素内のHTML文章を変更する
            addButton.innerText = '作業中';
            removeButton.innerText = '削除';
            idSpanTd.innerText = id;
            taskSpanTd.innerText = task;

            //生成したテーブル要素をブラウザに表示する
            tableItem.append(idSpanTd);
            tableItem.append(taskSpanTd);
            tableItem.append(addButtonTd);
            tableItem.append(removeButtonTd);
            addTaskTarget.appendChild(tableItem);

            //生成したbutton要素を生成する
            addButtonTd.append(addButton);
            removeButtonTd.append(removeButton);     

            const todo = {
                task: 'taskSpanTd',
                status: '作業中'
            };
            todos.push(todo);

        };

        function delete_element(){
        tbody.remoChild(tbody.firstChild);
        }

        addTaskTrigger.addEventListener('click',() => {
            const task = addTaskValue.value;
            addTask(task,nextId ++);
            addTaskValue.value = '';


        const delete_value =document.querySelector('button');
        delete_value.addEventListener('click, delete_element, false')
    });


    });

試したこと

        function delete_element(){
        tbody.remoChild(tbody.firstChild);
        }

        addTaskTrigger.addEventListener('click',() => {
            const task = addTaskValue.value;
            addTask(task,nextId ++);
            addTaskValue.value = '';


上記、削除と追加を同じ関数でまとめましたが、上手く動作せずでした。
delete_elementが認識されていないのでその辺りに問題があるのかなと考えています。

ID、classなどを取得して、加工して、HTMLに戻すという一連の動作は頭で理解しているのですが、
HTMLには削除ボタンに関するID、classがついていないため、こういった場合はどうするのかわからない状況です。
(削除ボタンがremoveButtonTd.append(removeButton);とJavascriptで生成された要素であるため)

お手数ですがご確認、ご教示宜しくお願い致します。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+2

検証はしておりませんが、取り急ぎ後ろから3行目の delete_value.addEventListener('click, delete_element, false') はエラーになりますよね。
全部文字列で囲ってしまっています。


とりあえず動くまで持っていきました。
delete_element は addTaskTarget に付与し、delete_element 内でボタンが押されたかどうか判断するようにしました。

document.addEventListener('DOMContentLoaded', function() {
  const addTaskTrigger = document.getElementsByClassName('addTask-trigger')[0];
  const addTaskTarget = document.getElementsByClassName('addTask-target')[0];
  const addTaskValue = document.getElementsByClassName('addTask-value')[0];
  let nextId = 0;
  const todos = [];

  const addTask = (task, id) => {
    //テーブル要素を生成する td要素を作る
    const tableItem = document.createElement('tr');
    const addButtonTd = document.createElement('td');
    const idSpanTd = document.createElement('td');
    const taskSpanTd = document.createElement('td');
    const removeButtonTd = document.createElement('td');

    //Button要素を生成する
    const addButton = document.createElement('button')
    const removeButton = document.createElement('button')

    //要素内のHTML文章を変更する
    addButton.innerText = '作業中';
    removeButton.innerText = '削除';
    idSpanTd.innerText = id;
    taskSpanTd.innerText = task;

    //生成したテーブル要素をブラウザに表示する
    tableItem.append(idSpanTd);
    tableItem.append(taskSpanTd);
    tableItem.append(addButtonTd);
    tableItem.append(removeButtonTd);
    addTaskTarget.appendChild(tableItem);

    //生成したbutton要素を生成する
    addButtonTd.append(addButton);
    removeButtonTd.append(removeButton);

    const todo = {
      task: 'taskSpanTd',
      status: '作業中'
    };
    todos.push(todo);
  };

  function delete_element(ev) {
    if (ev.target instanceof HTMLButtonElement && ev.target.textContent === '削除') {
      const row = ev.target.closest('tr');
      addTaskTarget.removeChild(row);
    }
  }

  addTaskTrigger.addEventListener('click', () => {
    const task = addTaskValue.value;
    addTask(task, nextId++);
    addTaskValue.value = '';
  });
  addTaskTarget.addEventListener('click', delete_element, false);
});

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/18 23:22

    htsign様
    ありがとうございます。無事動かすことが出来ました。
    ちなみに、削除した後に一番左手のインデックスを初期化(0からに戻す)する場合は、trごと削除するような実装になりますでしょうか。

    キャンセル

  • 2020/06/18 23:29 編集

    インデックスを初期化するには addTask の第二引数に渡す数字が 0 になればよいので、 nextId に 0 を代入すればよいと思います。
    ただし、他に残っているtodoタスクがあるのにも関わらず 0 に戻してしまうとそれはそれで変なので、 todos が空になったかどうかのチェックは必要かと思います。

    もしくは「いつどのtodoタスクを削除しても上から順に必ず 0, 1, 2, ... と並んでほしい」ということでしたら、削除後に残ったそれぞれの td の innerText に対して 0 から振り直す処理が必要です。
    これをするのであれば addTask に id を渡す処理自体が不要になり、必然的に nextId もコードから消してよいことになりますね。

    trごと削除してあげないと、いろいろと面倒な処理が増えることになりそうです。

    キャンセル

  • 2020/06/18 23:30

    承知致しました。
    ありがとうございます。
    やってみます。

    キャンセル

+1

全部文字列になっているので、下記のように修正してみてください。

// delete_value.addEventListener('click, delete_element, false')
//                                    ↓                       ↓
   delete_value.addEventListener('click', delete_element, false)


ただ、複数増えていく削除ボタンがすべて同じ位置の要素(最初の要素)を削除することになるので、それが正しい実装かは考えてみてください。

また、document.querySelector('button')で取得できるのはHTML中の全てのボタンの中で最初に現れたボタンなので、同じボタンに削除イベントをいくつも付与することになることも注意したほうが良いです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/18 23:23

    kei344様
    いつもありがとうございます。
    上記諸々承知致しました。selectorよりもIdで取得した方が賢明ですね。

    キャンセル

  • 2020/06/18 23:26

    Idで取得よりもエレメント作ったところでイベントをつけるほうが良いです。(削除も簡単だし)

    キャンセル

  • 2020/06/18 23:29

    承知致しました。
    ありがとうございます。勉強になりましたm(_ _)m

    キャンセル

+1

中略

            //生成したbutton要素を生成する
            addButtonTd.append(addButton);
            removeButtonTd.append(removeButton);     

            const todo = {
                task: 'taskSpanTd',
                status: '作業中'
            };
            todos.push(todo);

            removeButton.addEventListener('click', delete_element, false);

        };

        function delete_element () {
          let tr = this.closest ('tr');
          if (tr)
            tr.remove ();
        }


そもそも

delete_value.addEventListener('click, delete_element, false')


は構文エラー!

個人的には無駄が多すぎます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/18 23:24

    one_line様
    初歩的な部分のご教示ありがとうございます。
    まだまだ無駄が多いので修正していきます。

    キャンセル

0

<script>
window.addEventListener('DOMContentLoaded',()=>{
  let id=0;
  document.querySelector('.addTask-trigger').addEventListener('click',()=>{
    const tr=[
      document.createTextNode(id++),
      document.createTextNode(document.querySelector('.addTask-value').value),
      Object.assign(document.createElement('button'),{textContent:"削除",className:'del'}),
      Object.assign(document.createElement('button'),{textContent:"作業中"}),
      ].map(x=>[x].reduce((x,y)=>(x.appendChild(y),x),document.createElement('td')))
       .reduce((x,y)=>(x.appendChild(y),x),document.createElement('tr'));
    document.querySelector('.addTask-target').appendChild(tr);
  });
  document.querySelector('.addTask-target').addEventListener('click',(e)=>{
    if(e.target.classList.contains('del')){
      const tr=e.target.closest('tr');
      tr.parentNode.removeChild(tr);
    }
  });
});
</script>
<table>
<thead>
<th>ID</th>
<th>コメント</th>
<th>状態</th>
<th></th>
</thead>
<tbody class ="addTask-target"></tbody>
</table>
<h2>新規タスクの追加</h2>
<input class="addTask-value" type="text" />
<button class="addTask-trigger" type="button">追加</button>

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 88.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る