前提・実現したいこと
Todoリストを作成しています。
IDについてお伺いしたいです。
タスクを削除した後のID番号が連番になるようにしたいです。
(フィルタリングしても、idは元々のidが割り振られているままの状態が前提です。)
まず、何行かタスクを追加します。
ID:0,1,2,3となっています。
ID:1のタスクを削除した場合、ID:0,2,3となります。
これはIDが振り直されていない状態です。
現状
削除前 ID コメント 状態 0 aaaaaa 1 bbbbbb ←ID:1の行のタスクを消した場合 2 cccccc 3 dddddd 削除後 ID コメント 状態 0 aaaaaa 2 cccccc 3 dddddd ←IDは振り直されない, そのまま ID: 0,2,3 となる
次に、実現したい挙動です。
ID:0,1,2,3となっています。
ID:1のタスクを削除した場合、ID:0, 2, 3ではなく、ID:0,1,2となり、IDが新しく振り直されています。
この挙動を実現したいです。
実現したい挙動
削除前 ID コメント 状態 0 aaaaaa 1 bbbbbb ←ID:1の行のタスクを消した場合 2 cccccc 3 dddddd 削除後 ID コメント 状態 0 aaaaaa 1 cccccc ←改めてIDが振り直され、ID: 0,2,3 ではなく、 ID: 0,1,2 となる 2 dddddd
該当のソースコード
HTML
1 2<!DOCTYPE html> 3<html lang="ja"> 4 5<head> 6 <meta charset="UTF-8"> 7 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 8 <title>ToDoリスト</title> 9</head> 10 11<body> 12 <h1>ToDoリスト</h1> 13 14 <form name="radioform"> 15 <label for="radio-all-select"><input type="radio" name="radio1" value="all" id="radio-all-select" checked>すべて</label> 16 <label for="radio-woking-select"><input type="radio" name="radio1" value="working" id="radio-woking-select">作業中</label> 17 <label for="radio-done-select"><input type="radio" name="radio1" value="done" id="radio-done-select">完了</label> 18 </form> 19 20 <table> 21 <thead> 22 <tr> 23 <th>ID</th> 24 <th>コメント</th> 25 <th>状態</th> 26 </tr> 27 </thead> 28 <tbody id="todo-body"></tbody> 29 </table> 30 31 <h2>新規タスクの追加</h2> 32 <label for="input-todo-box">ToDoリスト</label> 33 <input id="input-todo-box" type="text"> 34 <button id="add-button">追加</button> 35 36 <script src='main.js'></script> 37</body> 38 39</html>
JavaScript
1 2 // 入力したTodoタスクの一覧を保持する配列を定義する 3 // IDのための変数を用意する 4 const todos = []; 5 let nextId = 0; 6 7 // HTMLのID値を使って以下のDOM要素を取得する 8 // 入力ボックス 9 // 追加ボタン 10 // Todoリストを一覧表示するためのtbody 11 // ラジオボタン 12 const inputBox = document.getElementById('input-todo-box'); 13 const addButton = document.getElementById('add-button'); 14 const tableBody = document.getElementById('todo-body'); 15 const radioButton = document.getElementsByName('radio1'); 16 17 // 「追加」ボタンがクリックされたときの処理を実装する // 18 addButton.addEventListener('click', () => { 19 const todo = {id: nextId++, comment: inputBox.value, status: '作業中' } 20 inputBox.focus(); 21 22 23 // 空文字が入力されたときの処理 24 if (inputBox.value === '') { 25 alert('タスクを入力してください!'); 26 return; 27 } 28 //todoがtrueの場合の処理 29 if (todo) { 30 todos.push(todo); 31 inputBox.value = ''; 32 showTodos(todos); 33 filterTodos(); 34 } 35 }); 36 37 38 // 「todos」の中身を一覧表示するための関数を用意する // 39 const showTodos = (todos) => { 40 tableBody.textContent = ''; 41 42 // 値を1つずつ取り出し、繰り返し処理を実行 43 todos.forEach((todo) => { 44 45 // tbody要素に追加するためのtr要素を作成し、子要素としてtrを追加 // 46 const tableRecord = document.createElement('tr'); 47 tableBody.appendChild(tableRecord); 48 49 // tr要素に追加するためのtd要素をそれぞれ作成する // 50 const tableId = document.createElement('th'); 51 const tableComment = document.createElement('td'); 52 const tableStatus = document.createElement('td'); 53 const tableAction = document.createElement('td'); 54 55 // 要素の中身のテキストを表示するため、オブジェクトの要素から取得する // 56 tableId.textContent = todo.id; 57 tableComment.textContent = todo.comment; 58 59 // td要素をtr要素の子要素として追加する // 60 tableRecord.appendChild(tableId); 61 tableRecord.appendChild(tableComment); 62 tableRecord.appendChild(tableStatus); 63 tableRecord.appendChild(tableAction); 64 65 tableStatus.appendChild(createStatusButton(todo)); 66 tableAction.appendChild(createDeleteButton(tableRecord, todo.id)); 67 }); 68 }; 69 70 //「状態機能」を管理するボタンを生成する関数 71 const createStatusButton = (todo) => { 72 const statusButton = document.createElement('button'); 73 statusButton.textContent = todo.status; 74 statusButton.addEventListener('click', () => { 75 if (todo.status === '作業中') { 76 todo.status = '完了'; 77 filterTodos() 78 } else { 79 todo.status = '作業中'; 80 filterTodos(); 81 } 82 }); 83 return statusButton; 84 }; 85 86 //「削除機能」を管理するボタンを生成する関数 87 const createDeleteButton = (tableRecord, id) => { 88 let index = tableRecord.rowIndex - 1; 89 const deleteButton = document.createElement('button'); 90 deleteButton.textContent = '削除'; 91 deleteButton.addEventListener('click', () => { 92 const targetIndex = todos.findIndex(todo => { 93 return todo.id === id; 94 }); 95 todos.splice(targetIndex, 1); 96 filterTodos(); 97 }); 98 return deleteButton; 99 }; 100 101 // 表示・非表示の機能を管理する関数 102 const filterTodos = () => { 103 if (radioButtonAll.checked) { 104 return showTodos(todos); 105 } else if (radioButtonWorking.checked) { 106 const doingTodos = todos.filter(todo => {return todo.status === '作業中'}); 107 return showTodos(doingTodos); 108 } else if (radioButtonDone.checked) { 109 const doneTodos = todos.filter(todo => {return todo.status === '完了'}); 110 return showTodos(doneTodos); 111 } 112 }; 113 114 radioButton.forEach((e, number) => { 115 radioButton[number].addEventListener('click', () => { 116 filterTodos(); 117 }); 118 }); 119
発生している問題
私の実現したい機能は、
フィルタリングしてもIDは変わらない
と
タスク削除後IDが新しく振り直される
の2つを兼ね備えたものです。
どちらか1つの機能は実現できるのですが、両方の機能を実現できません。
IDを表示するに当たり、以下の2つの方法で試みました。
1. forEachの中でtd要素を作り、todos配列のindex番号をIDの値として使用。
→タスクを削除した場合、IDが振り直される。◯
→フィルタリングした場合、IDは元のIDのまま。✕
2. nextIdを定義し、id: nextId++ とする。
→タスクを削除した場合、IDが振り直される。☓
→フィルタリングした場合、IDは元のIDのまま。◯
現状nextIdのやり方でIDを定義しています。
nextId++としているのでIDが只々増えていってしまうのは承知の上なのですが、
どうすればidを振り直すことができるのか解決方法が見つけられません。
実装できない原因として、以下のものが浮かんでいます。
・定義したidの管理の仕方を把握していない。
・idの取得方法が間違っている。
・idを毎回取得する仕組みを理解していない。
試したこと
以下の2つの箇所で問題があると思い、改善を試みました。
オブジェクトに入れるID
もしくは、
td要素のtextContent
td要素のtext.Contentをtodo.idからnextId++にしてみたり、
indexやnumberを入れ替えたりしてみましたが上手くいかず、
根本的に実装方法が思いつきません。
削除ボタンを押したら、idを0から振り直す、
みたいな関数も作れるような気はするんですが、
どう作ればいいか検討が付きません。
IDをindexにした場合、逆にnextIdとした場合、
どちらも意図した挙動にならないのは理解できます。
しかし、それを解決する方法が見つけられない現状です。
どのように考えていけば良いのか、ヒントや実装方法を教えていただけたら幸いです。
以上です。
よろしくお願いいたします!
補足情報(FW/ツールのバージョンなど)
エディタ:Visual Stadio Code
回答2件
あなたの回答
tips
プレビュー