質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

3710閲覧

Todoリスト タスクを削除した後のID番号が連番になるようにしたい。

gorinesia

総合スコア2

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2020/07/06 13:04

編集2020/07/06 16:08

前提・実現したいこと

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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sousuke

2020/07/06 13:30

idが増えていくことの何が問題なのかを伝えた方がいいです。連番のidを使ってどうしたいですか?
gorinesia

2020/07/06 14:17

行を削除したらIDが振り直されているようにしたいっていうことなんですが、私の表現の仕方がわかりにくいのでしょうか。 読んで頂く方に伝わるように心がけて、例を書いたりしたのですが、難しいですね。 もう少し考えて質問を編集します。
sousuke

2020/07/06 14:37

そこではなくて、言い方を変えると「欠番になるとなにが問題なのか」がわからないです。
gorinesia

2020/07/06 15:03

欠番になることでなにか問題があるわけではありません。 単純に見本通りに作りたい、といった所でしょうか。 現在作成しているToDoリストの見本がそのような仕様になっているので、それを目指して作っています。
guest

回答2

0

ベストアンサー

うーん認識違いな気がする。
表示されている左端の『質問者さんがidと言っているもの』は
『idではなくて表示中のリストの順番』だと思います。私ならそうしますが。

というかソースだといろいろ動かないゾ…試しにこうしてみてください。

diff

1 // 「todos」の中身を一覧表示するための関数を用意する // 2 const showTodos = (todos) => { 3 tableBody.textContent = ''; 4 5 // 値を1つずつ取り出し、繰り返し処理を実行 6+ // 引数増やしてインデックス取得 7- todos.forEach((todo) => { 8+ todos.forEach((todo,i) => { 9 10 // tbody要素に追加するためのtr要素を作成し、子要素としてtrを追加 // 11 const tableRecord = document.createElement('tr'); 12 tableBody.appendChild(tableRecord); 13 14 // tr要素に追加するためのtd要素をそれぞれ作成する // 15 const tableId = document.createElement('th'); 16 const tableComment = document.createElement('td'); 17 const tableStatus = document.createElement('td'); 18 const tableAction = document.createElement('td'); 19 20 // 要素の中身のテキストを表示するため、オブジェクトの要素から取得する // 21- tableId.textContent = todo.id; 22+ // インデックスを表示 23+ tableId.textContent = i; 24 tableComment.textContent = todo.comment; 25 26 // td要素をtr要素の子要素として追加する // 27 tableRecord.appendChild(tableId); 28 tableRecord.appendChild(tableComment); 29 tableRecord.appendChild(tableStatus); 30 tableRecord.appendChild(tableAction); 31 32 tableStatus.appendChild(createStatusButton(todo)); 33 // deleteのtodo.idはそのまま渡す 34 tableAction.appendChild(createDeleteButton(tableRecord, todo.id)); 35 }); 36 }; 37 38 //「状態機能」を管理するボタンを生成する関数 39 const createStatusButton = (todo) => { 40 const statusButton = document.createElement('button'); 41 statusButton.textContent = todo.status; 42 statusButton.addEventListener('click', () => { 43 if (todo.status === '作業中') { 44 todo.status = '完了'; 45 filterTodos() 46 } else { 47 todo.status = '作業中'; 48 filterTodos(); 49 } 50 }); 51 return statusButton; 52 }; 53 54 //「削除機能」を管理するボタンを生成する関数 55 const createDeleteButton = (tableRecord, id) => { 56 let index = tableRecord.rowIndex - 1; 57 const deleteButton = document.createElement('button'); 58 deleteButton.textContent = '削除'; 59 deleteButton.addEventListener('click', () => { 60 const targetIndex = todos.findIndex(todo => { 61 return todo.id === id; 62 }); 63 todos.splice(targetIndex, 1); 64 filterTodos(); 65 }); 66 return deleteButton; 67 }; 68+ // これ未定義だよ!!!!!!!!!!!!!!!!!!!!!! 69+ const radioButtonAll = document.getElementById('radio-all-select'); 70+ const radioButtonWorking = document.getElementById('radio-woking-select'); 71+ const radioButtonDone = document.getElementById('radio-done-select'); 72 // 表示・非表示の機能を管理する関数 73 const filterTodos = () => { 74 if (radioButtonAll.checked) { 75 return showTodos(todos); 76 } else if (radioButtonWorking.checked) { 77 const doingTodos = todos.filter(todo => { 78 return todo.status === '作業中' 79 }); 80 return showTodos(doingTodos); 81 } else if (radioButtonDone.checked) { 82 const doneTodos = todos.filter(todo => { 83 return todo.status === '完了' 84 }); 85 return showTodos(doneTodos); 86 } 87 }; 88

