4日目のゴールと今日やること
4日目のテーマは
「ミニ総合アプリに“編集機能”と“並び替え(ソート)”を加えて、アプリらしさを一段上げる」
ことです。
ここまでであなたは、
- 入力して一覧に追加する
- 削除する
- 条件分岐でメッセージや強調表示を変える
- 検索で絞り込む
というところまで来ました。
4日目はここに、
- 一覧の各行を「編集できる」ようにする
- 並び替え(ソート)で表示順を変えられるようにする
- 条件分岐を「編集中かどうか」にも使う
という、“一段階大人なアプリ”の要素を足していきます。
編集機能を追加するイメージをつかむ
どんな動きにしたいか
やりたいことはシンプルです。
- 一覧の行に「編集」ボタンを付ける
- 押したら、その行のテキストを入力欄に戻す
- 変更して「更新」ボタンを押すと、元のデータが書き換わる
ここで大事になるのが
「今、どのアイテムを編集しているのか」
という状態を持つことです。
「編集中の ID」を状態として持つ
状態を表す変数を用意する
let editingId = null;
JavaScriptこの変数が、
- null のとき → 新規追加モード
- 数字(id)が入っているとき → 編集モード
という意味になります。
追加ボタンを「モードによって動きを変える」
addButton.addEventListener("click", () => {
const text = input.value.trim();
if (text === "") return;
if (editingId === null) {
addItem(text);
} else {
updateItem(editingId, text);
}
input.value = "";
editingId = null;
addButton.textContent = "追加";
renderList();
});
JavaScriptここが今日の超重要ポイントです。
同じボタンでも「状態」によって役割を変える
これがアプリっぽさの正体のひとつです。
新規追加と更新を関数に分ける
新規追加用の関数
function addItem(text) {
const newItem = {
id: nextId,
text: text
};
items.push(newItem);
nextId += 1;
}
JavaScript更新用の関数
function updateItem(id, newText) {
const target = items.find((item) => item.id === id);
if (!target) return;
target.text = newText;
}
JavaScriptここで使っている find は、
「条件に合う最初の要素を返す」メソッドです。
一覧に「編集」ボタンを追加する
renderList に編集ボタンを足す
function renderList() {
listArea.innerHTML = "";
if (items.length === 0) {
message.textContent = "データがありません。";
return;
} else {
message.textContent = "";
}
items.forEach((item) => {
const row = document.createElement("div");
row.textContent = item.text;
const editButton = document.createElement("button");
editButton.textContent = "編集";
editButton.addEventListener("click", () => {
startEdit(item);
});
const deleteButton = document.createElement("button");
deleteButton.textContent = "削除";
deleteButton.addEventListener("click", () => {
deleteItem(item.id);
});
row.appendChild(editButton);
row.appendChild(deleteButton);
listArea.appendChild(row);
});
}
JavaScript編集開始の処理
function startEdit(item) {
input.value = item.text;
editingId = item.id;
addButton.textContent = "更新";
}
JavaScriptここでやっていることは、
- 入力欄に元のテキストを入れる
- editingId に対象の id を入れる
- ボタンのラベルを「更新」に変える
という「編集モードへの切り替え」です。
条件分岐で「モードによって UI を変える」感覚
ボタンのラベルを変えるのも条件分岐
さっきの addButton の処理は、
実は if 文によるモード分岐です。
if (editingId === null) {
addItem(text);
} else {
updateItem(editingId, text);
}
JavaScriptこのように、
- 状態(editingId)
- 条件分岐(if)
- 振る舞い(追加 or 更新)
がセットになっているのが、
アプリの基本的な構造です。
並び替え(ソート)機能を追加する
ソートボタンを用意する
HTML にボタンを追加します。
<button id="sortAscButton">昇順</button>
<button id="sortDescButton">降順</button>
JavaScript で取得します。
const sortAscButton = document.getElementById("sortAscButton");
const sortDescButton = document.getElementById("sortDescButton");
JavaScriptソート処理を実装する
sortAscButton.addEventListener("click", () => {
items.sort((a, b) => {
if (a.text < b.text) return -1;
if (a.text > b.text) return 1;
return 0;
});
renderList();
});
sortDescButton.addEventListener("click", () => {
items.sort((a, b) => {
if (a.text < b.text) return 1;
if (a.text > b.text) return -1;
return 0;
});
renderList();
});
JavaScript深掘り:sort の比較関数の意味
items.sort((a, b) => { ... }) の中で返している値は、
- 負の値 → a を先に
- 正の値 → b を先に
- 0 → 順番そのまま
というルールで解釈されます。
文字列の比較ではa.text < b.text を使って
「辞書順でどちらが先か」を判定しています。
条件分岐を「ソート状態」にも応用する
今どのソート状態かを持つ
状態を持つと、
「今どういう並び順なのか」を UI に反映できます。
let sortMode = "none"; // "none" | "asc" | "desc"
JavaScriptソートボタンで状態を更新します。
sortAscButton.addEventListener("click", () => {
sortMode = "asc";
sortItems();
renderList();
});
sortDescButton.addEventListener("click", () => {
sortMode = "desc";
sortItems();
renderList();
});
JavaScriptソート処理を関数にまとめます。
function sortItems() {
if (sortMode === "asc") {
items.sort((a, b) => (a.text < b.text ? -1 : a.text > b.text ? 1 : 0));
} else if (sortMode === "desc") {
items.sort((a, b) => (a.text < b.text ? 1 : a.text > b.text ? -1 : 0));
}
}
JavaScriptこのように、
状態(sortMode)と条件分岐(if / else if)
を組み合わせることで、
アプリの振る舞いをコントロールできます。
4日目の完成コード(要点まとめ)
let nextId = 1;
const items = [];
let editingId = null;
let sortMode = "none";
const input = document.getElementById("itemInput");
const addButton = document.getElementById("addButton");
const listArea = document.getElementById("listArea");
const message = document.getElementById("message");
const sortAscButton = document.getElementById("sortAscButton");
const sortDescButton = document.getElementById("sortDescButton");
addButton.addEventListener("click", () => {
const text = input.value.trim();
if (text === "") return;
if (editingId === null) {
addItem(text);
} else {
updateItem(editingId, text);
}
input.value = "";
editingId = null;
addButton.textContent = "追加";
sortItems();
renderList();
});
sortAscButton.addEventListener("click", () => {
sortMode = "asc";
sortItems();
renderList();
});
sortDescButton.addEventListener("click", () => {
sortMode = "desc";
sortItems();
renderList();
});
function addItem(text) {
const newItem = {
id: nextId,
text: text
};
items.push(newItem);
nextId += 1;
}
function updateItem(id, newText) {
const target = items.find((item) => item.id === id);
if (!target) return;
target.text = newText;
}
function deleteItem(id) {
const newItems = items.filter((item) => item.id !== id);
items.length = 0;
newItems.forEach((i) => items.push(i));
sortItems();
renderList();
}
function sortItems() {
if (sortMode === "asc") {
items.sort((a, b) => (a.text < b.text ? -1 : a.text > b.text ? 1 : 0));
} else if (sortMode === "desc") {
items.sort((a, b) => (a.text < b.text ? 1 : a.text > b.text ? -1 : 0));
}
}
function startEdit(item) {
input.value = item.text;
editingId = item.id;
addButton.textContent = "更新";
}
function renderList() {
listArea.innerHTML = "";
if (items.length === 0) {
message.textContent = "データがありません。";
return;
} else {
message.textContent = "";
}
items.forEach((item) => {
const row = document.createElement("div");
row.textContent = item.text;
const editButton = document.createElement("button");
editButton.textContent = "編集";
editButton.addEventListener("click", () => {
startEdit(item);
});
const deleteButton = document.createElement("button");
deleteButton.textContent = "削除";
deleteButton.addEventListener("click", () => {
deleteItem(item.id);
});
row.appendChild(editButton);
row.appendChild(deleteButton);
listArea.appendChild(row);
});
}
renderList();
JavaScript今日いちばん深く理解してほしいこと
アプリは「状態 × 条件分岐 × 振る舞い」でできている
今日出てきた状態は、
- editingId(編集中かどうか)
- sortMode(並び順)
これらを if 文で分岐し、
追加・更新・ソート・表示を切り替えました。
状態を持つ → 条件分岐で振る舞いを変える
このパターンを掴めると、
アプリの設計が一気に楽しくなります。
明日はここから、
「複数項目の入力」「複合条件の分岐」
に進んでいきます。
もう完全に“アプリを作っている人の思考”になっていますよ。

