JavaScript | ゼロからはじめるプログラミング、30日で基礎を学ぶJavaScript:ミニWebアプリ開発 - Day26:TODOアプリ②

JavaScript JavaScript
スポンサーリンク

Day26 前半のゴール

Day25 で「タスクを追加できる TODO アプリ」ができました。
Day26 のテーマは タスク削除の実装
前半ではまず、

「どのタスクを消すか」をどう特定するか
削除ボタンをどう配置するか
配列と画面をどう連動させるか

ここを、できるだけシンプルな形で押さえていきます。


いきなりコードを書かずに「削除」を設計する

何を消すのかをはっきりさせる

「削除機能」と聞くと、ついこう思いがちです。

「ボタンを押したら、そのタスクを消す」

でも、プログラム的にはもう一歩踏み込んで考える必要があります。

どのタスクに対応するボタンが押されたのか
そのタスクは tasks 配列の何番目なのか
配列から消したあと、画面をどう更新するのか

この3つが見えていれば、削除機能は怖くありません。


前提となる TODO アプリの形を確認する

配列+描画の構造をおさらい

Day25 の後半で作った形は、ざっくり言うとこうでした。

const taskInputElement = document.getElementById("taskInput");
const addButtonElement = document.getElementById("addButton");
const taskListElement = document.getElementById("taskList");

let tasks = [];

function addTask(text) {
  tasks.push(text);
}

function renderTasks() {
  taskListElement.textContent = "";

  tasks.forEach((text) => {
    const taskElement = document.createElement("p");
    taskElement.textContent = text;
    taskListElement.appendChild(taskElement);
  });
}

addButtonElement.addEventListener("click", () => {
  const text = taskInputElement.value.trim();

  if (text === "") {
    return;
  }

  addTask(text);
  renderTasks();
  taskInputElement.value = "";
});
JavaScript

ここで重要なのは、

タスクの本体は tasks 配列
画面は renderTasks で配列から再構築

という構造になっていることです。
削除機能は、この「配列をいじってから再描画する」という流れに乗せて作ります。


削除ボタンをどこに置くかを決める

各タスクの横に「削除」ボタンを付ける

削除の UI として一番分かりやすいのは、

タスクの右側に「削除」ボタンを置く

という形です。

つまり、1つのタスクは

テキスト
削除ボタン

のセットになります。

これを renderTasks の中で作るイメージを持っておきましょう。


renderTasks を「削除ボタン付き」に書き換える

タスク1件分の「箱」を作る

まずは、タスク1件を包む要素を作ります。
p でも div でもいいですが、ここでは div を使ってみます。

function renderTasks() {
  taskListElement.textContent = "";

  tasks.forEach((text) => {
    const taskItemElement = document.createElement("div");

    const taskTextElement = document.createElement("span");
    taskTextElement.textContent = text;

    const deleteButtonElement = document.createElement("button");
    deleteButtonElement.textContent = "削除";

    taskItemElement.appendChild(taskTextElement);
    taskItemElement.appendChild(deleteButtonElement);

    taskListElement.appendChild(taskItemElement);
  });
}
JavaScript

この時点で、画面上は

タスクのテキスト + 削除ボタン

という形で並ぶようになります。
まだ削除は動きませんが、「見た目の準備」ができました。


どのタスクを削除するかを特定する

forEach の index を使う

削除ボタンが押されたときに必要なのは、

このボタンは tasks の何番目のタスクに対応しているのか

という情報です。

forEach には、第2引数として index(何番目か)が渡されます。
これを使って、「削除したいタスクの位置」を覚えさせます。

function renderTasks() {
  taskListElement.textContent = "";

  tasks.forEach((text, index) => {
    const taskItemElement = document.createElement("div");

    const taskTextElement = document.createElement("span");
    taskTextElement.textContent = text;

    const deleteButtonElement = document.createElement("button");
    deleteButtonElement.textContent = "削除";

    deleteButtonElement.addEventListener("click", () => {
      console.log("削除ボタンが押されました。index:", index);
    });

    taskItemElement.appendChild(taskTextElement);
    taskItemElement.appendChild(deleteButtonElement);

    taskListElement.appendChild(taskItemElement);
  });
}
JavaScript

この状態でブラウザを開き、
タスクをいくつか追加してから削除ボタンを押すと、
コンソールに index が表示されます。

0 番目、1 番目、2 番目……

という情報が取れていれば、削除の準備はほぼ完了です。


配列からタスクを削除する

splice を使って「その1件だけ」を消す

配列から特定の位置の要素を削除するには、splice を使います。

tasks.splice(index, 1);
JavaScript

index 番目から 1 件だけ削除する、という意味です。

さきほどの削除ボタンのイベントの中を、こう書き換えます。

deleteButtonElement.addEventListener("click", () => {
  tasks.splice(index, 1);
  renderTasks();
});
JavaScript

これで、

削除ボタンが押される
対応する index のタスクが tasks から消える
renderTasks で画面を再描画する

という流れが完成します。


削除機能付き renderTasks の全体像

ここまでのコードをまとめる

前半のゴールとして、削除ボタン付きの renderTasks をまとめておきます。

function renderTasks() {
  taskListElement.textContent = "";

  tasks.forEach((text, index) => {
    const taskItemElement = document.createElement("div");

    const taskTextElement = document.createElement("span");
    taskTextElement.textContent = text;

    const deleteButtonElement = document.createElement("button");
    deleteButtonElement.textContent = "削除";

    deleteButtonElement.addEventListener("click", () => {
      tasks.splice(index, 1);
      renderTasks();
    });

    taskItemElement.appendChild(taskTextElement);
    taskItemElement.appendChild(deleteButtonElement);

    taskListElement.appendChild(taskItemElement);
  });
}
JavaScript

この関数は、

画面を一度クリアする
tasks を順番に見て、タスク1件分の要素を作る
テキストと削除ボタンをセットで配置する
削除ボタンには「自分の index を消す」処理を付ける

という役割を持っています。


デバッグの視点を少し足しておく

「どのタスクが消えたか」を確認する

もし削除がうまくいかないと感じたら、
削除イベントの中に console.log を入れてみてください。

deleteButtonElement.addEventListener("click", () => {
  console.log("削除前 tasks:", tasks);
  console.log("削除する index:", index);

  tasks.splice(index, 1);

  console.log("削除後 tasks:", tasks);

  renderTasks();
});
JavaScript

これで、

削除前に tasks がどうなっているか
どの index を消そうとしているか
削除後に tasks がどう変わったか

を一つずつ確認できます。

「配列がどう変わっているか」を意識して見る癖は、
この先もっと複雑なアプリを作るときにも必ず役に立ちます。


Day26 前半のまとめ

前半でやったことを整理すると、こうなります。

削除機能を「どのタスクを消すか」という視点から設計した
タスクの本体は tasks 配列で管理する前提を再確認した
renderTasks の中で、タスク1件分の要素(テキスト+削除ボタン)を作った
forEach の index を使って「削除対象の位置」を特定した
splice(index, 1) で配列からタスクを削除し、renderTasks で再描画した

後半では、この削除機能をもう少し整理して、

関数分割で削除処理を分ける
見た目やクラス名を整える
将来の「完了機能」や「保存機能」を見据えた形にする

というところまで一緒に進めていきます。

タイトルとURLをコピーしました