メインコンテンツまでスキップ

プロジェクト

ここまでの知識を使って、シンプルな ToDo アプリを作ってみましょう。

ルール

  • ToDo の追加ができます。
  • ToDo の削除ができます。
  • ToDo の編集ができます。
  • 入力欄が空欄だと ToDo の追加ができなくなります。

ヒント

いきなり作るのが難しい場合はタスクを分解してみましょう。今回はルールにある4つの課題をひとつずつ解決していきます。

  1. ToDo を追加できるようにする。
  2. ToDo を削除できるようにする。
  3. ToDo を編集できるようにする。
  4. 空の ToDo を追加できないようにする。

の4つの仕事があるので、まず 1 からやっていきましょう。

ステップ 1: ToDo を追加する

ひとまず ToDo の一覧、ToDo の入力欄、ToDo の追加ボタンが必要です。 ul 要素と input 要素と button 要素を使ってみましょう。

index.html
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<title>Title</title>
</head>
<body>
<ul id="todo-list"></ul>
<input id="todo-input" />
<button id="add-button">追加</button>
<script src="./script.js"></script>
</body>
</html>

次に JavaScript ファイルを作成して追加ボタンを押したときの処理を記述しましょう。

script.js
const todoList = document.getElementById("todo-list");
const todoInput = document.getElementById("todo-input");
const addButton = document.getElementById("add-button");

addButton.onclick = () => {
// 追加ボタンを押すと ToDo を 1 つ追加する
};

この時箇条書きの項目として新たに li 要素を追加する必要があります。 DOM の章で扱ったように、document.createElement 関数を使うと新しい要素を作成できます。 また、Node#appendChild メソッドを用いることで既存の要素内に子要素を追加することができます。

const li = document.createElement("li");
todoList.appendChild(li);

また、HTMLInputElement#value プロパティから、DOM に対応する input 要素の入力欄への入力内容を取得できます。

const todoText = document.createElement("span");
todoText.textContent = todoInput.value; // input 要素に入力された文字列を取得する
todoInput.value = ""; // input 要素の入力欄を空にする
ステップ 1 の解答例
index.html
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<title>Title</title>
</head>
<body>
<ul id="todo-list"></ul>
<input id="todo-input" />
<button id="add-button">追加</button>
<script src="./script.js"></script>
</body>
</html>
script.js
const todoList = document.getElementById("todo-list");
const todoInput = document.getElementById("todo-input");
const addButton = document.getElementById("add-button");

addButton.onclick = () => {
const todoItem = document.createElement("li");
const todoText = document.createElement("span");
todoText.textContent = todoInput.value;
todoInput.value = "";
todoItem.appendChild(todoText);
todoList.appendChild(todoItem);
};

ステップ 2: ToDo を削除する

次に削除ボタンを追加します。 document.createElement 関数button 要素を生成し削除ボタンにしてから Node#appendChild メソッドで要素内に追加しましょう。

削除ボタンを押すと li 要素が 1 つ消える機能を実装するためには、ある要素から子要素を取り除く Node#removeChild メソッドを使います。

// todoList から todoItem を取り除く
todoList.removeChild(todoItem);
ステップ 2 の解答例
index.html
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<title>Title</title>
</head>
<body>
<ul id="todo-list"></ul>
<input id="todo-input" />
<button id="add-button">追加</button>
<script src="./script.js"></script>
</body>
</html>
script.js
const todoList = document.getElementById("todo-list");
const todoInput = document.getElementById("todo-input");
const addButton = document.getElementById("add-button");

addButton.onclick = () => {
const todoItem = document.createElement("li");
const todoText = document.createElement("span");
const deleteButton = document.createElement("button");
todoText.textContent = todoInput.value;
todoInput.value = "";
deleteButton.textContent = "削除";
deleteButton.onclick = () => {
todoList.removeChild(todoItem);
};
todoItem.appendChild(todoText);
todoItem.appendChild(deleteButton);
todoList.appendChild(todoItem);
};

ステップ 3: ToDo を編集する

編集ボタンをつけてみましょう。

編集ボタンが押されたときに、ユーザーにテキストを入力するように促すダイアログを表示します。 prompt 関数を使い、ユーザーに入力を求めることができます。

todoText.textContent = prompt("新しい内容を入力してください。"); // ユーザーに入力を求める
ステップ 3 の解答例
index.html
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<title>Title</title>
</head>
<body>
<ul id="todo-list"></ul>
<input id="todo-input" />
<button id="add-button">追加</button>
<script src="./script.js"></script>
</body>
</html>
script.js
const todoList = document.getElementById("todo-list");
const todoInput = document.getElementById("todo-input");
const addButton = document.getElementById("add-button");

addButton.onclick = () => {
const todoItem = document.createElement("li");
const todoText = document.createElement("span");
const editButton = document.createElement("button");
const deleteButton = document.createElement("button");
todoText.textContent = todoInput.value;
todoInput.value = "";
editButton.textContent = "編集";
editButton.onclick = () => {
todoText.textContent = prompt("新しい内容を入力してください。");
};
deleteButton.textContent = "削除";
deleteButton.onclick = () => {
todoList.removeChild(todoItem);
};
todoItem.appendChild(todoText);
todoItem.appendChild(editButton);
todoItem.appendChild(deleteButton);
todoList.appendChild(todoItem);
};

ステップ 4: 空の ToDo を入れさせない

HTMLButtonElement#disabled プロパティtrue の時、ボタンはクリックを受け付けなくなります。 入力欄が空の時にこのプロパティを true に、それ以外の時は false にすることによって空のタスクの追加を防ぐことができます。 この時、入力欄に何かキー入力があるたびに入力欄が空かどうかを判定する必要があります。 HTMLElement#oninput プロパティにイベントハンドラを登録すると、ユーザーによって要素に入力されたときに実行される関数を定めることができます。

todoInput.oninput = () => {
// 入力欄が空の時はボタンを押せないようにする
addButton.disabled = todoInput.value === "";
};

解答

解答例
index.html
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<title>Title</title>
</head>
<body>
<ul id="todo-list"></ul>
<input id="todo-input" />
<button id="add-button" disabled>追加</button>
<script src="./script.js"></script>
</body>
</html>
script.js
const todoList = document.getElementById("todo-list");
const todoInput = document.getElementById("todo-input");
const addButton = document.getElementById("add-button");

todoInput.oninput = () => {
addButton.disabled = todoInput.value === "";
};

addButton.onclick = () => {
const todoItem = document.createElement("li");
const todoText = document.createElement("span");
const editButton = document.createElement("button");
const deleteButton = document.createElement("button");
todoText.textContent = todoInput.value;
todoInput.value = "";
addButton.disabled = true; // value への代入は oninput イベントを発火しない
editButton.textContent = "編集";
editButton.onclick = () => {
const input = prompt("新しい内容を入力してください");
// prompt 関数は入力された文字列が空の場合は空文字列 ("")、キャンセルされた場合は null を返す
if (input !== "" && input !== null) todoText.textContent = input;
};
deleteButton.textContent = "削除";
deleteButton.onclick = () => {
todoList.removeChild(todoItem);
};
todoItem.appendChild(todoText);
todoItem.appendChild(editButton);
todoItem.appendChild(deleteButton);
todoList.appendChild(todoItem);
};