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

JavaScript JavaScript
スポンサーリンク

Day28 前半のゴール

ここまでで、TODOアプリは「追加・削除・保存・復元」までできるようになりました。
Day28 のテーマは 完了機能
前半でやるのは、ざっくり言うとこの2つです。

タスクに「完了したかどうか」の情報を持たせる
その情報を画面(チェックボックス)に反映できる形にする

まだ「クリックして完了状態を切り替える」ところまでは行きません。
まずは データの形を整えること に集中します。


完了機能を日本語で分解してみる

ただ「チェックを付ける」だけでは足りない

「完了機能を付けたい」と聞くと、
多くの人は「チェックボックスを置けばいいんでしょ?」と思います。

でも、アプリとしてちゃんと動かすには、もう少し分解が必要です。

タスクごとに「完了しているかどうか」を覚えておく
その状態を画面に反映する(チェックの ON/OFF)
後で localStorage にも完了状態を含めて保存したい

つまり、見た目だけじゃなくて、データ側にも完了フラグが必要になります。


いまの tasks の形を見直す

文字列だけでは「完了」を表現できない

Day27 までの tasks は、こんな形でした。

let tasks = ["買い物に行く", "メールを送る"];
JavaScript

これは「タスクの名前」しか持っていません。
ここに「完了したかどうか」を足そうとすると、
文字列だけではどうにもなりません。

そこで、「タスク1件」を オブジェクト で表現することにします。


タスク1件をオブジェクトで表す

title と isDone を持つ形にする

タスク1件を、こういう形にします。

const task = {
  title: "買い物に行く",
  isDone: false
};
JavaScript

title
タスクの内容(今までの文字列)

isDone
完了しているかどうか(true / false)

これを配列にすると、こうなります。

let tasks = [
  { title: "買い物に行く", isDone: false },
  { title: "メールを送る", isDone: true }
];
JavaScript

この形にしておくと、

完了したタスクだけ見た目を変える
完了状態も含めて localStorage に保存する
後で「完了だけ表示」みたいな機能も付けられる

といった拡張が、自然にできるようになります。


addTask をオブジェクト対応に書き換える

文字列ではなく「タスクオブジェクト」を追加する

今までの addTask はこうでした。

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

これを、オブジェクトを追加する形に変えます。

function addTask(text) {
  const task = {
    title: text,
    isDone: false
  };

  tasks.push(task);
}
JavaScript

ここでのポイントは、

新しく作られるタスクは必ず isDone: false から始まる

ということです。
「最初は未完了、あとで完了に変える」という流れが、ここで決まります。


renderTasks を「オブジェクト前提」に書き換える

task.title を表示に使う

今までは、forEach の中で text を受け取っていました。

tasks.forEach((text, index) => {
  // text を使って表示
});
JavaScript

これを、オブジェクト前提に変えます。

tasks.forEach((task, index) => {
  // task.title を使って表示
});
JavaScript

具体的にはこうです。

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

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

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

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

    deleteButtonElement.addEventListener("click", () => {
      deleteTask(index);
      saveTasks();
      renderTasks();
    });

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

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

ここで大事なのは、

tasks の中身が「文字列」から「オブジェクト」に変わった
それに合わせて、表示も task.title に変えた

という 2 点です。
isDone はまだ使っていませんが、「いつでも使える状態」にはなりました。


完了チェック用の UI を追加する

チェックボックスをタスクの左に置く

完了機能の UI として、一番分かりやすいのはチェックボックスです。
タスク1件の中に、チェックボックスを追加します。

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

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

    const checkboxElement = document.createElement("input");
    checkboxElement.type = "checkbox";

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

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

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

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

これで見た目は、

[ ] 買い物に行く 削除
[ ] メールを送る 削除

のようになります。
まだチェックと isDone は連動していませんが、
「完了機能の入り口」はできました。


isDone とチェック状態を結びつける

データの状態を UI に反映する

次に、「完了しているタスクは最初からチェックが付いている」状態にします。

checkboxElement.checked = task.isDone;
JavaScript

これを renderTasks の中に追加します。

const checkboxElement = document.createElement("input");
checkboxElement.type = "checkbox";
checkboxElement.checked = task.isDone;
JavaScript

これで、

isDone が true のタスク → チェック付き
isDone が false のタスク → チェックなし

という表示になります。

ここでようやく、

データ(task.isDone)

UI(checkbox.checked)

という「一方向のつながり」ができました。

まだ「クリックして isDone を変える」処理は書いていません。
前半のゴールはあくまで、

タスクをオブジェクトにする
完了フラグ isDone を持たせる
isDone に応じてチェック状態を反映する

ここまでです。


Day28 前半のコードイメージ

追加・削除・保存はそのまま、タスク構造だけ進化させる

前半の時点でのイメージをまとめると、こんな感じです。

let tasks = [];

function addTask(text) {
  const task = {
    title: text,
    isDone: false
  };
  tasks.push(task);
}

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

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

    const checkboxElement = document.createElement("input");
    checkboxElement.type = "checkbox";
    checkboxElement.checked = task.isDone;

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

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

    deleteButtonElement.addEventListener("click", () => {
      deleteTask(index);
      saveTasks();
      renderTasks();
    });

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

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

まだ完了状態の切り替えはしません。
でも、「完了機能を載せるための土台」はここでほぼ完成しています。


Day28 前半のまとめ

前半で本当に押さえてほしいのは、この5つです。

タスクは「文字列」ではなく「オブジェクト」で持つ
オブジェクトには title と isDone を持たせる
addTask はオブジェクトを追加するように書き換える
renderTasks は task.title と task.isDone を使う
チェックボックスを表示し、isDone に応じて checked を設定する

後半では、この土台の上に、

チェックをクリックしたら isDone を切り替える
完了タスクの見た目を変える(取り消し線など)
完了状態も含めて localStorage に保存・復元する

という「完了機能の本体」を一緒に作っていきます。

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