axios CRUD. 重 手順書

### 目次
<ul>
<li>【おまけ】テーブル読み込みとテーブル表示を一緒に処理してない理由</li>
<li> [おまけ2] バリデーション表示</li>
<li> [おまけ3]  バリデーション作る 流れ</li>
<li> [おまけ4]  バリデーション使う 流れ</li>
<li> [おまけ5]  バリデーション code並び順 </li>
<li> [おまけ6]  初期化がいる関数 </li>
<li> [1】テーブルhtml 作成</li>
<li>[2-1: 本番より】入力/編集formから入力data取得 getFormData作成</li>
<li>[2-2: 実装より】入力/編集formから入力data取得 getFormData作成</li>
<li>【3】入力form 初期化 clearFormInputs 関数 作る</li>
<li> [4】APIからdata取得 fetchAllData 作る</li>
<li>【5】テーブル全員分 renderTable作る</li> 
<li>【6】テーブル一件分表示 addTableRow 作る</li>
<li> [7】テーブル作成 createData作成 </li>
<li>【8】入力form送信ボタン 作る </li>
<li>【9-1】バリデーション表示させ、消すの作る [関数 :showError ] </li>
<li>【9-2】バリデーション表示　作る[関数 : validate ]</li>
<li>【9-3】エラーメッセージ初期化　作る  [関数 : clearAllErrors]  </li>
<li>【10-1】入力form送信ボタンに　data読み込みセット[追加ボタンに バリデーション追加]</li>
<li>【10-2】バリデーション消すshowErrorを、バリデーション表示関数に仕込む [追加ボタンに バリデーション追加]</li>
<li>【10-3】data送信[追加ボタンに バリデーション追加]</li>
<li>【11】addTableRow関数に「編集・削除ボタン]追加</li>
<li>【12】編集フォーム表示と非表示 作る[showEditForm / hideEditForm] ”目的 : テーブル - 編集ボタン押したら”</li>
<li>【13-1】編集イベントリスナー作る ”場所 : テーブル - 編集ボタン”</li>
<li>【13-2】編集ボタン押したら、編集formを表示非表示できるようにする（showEditForm）”場所 : テーブル - 編集ボタン”</li>
<li>【14-1】保存ボタンイベントリスナー作る ”場所 : 編集form - 保存ボタン”</li>
  <li>【14-2】保存関数 作る(updateData) ”目的 : 編集form のdata保存”</li>
  <li>【14-3】保存関数 に、バリデーション仕込む(updateData) ”目的 : 編集formでバリデーション ”</li>
  <li>【15-1】キャンセルボタンイベントリスナー作る ”場所 : 編集form - キャンセルボタン”</li>
  <li>【15-2】キャンセルボタン押したら、編集フォーム閉じる処理 作る "場所：編集form - キャンセルボタン" （hideEditForm）</li>
  <li>【16-1】削除ボタンイベントリスナー 追加 "目的：addTableRow 「削除ボタン」で削除 "</li>
  <li>【16-2】削除  関数 作成 (deleteData)"目的
  ：addTableRow 「削除ボタン」で削除 "</li>
</ul>


<br>
<h3>【おまけ】getformDataとテーブル表示"addTablerow"を一緒に処理してない理由></h3>
<p>テーブル読み込みにはいつも時間がかかり、テーブル</p>
<p>表示とテーブル読み込みを同時にしたら、dataが</p>
<p>表示できない時があるから、分けてる</p>
<br>
<p>分けてるとバグが出にくく、メンテナンスしやすい</p>


<br>
<h3>[おまけ2]バリデーション表示</h3>

```js:
  if (!validateForm(formData)) return;
```

<br>
<h3>[おまけ3]バリデーション 作る流れ</h3>
<p> → バリデーション表示させて、消す関数作成 [関数 :showError ]</p>
<p> → エラーメッセージ初期化関数　作成 [関数 : clearAllErrors]</p>
<p> → バリデーション表示関数　作成 [関数 : validate ]</p>
<p> → バリデーション消すshowErrorを、バリデーション表示関数に仕込む [場所 : validate ]</p>


<br>
<h3>[おまけ4] バリデーション使う流れ</h3>
<p> data読み込む(getform) [場所 : ボタン押す関数で] </p>
<p> エラー初期化 仕込む [場所 : ボタン押す関数で] </p>
<p> バリデーション表示関数(validate)　仕込む [場所 : ボタン押す関数で] </p>
<p> data送るか編集成功させる [createData / updateData();] </p>

```js:code例
  addButton.addEventListener('click', () => {
      const formData = getFormData('add');
        clearAllErrors(); // ★追加: 新規追加前のエラークリア
        if (!validate(formData, nameError)) return; 
        createData(formData);

  //保存ボタン
  saveEditButton.addEventListener('click', () => {
        const id = parseInt(editIdInput.value);
        const updatedData = getFormData('edit');
        clearAllErrors(); 
        if (!validate(updatedData, editNameError)) return; 
        updateData(id, updatedData);
    });
```

<br>
<h3> [おまけ5]  バリデーション code並び順 </h3>

```js:

   <script>
    // ★初期設定
    document.addEventListener('DOMContentLoaded', async () => {


    // ★バリデーション表示
function validate(data, errorElement) { 
        if (!data.name) {
    }


    // ★エラーメッセージ表示して消す
    function showError(element) {
    }


     // ★エラー初期化
    function clearAllErrors() {
    }


    // ★API読み込み
    await fetchAllData();


    // 「追加」ボタン
    addButton.addEventListener('click', () => {
    });


    // data新規作成
    async function createData(data) {
    });
```

<br>
<h3> [おまけ6]  初期化がいる関数</h3>
<p> fetchALLData "エラー初期化" </p>
<p>バリデーション (エラー初期化) </p>
<p>編集form表示 "エラー初期化" </p>
<p>編集form閉じる"入力form初期化" / "エラー初期化"</p>


<br>
<h3>[1】テーブル作成</h3>

```js:
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Axios CRUDアプリ（フォーム編集）</title>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

</head>
<body>

<form id="userForm">
    <div class="form-group">
        <label class="label" for="studentName">名前</label>
        <input type="text" id="studentName" name="studentName">
    </div>
    <div class="form-group">
        <label class="label" for="studentAge">年齢</label>
        <input type="number" id="studentAge" name="studentAge">
    </div>
    <div class="form-group">
        <label class="label" for="studentEmail">メール</label>
        <input type="email" id="studentEmail" name="studentEmail">
    </div>
    <div class="form-group">
        <label class="label" for="studentnumber">電話</label>
        <input type="text" id="studentnumber" name="studentnumber">
    </div>
</form>

<script>  ⇦ headとインデントを同じに

</script>

</body>
</html>
```


<h4>テーブルにスタイル追加[テーブル作成]</h4>

```js:
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Axios CRUDアプリ（フォーム編集）</title>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    
    // ここに追加
    <style>
      body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        .form-group { margin-bottom: 10px; }
        .label { display: inline-block; width: 80px; }

        /* テーブル全体の基本スタイル */
        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; /* ヘッダーの枠線を太く */
        }
    </style>
    // 追加終わり

</head>
```


<h4>axios初期設定　追加[テーブル作成]</h4>

```js:
 <script>

 // 3行 追加
document.addEventListener('DOMContentLoaded', async () => {
    const API_BASE_URL = 'https://jsonplaceholder.typicode.com/users';

});

</script>
```

<h4>テーブル各データの要素を作る [テーブル作成]</h4>

```js:
document.addEventListener('DOMContentLoaded', async () => {
    const API_BASE_URL = 'https://jsonplaceholder.typicode.com/users';

    // 6行 追加
    const userForm = document.getElementById('userForm');
    const nameInput = document.getElementById('studentName');
    const ageInput = document.getElementById('studentAge');
    const emailInput = document.getElementById('studentEmail');
    const phoneInput = document.getElementById('studentnumber');
    const tableBody =  document.querySelector('#studentTable tbody');
});
```


<h4>テーブル表示 html作る [テーブル作成]</h4>

```js:
    <form id="userForm">
    <div class="form-group">
        <label class="label" for="studentName">名前</label>
        <input type="text" id="studentName" name="studentName">
    </div>
    <div class="form-group">
        <label class="label" for="studentAge">年齢</label>
        <input type="number" id="studentAge" name="studentAge">
    </div>
    <div class="form-group">
        <label class="label" for="studentEmail">メール</label>
        <input type="email" id="studentEmail" name="studentEmail">
    </div>
    <div class="form-group">
        <label class="label" for="studentnumber">電話</label>
        <input type="text" id="studentnumber" name="studentnumber">
    </div>
</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>
    //ここまで
```
  

<h4>配列用意する[テーブル作成]</h4>

```js:
      const tableBody = document.querySelector('#studentTable tbody');
      
      // ここ
      let studentData = [];
```

<h3>[2-1】formから入力data取得 getFormData作成[入力data取得 : getFormData関数]</h3>

```js:
  let studentData = [];

  //　ここに追加
  function getFormData(type = 'add') {
        if (type === 'add') {
            return {
                name: nameInput.value.trim(),
                age: parseInt(ageInput.value.trim()) || 0,
                email: emailInput.value.trim(),
                phone: phoneInput.value.trim()
            };
        } else { 
            return {
                name: editNameInput.value.trim(),
                age: parseInt(editAgeInput.value.trim()) || 0,
                email: editEmailInput.value.trim(),
                phone: editPhoneInput.value.trim()
            };
        }
    }
```

<h4>[2-2: 実装より】入力/編集formから入力data取得 getFormData作成</h4>

```js:
  function getFormData(type = 'add') {
    if (type === 'add') {
        const data = { // 一度変数に格納
            name: nameInput.value.trim(),
            age: parseInt(ageInput.value.trim()) || 0,
            email: emailInput.value.trim(),
            phone: phoneInput.value.trim()
        };
        console.log('新規登録:', data); // ここにconsole.logを追加
        return data;
    } else {
        const data = { // 一度変数に格納
            name: editNameInput.value.trim(),
            age: parseInt(editAgeInput.value.trim()) || 0,
            email: editEmailInput.value.trim(),
            phone: editPhoneInput.value.trim()
        };
        console.log('編集:', data); // ここにconsole.logを追加
        return data;
    }
}
getFormData()         
getFormData('edit') 
```

### 出力結果

![スクリーンショット 2025-06-19 15.11.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628823/8030fc1e-d10d-447d-9c5e-f40c8c3cc58d.png)


<h4>getformdata消す</h4>

```js:
function getFormData() {
    }
    // getFormData();
    // getFormData('edit') 
});
```


<br>
<h3>[3] APIからdata取得 fetchAllData 作る[APIからdata取得]</h3>

```js:
  //ここに追加
  async function fetchAllData() {  ⇦ インデントはconstで
    const response = await axios.get(API_BASE_URL);
console.log("APIからの生データ:", response.data);
  }
  await fetchAllData();
  // ここまで
});

   //この上に　追加
    function getFormData() {
}
// getFormData();
```

### 出力結果

![スクリーンショット 2025-06-16 17.27.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628823/4b004396-a3e8-41c0-ad0e-a38dd158e5b7.png)


<h4>data表示させる [APIからdata取得]</h4>

```js:
    async function fetchAllData() {
    try {
        const response = await axios.get(API_BASE_URL);
        studentData = response.data.map(item => ({
            id: item.id,
            name: item.name,
            age: item.id % 40 + 20,
            email: item.email,
            phone: item.phone
        }));
        renderTable();
        console.log("整形後のデータ:", studentData);
    } catch (error) {
        console.error("データ取得エラー:", error);
    }
}
await fetchAllData();
```

<h4>さっきのcodeを、try catchにする [APIからdata取得]</h4>

```js:
async function fetchAllData() {
    try {
        const response = await axios.get(API_BASE_URL);
        studentData = response.data.map(item => ({
            id: item.id,
            name: item.name,
            age: item.id % 40 + 20,
            email: item.email,
            phone: item.phone
        }));
        renderTable();
        console.log("整形後のデータ:", studentData);
    } catch (error) {
        console.error("データ取得エラー:", error);
    }
}
await fetchAllData();
```


<br>
<h3>関数作った時の、重要ポイント</h3>
<h6>関数は作ったらすぐ呼ばないと、cosole.logできない！</h6>

```js:
    async function fetchAllData() {  
    }

    //関数は作ったら、すぐ呼ぶ！
    await fetchAllData();
```

<br>
<h3>[4]テーブル全員分 renderTable作る[]</h3>

```js:
function renderTable() {
        while (tableBody.firstChild) {
            tableBody.removeChild(tableBody.firstChild);
        }
        studentData.forEach(data => console.log("1件分のデータ:", data));
    }
    renderTable(); 

    //この上に　追加
    async function fetchAllData() {
    try {
}
await fetchAllData();
```

<br>
<h4>renderTable "studentData.forEach"変える[テーブル全員分]</h4>

```js:
  //変更前
  studentData.forEach(data => console.log("1件分のデータ:", data));

  //変更後
  studentData.forEach(data => addTableRow(data));
  console.log("render:", studentData);
  // ここまで
```

<br>
<h4>getformData　復活させる</h4>

```js:
function getFormData() {
        const name = nameInput.value.trim();
        return { name, age, email, phone };
    }

    //これ　↓
    getFormData();
    //
});
```


<h3>【5】テーブル一件分表示 addTableRow 作る</h3>

```js:
 function addTableRow(data) {
        const row = document.createElement('tr');
        row.setAttribute('data-id', data.id);

        row.innerHTML = `
            <td>${data.id}</td>
            <td>${data.name}</td>
            <td>${data.age}</td>
            <td>${data.email}</td>
            <td>${data.phone}</td>
        `;

        const tableBody = document.querySelector('#studentTable tbody');
        tableBody.appendChild(row);
        console.log("add", studentData)
    }
    addTableRow();


  //この上に　追加
function renderTable() {
        while (tableBody.firstChild) {
    }
    renderTable(); 
```

<h4>addTableRow tableBody 消去</h4>

```js:
//消去
const tableBody = document.querySelector('#studentTable tbody');
```

<h4>await fetchAllData();　消去</h4>

```js:
   async function fetchAllData() {
     console.error("データ取得エラー:", error);
    }
}

//消去
await fetchAllData();
```


<h3> [6】テーブル作成 createData作成</h3>
<h4>場所 : addTableRow の上</h4>

```js:
//ここから追加
async function createData(data) {
        const response = await axios.post(API_BASE_URL, data);
        console.log('APIから新規データが追加されました:', response.data);
            
        const newData = { 
            id: response.data.id, 
            name: data.name, 
            age: data.age, 
            email: data.email, 
            phone: data.phone 
            };
            studentData.push(newData);
            renderTable();
            // clearFormInputs();
    }
    await createData({
      name: "テスト",
      age: 30,
      email: "test@example.com",
      phone: "000-0000-0000"
    });

    //この上に　追加
    function addTableRow(data) {
        const row = document.createElement('tr');
    }
    addTableRow({ id: 1, name: "山田太郎", " });
```

<br>
<h3>【7】入力form送信ボタン追加 </h3>
<h4>追加する場所 : createDataの上</h4>

```js:
await fetchAllData();

    // 「追加」ボタンのクリックイベント
    addButton.addEventListener('click', () => {
        addButton.classList.add('clicked-button'); 
        setTimeout(() => { 
            addButton.classList.remove('clicked-button');
        }, 300);

        const formData = getFormData();
        console.log('追加ボタン発動！');
    });
```

<h4>css追加[入力form送信ボタン追加]</h4>

```js:
<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, .save-edit-button, .cancel-edit-button {
            padding: 8px 15px;
            font-size: 16px;
            cursor: pointer;
            color: white;
            border: none;
            border-radius: 4px;
            transition: background-color 0.3s ease;
        }

        #addButon {
            background-color: #007bff; /* 初期の色（青） */
        }

        /* ボタンがクリックされた後のスタイル */
        #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; /* 黄色には黒文字が見やすい */
        }

        /* 編集フォームのスタイル */
        #editForm {
            margin-top: 30px;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 8px;
            background-color: #f9f9f9;
            display: none; /* 初期状態では非表示 */
        }
        #editForm h2 {
            margin-top: 0;
            color: #333;
        }
        .edit-form-buttons {
            margin-top: 20px;
            text-align: right;
        }
        .save-edit-button {
            background-color: #28a745;
            margin-left: 10px;
        }
        .cancel-edit-button {
            background-color: #6c757d;
        }
    </style>
```

<h4>ボタン追加[入力form送信ボタン追加]</h4>

```js:
  <button type="button" id="addButon">追加</button>
```

<h4>ボタン要素作成[入力form送信ボタン追加]</h4>

```js:
const userForm = document.getElementById('userForm');
//ここに　追加
const addButton = document.getElementById('addButon');
//追加 終
```


<br>
<h3>追加ボタンを押すと、これが出る</h3>

![スクリーンショット 2025-06-18 19.47.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628823/d810d815-21f8-4c94-aff6-f1c8be069c43.png)


<h4>htmlにこれ追加[バリデーション　追加]</h4>

```js:
  <form id="userForm">
    <div class="form-group">
        <label class="label" for="studentName">名前</label>
        <input type="text" id="studentName" name="studentName">

         //ここに　追加
        <div id="nameError" class="error-message">名前を入力してください</div>
        //追加　終
        
    </div>
```


<h4>名前要素　作成[バリデーション追加]</h4>

```js:
   const phoneInput = document.getElementById('studentnumber');
   
   //１行　追加
    const nameError = document.getElementById('nameError');
 //追加　終わり
    
    const tableBody =  document.querySelector('#studentTable tbody');
```

<h3>【8-1】バリデーション表示させ、消すの作る [関数 :showError ] </h3>
<h4>追加場所 :createDataの上 </h4>

```js:
  function showError(element) {
        element.style.display = 'inline';
        setTimeout(() => { element.style.display = 'none'; }, 2000);
    }
  
  //この上に　追加
  async function createData(data) {
```

<br>
<h3>【8-2】バリデーション表示　作る[関数 : validate ]</h3>
<h4>場所 :showError の上</h4>

```js:
function validate(data, errorElement) { // ★修正: errorElementを引数に追加
        if (!data.name) {
            showError(errorElement);
            return false;
        }
        // エラーがない場合はエラーメッセージを非表示に
        errorElement.style.display = 'none'; 
        return true;
    }

    //この上に　追加
  function showError();
```

<h3>【8-3】エラーメッセージ初期化　作る  [関数 : clearAllErrors] </h3>
<h4>場所 createData の上</h4>

```js:
  function clearAllErrors() {
        nameError.style.display = 'none';
        editNameError.style.display = 'none';
    }

    
   //ここに　追加
   async function createData(data) {   
```


<h4>【9-1】入力form送信ボタンに　data読み込みセット[追加ボタンに バリデーション追加]</h4>

```js:
  addButton.addEventListener('click', () => {
        addButton.classList.add('clicked-button');
        setTimeout(() => addButton.classList.remove('clicked-button'), 300);

        //ここに　追加
        const formData = getFormData('add');
        // 追加 終
     });
```


<h4>【9-2】バリデーション消すshowErrorを、バリデーション表示関数に仕込む [追加ボタンに バリデーション追加]</h4>

```js:
    addButton.addEventListener('click', () => {
        addButton.classList.add('clicked-button');
        setTimeout(() => addButton.classList.remove('clicked-button'), 300);
        const formData = getFormData('add');

        //ここに　追加
        clearAllErrors();
        // 追加 終
```


<h4>【9-3】data送信[追加ボタンに バリデーション追加</h4>

```js:
addButton.addEventListener('click', () => {
        addButton.classList.add('clicked-button');
        setTimeout(() => addButton.classList.remove('clicked-button'), 300);
        const formData = getFormData('add');
        clearAllErrors(); 
        if (!validate(formData, nameError)) return; 
        
        //ここに　追加
        createData(formData);
        // 追加 終
    });
```


<br>
<h3>【10】入力form 初期化 clearFormInputs 作る</h3>
<h4>場所 :clearAllErrorsの下 </h4>

```js:
   function clearAllErrors() {
       
    }
    
    //この下に　追加
    function clearFormInputs(type = 'add') { // ★修正: typeを引数に追加
        if (type === 'add') {
            nameInput.value = '';
            ageInput.value = '';
            emailInput.value = '';
            phoneInput.value = '';
        } else { // type === 'edit'
            editIdInput.value = '';
            editNameInput.value = '';
            editAgeInput.value = '';
            editEmailInput.value = '';
            editPhoneInput.value = '';
        }
    }
```


<h4>【11】addTableRow関数に「編集・削除ボタン]追加</h4>

```js:
function addTableRow(data) {
            <td>${data.phone}</td>

            //ここから追加
            <td>
                <button class="action-button edit-button">編集</button>
                <button class="action-button delete-button">削除</button>
            </td>
        //ここまで
        
        `;
        tableBody.appendChild(row);

        //ここから追加
        row.querySelector('.edit-button').addEventListener('click', () => {
            showEditForm(data.id);
        });
        row.querySelector('.delete-button').addEventListener('click', () => {
            deleteData(data.id);
        });
        //ここまで
    
    }
    addTableRow({ id: 1, name: "山田太郎", age: 30, email: "yamada@example.com", phone: "090-1234-5678" });
```


### ここから、簡易手順書に移行 


# 簡易手順書リンク

https://qiita.com/drafts/8ac095361df47ba7e2b1/edit