追記

削除後に振りなおすしかないでしょうね。

javascript

1 // 「追加」ボタンがクリックされたときの処理を実装する // 2 addButton.addEventListener('click', () => { 3 // ここでidをとるとキャンセルしたときにおかしい 4 inputBox.focus(); 5 6 // 空文字が入力されたときの処理 7 if (inputBox.value === '') { 8 alert('タスクを入力してください!'); 9 return; 10 } 11 //todoがtrueの場合の処理 12 // この書き方はすべてtrueなので意味なし 13 //if (todo) { 14 // push直前でid取得 15 const todo = { 16 id: todos.length, 17 comment: inputBox.value, 18 status: '作業中' 19 } 20 todos.push(todo); 21 inputBox.value = ''; 22 showTodos(todos); 23 filterTodos(); 24 //} 25 }); 26 27 //「削除機能」を管理するボタンを生成する関数 28 const createDeleteButton = (tableRecord, id) => { 29 let index = tableRecord.rowIndex - 1; 30 const deleteButton = document.createElement('button'); 31 deleteButton.textContent = '削除'; 32 deleteButton.addEventListener('click', () => { 33 const targetIndex = todos.findIndex(todo => { 34 return todo.id === id; 35 }); 36 todos.splice(targetIndex, 1); 37 // 削除後に削除id以上を振りなおす 38 for (var i = targetIndex; i < todos.length; i++) { 39 todos[i].id = i 40 } 41 filterTodos(); 42 }); 43 return deleteButton; 44 };

投稿2020/07/06 15:26

編集2020/07/06 16:46
sousuke

総合スコア3828

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gorinesia

2020/07/06 15:45 編集

アドバイスありがとうございます! 元々はtableId.textContentをindexにしてました。 それだと削除後の挙動は問題ないのですが、フィルタリングした際にidが0からになってしまうので、考えた末現在のコードになっています。 ラジオボタンのid取得のコードはteratailに載せる際に間違えて消してしまってました、すいません。 ご指摘くださり、ありがとうございます。
sousuke

2020/07/06 16:25

とりあえず削除後に正しく振りなおすしかないですね。 普通はそれをやる必要性を全く感じないので回答が付きにくいのだと思います。
gorinesia

2020/07/06 22:20

ご回答ありがとうございます! 自身のコードに反映させて、実現できました! 具体的な実装方法や的確なコメントなど、非常にわかりやすいです。 idの値の書き方や削除後にIDを振り直す方法など、とても参考になります。 質問自体に対してのアドバイスも今後に活かしていきます。 伝わりにくい質問にお付き合いくださり、ありがとうございました!
guest

0

イマイチなにをどうしたいかがわかりません。
配列なら振り直すのが楽だと思いますが・・・

投稿2020/07/06 13:31

yambejp

総合スコア114572

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yambejp

2020/07/06 13:32

var data=[ [1,"aaaaaa"], [2,"bbbbbb"], [3,"cccccc"], [4,"dddddd"], ]; data.splice(2,1);//ccccccを削除 console.log(data); data=data.sort((x,y)=>x[0]-y[0]).map((x,y)=>[y+1,x[1]]); console.log(data);
gorinesia

2020/07/06 14:20

わかりにくいのに関わらず、ご回答くださり、ありがとうございます。 もっとわかりやすく質問を編集します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問