重要ポイント
ローカルストレージ使う時、IDとワンセット
IDは、htmlでは隠しとくのが基本
(編集画面のみ、IDつける)
<input type="hidden" id="editId">
保存の仕組み : テーブルにdata 表示してから保存
テーブル表示と保存は、処理を同時にはしない
保存とテーブル表示は、いつも、処理別々
ローカルストレージ 作成手順
1.ローカルストレージ使うための、初期設定
2.data読み込み関数 作成
3.data保存関数 作成
4.data取得関数 作成
5.新規追加 変数 仕込む
6.data編集 変数仕込む
7.削除 変数 仕込む
8.テーブル読み込み 変数 仕込む
9.編集モーダル開く 変数 仕込む
10.入力formでdata送信ボタン押したら、ボタンの色を変える
に、変数仕込む
code化すると
↓
1.ローカルストレージ使うための、初期設定 場所 : 最初と最後
→ 名前"studentData"でローカルストレージ使うよ
const LOCAL_STORAGE_KEY = 'studentData';
→ ローカルストレージにはたくさんdataを入れる。
たくさんdataを入れるには配列がいるから、配列を用意し、
配列を初期化
let studentData = [];
↓
2.data読み込み関数 作成
作った配列を、ローカルストレージにセット
const storedData = localStorage.getItem(LOCAL_STORAGE_KEY);
dataはそのままだとJSで扱えないから、JSで扱える形にする
studentData = JSON.parse(storedData);
ローカルストレージの長さが増えてたらデータが新しく追加された、
ってことだから、ローカルストレージの長さを数える
if (studentData.length > 0) {
data追加時、最新IDでdata追加できるよう、処理
nextId = Math.max(...studentData.map(item => item.id)) + 1;
テーブルの中身を毎回からにし、入力欄でdataを新規作成にするには
テーブル初期化しないといけないから、テーブル初期化
renderTable();
↓
3.data保存関数 作成
JSで扱えるようにしたdataを、画面に表示できるよう 設定
function saveDataToLocalStorage() {
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(studentData));
}
↓
5.新規追加 変数 仕込む
idの初期値はローカルストレージに保存されてて、
最初のidはローカルストレージから引っ張って来ないと
使えないから、 push使う
studentData.push({ ...data, id: nextId++ }); // IDを更新
data保存とテーブル初期化関数 呼び出し
saveDataToLocalStorage();
renderTable();
data を作り終えたら、入力formはからにしないと
data を新規作成できないから、入力formをからに
clearFormInputs();
↓
6.data編集 変数仕込む
index でIDを指定し、指定したID 探す
findIndex : dataがローカルストレージの何番目に入ってるか
探す(何番目に入ってるか、要素番号調べないとdataを正しく
編集できないから)
const index = studentData.findIndex(item => item.id === id);
探したIDがあったら、dataを更新するから index !== -1
if (index !== -1) {
探したIDで、ローカルストレージにdataを代入し、更新
studentData[index] = { ...studentData[index], ...updatedData };
data保存、テーブル初期化
saveDataToLocalStorage();
renderTable();
↓
7.削除 変数 仕込む
削除するID指定 ; itemし、ID削除されてるか確認
studentData = studentData.filter(item => item.id !== id);
data 保存、テーブル初期化
saveDataToLocalStorage();
renderTable();
↓
8.テーブル空欄に 変数 仕込む
テーブルにdata新規追加を新しくやる時、
テーブルの全項目を空にしないといけなくて、
テーブルの全項目を空にするにはforeach使わないとできないから
やってる
function renderTable() {
tableBody.innerHTML = ''; // テーブルの中身をクリア
studentData.forEach(data => addTableRow(data)); // 全てのデータを再描画
}
↓
9.編集モーダル開く 変数 仕込む
すでにあるidを探し、探したidをもとにdata編集
const dataToEdit = studentData.find(item => item.id === id);
↓
10.入力formでdata送信ボタン押したら、ボタンの色を変える
に、変数仕込む
ボタンの色を変える時、ローカルストレージのdataを
読み込んでからボタンの色を変えないと、data 読み込みなしで
ボタンの色を変えたら エラーになるらしい
oadDataFromLocalStorage();
addButton.addEventListener('click', () => {
addButton.classList.add('clicked-button');
ID使い、 ローカルストレージで保存 仕組み
1.データ初期設定
→ IDの初期値 設定
2.ID最大値を探し、今のid読み込み
→ IDの最大値を探し、IDを常に+1しておく
→ dataが新規作成されたら、IDは常に最大値になるから
→ IDは数字だから、数字を扱う時、maoでいつも処理
3.入力data取得
→ idは呼び出すのみ
4.新規追加
id増やす
5.data編集 変数仕込む
同じID探す
ID探してからじゃないと、編集dataをストレージから
常に引っ張って来れないから、使うのがfind
7.削除
IDは消したら無くなるから、なくなったID探す
IDがなく存在しなくなったことを確認してから
出ないと、dataを安全に消せないから、調べてる"filter"
8.テーブル表示 : idセット
編集ボタン押した / 削除ボタン押した / 編集modal開いた
/ 編集モーダル開き、保存
→ id渡す "id渡してないと、data反映できない”から
code化すると
↓
1.データ初期設定
let nextId = 1;
↓
2.ID最大値を探し、今のid読み込み
nextId = Math.max(...studentData.map(item => item.id)) + 1;
↓
3.入力data取得 :id 読み込み
id: nextId,
↓
4.新規追加: id増やす
studentData.push({ ...data, id: nextId++ });
↓
5.data編集 : 同じID探す
findIndex : dataがローカルストレージの何番目に入ってるか
探す(何番目に入ってるか、要素番号調べないとdataを正しく
編集できないから)
const index = studentData.findIndex(item => item.id === id);
↓
7.削除 : 消したID探す
studentData = studentData.filter(item => item.id !== id);
↓
8.テーブル表示 : idセット
row.setAttribute('data-id', data.id);
↓
編集ボタン押したら、idセット
editButton.addEventListener('click', () => {
openEditModal(data.id); // 編集モーダルを開く
});
↓
削除ボタン押したら、idセット
deleteButton.addEventListener('click', () => {
deleteData(data.id); // データ削除関数を呼び出す
});
↓
編集ボタン押してモーダルウィンドウ開く時、idセットし、
id探す
function openEditModal(id) {
const dataToEdit = studentData.find(item => item.id === id);
↓
編集画面で、id表示
editIdInput.value = dataToEdit.id;
↓
保存先を指定し、保存(保存先 : 編集画面のid)
const id = parseInt(editIdInput.value);
↓
バリデーションさせた後、dataを保存するから、
バリデーション後は、もう一度idを呼び出して保存
updateData(id, updatedData);
ボタンの色を変える 仕組み
ボタンの色を変えるクラスをcssに設定
ボタンの初期値セット
dataを読み込んで
追加ボタン押したら、ボタンの色変える
入力formのdataを取得し、表示
バリデーション無効に
code化すると
↓
ボタンの色を変えるクラスをcssに設定
#addButon.clicked-button {
background-color: #28a745; /* クリック後は別の色(例: 緑) */
}
↓
ボタンの初期値セット
document.addEventListener('DOMContentLoaded', () => {
const addButton = document.getElementById('addButon');
↓
dataを読み込んで
loadDataFromLocalStorage();
↓
追加ボタン押したら、ボタンの色変える
addButton.addEventListener('click', () => {
addButton.classList.add('clicked-button');
↓
入力formのdataを取得し、表示
→ ボタンの色を変えた後も、入力formのdataを表示しとか
なきゃいけないから
const formData = getFormData();
↓
・バリデーション無効に
バリデーションを効かせないために、バリデーション時
表示するdivを、表示させないようにする
clearErrors();
↓
バリデーションさせてなかったら、処理続ける
if (!validateForm(formData)) return;
data新規追加(テーブルにdata表示の、前の処理)
createData(formData);
});
編集・削除ボタン 追加 仕組み
やり方: テーブル表示のすぐ後
# 仕込む場所 : テーブル表示する変数
function addTableRow(data) {
html テーブル
html 削除ボタン
html 編集ボタン
tableBody.appendChild(row);
↓
これの、すぐ後に編集と削除ボタン追加
ボタンが押されたらイベントリスナー設定
code化すると
↓
編集と削除ボタン追加(querySelector)
const editButton = row.querySelector('.edit-button');
const deleteButton = row.querySelector('.delete-button');
↓
ボタンが押されたら、イベントリスナー設定
editButton.addEventListener('click', () => {
openEditModal(data.id); // 編集モーダルを開く
});
deleteButton.addEventListener('click', () => {
deleteData(data.id); // データ削除関数を呼び出す
});
}
モーダルウィンドウ 作成仕組み
ばつボタン/ モーダルウィンドウ,
キャンセルボタン / 保存ボタンのスタイル設定
編集画面 idはテーブル表示では、隠しておく
モーダルウィンドウ全体のdiv id 読み込み
ばつボタン 表示させるため、❌ボタンのクラス表示させる
[編集画面]保存ボタン ID読み込み
[編集画面]キャンセルボタン ID読み込み
[編集画面] id / 電話番号/ 年齢 / 名前 / Eメール ID読み込み
編集関数作成し、ローカルストレージにdata保存
モーダルを閉じる関数だけ 仕込む
→ 編集画面開いた時、編集せず
モーダル閉じたい場合もあるから
編集ボタンが押されたら、モーダルを開く関数 仕込む
編集モーダル開く関数 作成
編集モーダル閉じる関数 作成
→ 画面を消すから、display none
ボタンの色を変える関数の後に、ばつボタンと
キャンセルボタンでモーダルを閉じる処理 作成
モーダルの保存ボタンで、data保存する関数 作成
data編集関数呼び出し、data更新
code化
↓
モーダルウィンドウのスタイル設定
↓
変種画面 idはテーブル表示では、隠しておく
<input type="hidden" id="editId">
↓
モーダルウィンドウ全体のdiv id 読み込み
document.addEventListener('DOMContentLoaded', () => {
const editModal = document.getElementById('editModal');
↓
ばつボタン 表示させるため、❌ボタンのクラス表示させる
const closeButton = document.querySelector('.close-button');
↓
[編集画面]保存ボタン ID読み込み
const saveEditButton = document.getElementById('saveEditButton');
↓
[編集画面]キャンセルボタン ID読み込み
const cancelEditButton = document.getElementById('cancelEditButton');
↓
[編集画面] id / 電話番号/ 年齢 / 名前 / Eメール ID読み込み
const editIdInput = document.getElementById('editId');
const editNameInput = document.getElementById('editName');
const editAgeInput = document.getElementById('editAge');
const editEmailInput = document.getElementById('editEmail');
const editPhoneInput = document.getElementById('editPhone');
↓
編集関数作成
async function updateData(id, updatedData) {
try {
// ダミーAPIはPUT/PATCHしても実際のデータは更新しないため、擬似的な成功とします
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`, { // ダミーAPI
method: 'PUT', // または 'PATCH'
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updatedData)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
console.log('APIでデータが更新されました:', result);
// 成功したらローカルデータとLocalStorageを更新
const index = studentData.findIndex(item => item.id === id);
if (index !== -1) {
studentData[index] = { ...studentData[index], ...updatedData };
saveDataToLocalStorage();
renderTable();
}
編集関数に、モーダル閉じる関数 仕込む
→ モーダル開いても、何も処理しないで画面閉じたい時もあるから
}
closeEditModal(); // 編集成功後にモーダルを閉じる
} catch (error) {
console.error('データ更新に失敗しました:', error);
alert('データ更新に失敗しました。');
}
↓
編集ボタンが押されたら、モーダルを開く関数 仕込む
editButton.addEventListener('click', () => {
openEditModal(data.id); // 編集モーダルを開く
});
↓
編集モーダル開く関数 作成
function openEditModal(id) {
const dataToEdit = studentData.find(item => item.id === id);
if (dataToEdit) {
editIdInput.value = dataToEdit.id;
editNameInput.value = dataToEdit.name;
editAgeInput.value = dataToEdit.age;
editEmailInput.value = dataToEdit.email;
editPhoneInput.value = dataToEdit.phone;
editModal.style.display = 'flex'; // flexにして中央寄せを有効に
}
↓
編集モーダル閉じる関数 作成
function closeEditModal() {
editModal.style.display = 'none';
}
↓
ボタンの色を変える関数の後に、ばつボタンと
キャンセルボタンでモーダルを閉じる処理 作成
closeButton.addEventListener('click', closeEditModal); → ばつボタン
cancelEditButton.addEventListener('click', closeEditModal); → キャンセルボタン
↓
モーダルの保存ボタンが押されたら、イベントリスナーで
dataを画面に表示関数、作成
saveEditButton.addEventListener('click', () => {
const id = parseInt(editIdInput.value);
const updatedData = {
name: editNameInput.value.trim(),
age: parseInt(editAgeInput.value.trim()),
email: editEmailInput.value.trim(),
phone: editPhoneInput.value.trim()
};
↓
data保存関数[編集のみの]呼び出し、data更新
updateData(id, updatedData);
code全文
!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>テーブル表示練習</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.form-group { margin-bottom: 10px; }
.label { display: inline-block; width: 80px; }
.error-message { display:none; color:red; margin-left:5px; }
/* テーブル全体の基本スタイル */
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
table, th, td { border:1px solid #000; border-collapse:collapse; padding:5px; }
/* テーブルヘッダーの枠線を太くする */
th {
border: 3px solid #000; /* ヘッダーの枠線を太く */
}
/* ボタンの初期スタイル */
#addButon {
padding: 8px 15px;
font-size: 16px;
cursor: pointer;
background-color: #007bff; /* 初期の色(青) */
color: white;
border: none;
border-radius: 4px;
transition: background-color 0.3s ease; /* 色の変化を滑らかに */
}
/* ボタンがクリックされた後のスタイル */
#addButon.clicked-button {
background-color: #28a745; /* クリック後は別の色(例: 緑) */
}
/* 削除・編集ボタンのスタイル */
.action-button {
padding: 5px 10px;
margin-left: 5px; /* ボタン間のスペース */
border: none;
border-radius: 3px;
cursor: pointer;
font-size: 13px;
color: white;
}
.delete-button {
background-color: #dc3545; /* 赤色 */
}
.edit-button {
background-color: #ffc107; /* 黄色 */
color: black; /* 黄色には黒文字が見やすい */
}
/* --- モーダルウィンドウのスタイル --- */
.modal {
display: none; /* 初期状態では非表示 */
position: fixed; /* 画面に固定 */
z-index: 1; /* 最前面に表示 */
left: 0;
top: 0;
width: 100%; /* 全幅 */
height: 100%; /* 全高 */
overflow: auto; /* スクロール可能にする */
background-color: rgba(0,0,0,0.4); /* 半透明の黒背景 */
justify-content: center;
align-items: center;
}
.modal-content {
background-color: #fefefe;
margin: auto; /* 中央寄せ */
padding: 20px;
border: 1px solid #888;
width: 80%; /* 幅 */
max-width: 500px; /* 最大幅 */
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
position: relative;
}
.close-button {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close-button:hover,
.close-button:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
.modal-buttons {
margin-top: 20px;
text-align: right;
}
.modal-buttons button {
padding: 8px 15px;
margin-left: 10px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.modal-buttons .save-button {
background-color: #28a745;
color: white;
}
.modal-buttons .cancel-button {
background-color: #6c757d;
color: white;
}
</style>
</head>
<body>
<form id="userForm">
<div class="form-group">
<label class="label" for="studentName">名前</label>
<input type="text" id="studentName">
<div id="nameError" class="error-message">名前を入力してください</div>
</div>
<div class="form-group">
<label class="label" for="studentAge">年齢</label>
<input type="number" id="studentAge">
</div>
<div class="form-group">
<label class="label" for="studentEmail">メール</label>
<input type="email" id="studentEmail">
</div>
<div class="form-group">
<label class="label" for="studentnumber">電話</label>
<input type="text" id="studentnumber">
</div>
<button type="button" id="addButon">追加</button>
</form>
<hr>
<table id="studentTable">
<thead>
<tr><th>ID</th><th>名前</th><th>年齢</th><th>メール</th><th>電話</th><th>操作</th></tr> </thead>
<tbody></tbody>
</table>
<div id="editModal" class="modal">
<div class="modal-content">
<span class="close-button">×</span>
<h2>データ編集</h2>
<input type="hidden" id="editId">
<div class="form-group">
<label class="label" for="editName">名前</label>
<input type="text" id="editName">
</div>
<div class="form-group">
<label class="label" for="editAge">年齢</label>
<input type="number" id="editAge">
</div>
<div class="form-group">
<label class="label" for="editEmail">メール</label>
<input type="email" id="editEmail">
</div>
<div class="form-group">
<label class="label" for="editPhone">電話</label>
<input type="text" id="editPhone">
</div>
<div class="modal-buttons">
<button class="save-button" id="saveEditButton">保存</button>
<button class="cancel-button" id="cancelEditButton">キャンセル</button>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const LOCAL_STORAGE_KEY = 'studentData'; // ローカルストレージのキー
const addButton = document.getElementById('addButon');
const nameInput = document.getElementById('studentName');
const ageInput = document.getElementById('studentAge');
const emailInput = document.getElementById('studentEmail');
const phoneInput = document.getElementById('studentnumber');
const nameError = document.getElementById('nameError');
const tableBody = document.querySelector('#studentTable tbody');
// モーダル関連要素
const editModal = document.getElementById('editModal');
const closeButton = document.querySelector('.close-button');
const saveEditButton = document.getElementById('saveEditButton');
const cancelEditButton = document.getElementById('cancelEditButton');
const editIdInput = document.getElementById('editId');
const editNameInput = document.getElementById('editName');
const editAgeInput = document.getElementById('editAge');
const editEmailInput = document.getElementById('editEmail');
const editPhoneInput = document.getElementById('editPhone');
let studentData = []; // アプリケーションのデータ配列
let nextId = 1; // 次に割り当てるID
// --- ローカルストレージとデータ管理 ---
// ローカルストレージからデータを読み込む
function loadDataFromLocalStorage() {
const storedData = localStorage.getItem(LOCAL_STORAGE_KEY);
if (storedData) {
studentData = JSON.parse(storedData);
// 既存データから最大のIDを見つけてnextIdを設定
if (studentData.length > 0) {
nextId = Math.max(...studentData.map(item => item.id)) + 1;
}
renderTable(); // テーブルを初期表示
}
}
// ローカルストレージにデータを保存する
function saveDataToLocalStorage() {
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(studentData));
}
// --- 関数定義 ---
// 入力データ取得
function getFormData() {
return {
id: nextId, // 現在のnextIdを割り当てる
name: nameInput.value.trim(),
age: parseInt(ageInput.value.trim()) || 0, // 数値に変換、無効な場合は0
email: emailInput.value.trim(),
phone: phoneInput.value.trim()
};
}
// バリデーション
function validateForm(data) {
if (data.name === '') {
nameError.style.display = 'inline';
setTimeout(() => { nameError.style.display = 'none'; }, 2000);
return false;
}
if (isNaN(data.age) || data.age <= 0) {
alert('正しい年齢を入力してください'); // ここは残しておきます
return false;
}
return true;
}
// バリデーションエラー初期化
function clearErrors() {
nameError.style.display = 'none';
}
// --- CRUD操作(Fetch APIを使用) ---
// データ新規追加 (Create)
async function createData(data) {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users', { // ダミーAPI
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
console.log('APIから新規データが追加されました:', result);
// 成功したらローカルデータとLocalStorageを更新
studentData.push({ ...data, id: nextId++ }); // IDを更新
saveDataToLocalStorage();
renderTable();
clearFormInputs();
} catch (error) {
console.error('データ追加に失敗しました:', error);
alert('データ追加に失敗しました。');
}
}
// データ編集 (Update)
async function updateData(id, updatedData) {
try {
// ダミーAPIはPUT/PATCHしても実際のデータは更新しないため、擬似的な成功とします
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`, { // ダミーAPI
method: 'PUT', // または 'PATCH'
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updatedData)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
console.log('APIでデータが更新されました:', result);
// 成功したらローカルデータとLocalStorageを更新
const index = studentData.findIndex(item => item.id === id);
if (index !== -1) {
studentData[index] = { ...studentData[index], ...updatedData };
saveDataToLocalStorage();
renderTable();
}
closeEditModal(); // 編集成功後にモーダルを閉じる
} catch (error) {
console.error('データ更新に失敗しました:', error);
alert('データ更新に失敗しました。');
}
}
// データ削除 (Delete)
async function deleteData(id) {
const confirmDelete = confirm('本当に削除しますか?');
if (!confirmDelete) return;
try {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`, { // ダミーAPI
method: 'DELETE'
});
if (!response.ok) {
// DELETEリクエストは200 OKまたは204 No Contentを返すことが一般的
// ここでは200番台以外のエラーを捕捉
throw new Error(`HTTP error! status: ${response.status}`);
}
console.log(`APIからID ${id} のデータが削除されました。`);
// 成功したらローカルデータとLocalStorageを更新
studentData = studentData.filter(item => item.id !== id);
saveDataToLocalStorage();
renderTable();
} catch (error) {
console.error('データ削除に失敗しました:', error);
alert('データ削除に失敗しました。');
}
}
// --- UI操作 ---
// テーブルに行追加(編集・削除ボタン付き)
function addTableRow(data) {
const row = document.createElement('tr');
row.setAttribute('data-id', data.id); // 行にデータのIDを設定
row.innerHTML = `
<td>${data.id}</td> <td>${data.name}</td>
<td>${data.age}</td>
<td>${data.email}</td>
<td>${data.phone}</td>
<td>
<button class="action-button edit-button">編集</button>
<button class="action-button delete-button">削除</button>
</td>
`;
tableBody.appendChild(row);
// 追加したばかりのボタンにイベントリスナーを設定
const editButton = row.querySelector('.edit-button');
const deleteButton = row.querySelector('.delete-button');
editButton.addEventListener('click', () => {
openEditModal(data.id); // 編集モーダルを開く
});
deleteButton.addEventListener('click', () => {
deleteData(data.id); // データ削除関数を呼び出す
});
}
// 入力欄クリア
function clearFormInputs() {
nameInput.value = '';
ageInput.value = '';
emailInput.value = '';
phoneInput.value = '';
}
// テーブルを再描画する関数
function renderTable() {
tableBody.innerHTML = ''; // テーブルの中身をクリア
studentData.forEach(data => addTableRow(data)); // 全てのデータを再描画
}
// 編集モーダルを開く関数
function openEditModal(id) {
const dataToEdit = studentData.find(item => item.id === id);
if (dataToEdit) {
editIdInput.value = dataToEdit.id;
editNameInput.value = dataToEdit.name;
editAgeInput.value = dataToEdit.age;
editEmailInput.value = dataToEdit.email;
editPhoneInput.value = dataToEdit.phone;
editModal.style.display = 'flex'; // flexにして中央寄せを有効に
}
}
// 編集モーダルを閉じる関数
function closeEditModal() {
editModal.style.display = 'none';
}
// --- イベントリスナー ---
// ページロード時にローカルストレージからデータを読み込み、テーブルを表示
loadDataFromLocalStorage();
// 「追加」ボタンのクリックイベント
addButton.addEventListener('click', () => {
// ボタンの色を青に変更 (今回はクリック後に緑に変える例)
addButton.classList.add('clicked-button');
const formData = getFormData();
clearErrors();
if (!validateForm(formData)) return;
createData(formData); // データ追加関数を呼び出す
});
// モーダルを閉じるボタン
closeButton.addEventListener('click', closeEditModal);
cancelEditButton.addEventListener('click', closeEditModal);
// モーダル内の保存ボタン
saveEditButton.addEventListener('click', () => {
const id = parseInt(editIdInput.value);
const updatedData = {
name: editNameInput.value.trim(),
age: parseInt(editAgeInput.value.trim()),
email: editEmailInput.value.trim(),
phone: editPhoneInput.value.trim()
};
if (!validateForm(updatedData)) return; // 編集フォームのバリデーションも既存関数を利用
updateData(id, updatedData); // データ更新関数を呼び出す
});
});
</script>
</body>
</html>