質問するログイン新規登録
JavaScript

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

2回答

1205閲覧

addEventListenerの挙動について

ngk10

総合スコア8

JavaScript

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

2クリップ

投稿2025/06/24 08:51

0

2

実現したいこと

動的に作成されるbuttonタグにaddEventListenerを付与し、buttonタグの削除機能を実装したい。
また、buttonタグのindexとfilesのindexを紐づけ、タグが削除されるとfilesからも削除されるようにしたい。

前提

ここに質問の内容を詳しく書いてください。
以下の要件でファイルアップロード機能を作成しています。
・ファイルを選択またはドラッグすると、選択済ファイルとしてファイル名が画面に表示される。
・選択した複数ファイルを一括でアップロードできる。
・選択したファイルは×ボタンで取り消しが可能。

tagDeleteが発火すると紐付くbuttonタグが消えるところまでは確認できましたが、fileDeleteがうまく挙動しません。
例えばファイルを3つ選択した後、0番目のファイルを消したときにconsoleに表示されるのは"0"のみであってほしいのですが、for文が回った回数だけ(この場合3回)0が表示されます。
※本来、fileDeleteにindexを渡してfileList.filesから該当のファイルを消す処理を入れたいのですが、今は確認のためconsole.logでindexを表示するのみにしています。

また、ドラッグ部分まで処理が追い付いていないのでその部分は無視してください。
ごちゃごちゃやってしまったので中途半端な見づらいコードで申し訳ありませんが、お知恵を拝借できればと思います。

該当のソースコード

html

1<div>アップロード用画面です</div> 2<form action="test.html" method="post" enctype="multipart/form-data" > 3 <div id="upFileWrap"> 4 <div id="inputFile"> 5 <!-- ドラッグ&ドロップエリア --> 6 <p id="dropArea"> 7 アップロードするファイルをドロップ<br />またはファイルを選択してください 8 </p> 9 10 <!-- 通常のinput[type=file] --> 11 <div id="inputFileWrap"> 12 <input type="file" name="uploadFile" id="uploadFile" multiple/> 13 <div id="btnInputFile"><span>ファイルを選択</span></div> 14 </div> 15 </div> 16 <div id="droppedFile"></div> 17 <div id="sendBtnArea"> 18 <button id="sendBtn">アップロード</button> 19 </div> 20 <div>ドロップ済 21 <ul id="showFiles"></ul> 22 </div> 23 </form>

js

1// ドラッグ&ドロップエリアの取得 2var fileArea = document.getElementById("dropArea"); 3 4// input[type=file]の取得 5var fileInput = document.getElementById("uploadFile"); 6var showFiles = document.getElementById('showFiles'); 7var fileList = new DataTransfer(); 8var fileDelete; 9var tagDelete; 10var allDroppedFiles = []; 11 12fileDelete = function(e){ 13 //本来ここでfileList.files[this.name]を削除してfileInput.filesに入れたい。 14 console.log(this.name); 15} 16 17tagDelete = function(){ 18 this.closest('li').remove(); 19 } 20 21// ドラッグオーバー時の処理 22fileArea.addEventListener("dragover", function (e) { 23 e.preventDefault(); 24 fileArea.classList.add("dragover"); 25}); 26 27// ドラッグアウト時の処理 28fileArea.addEventListener("dragleave", function (e) { 29 e.preventDefault(); 30 fileArea.classList.remove("dragover"); 31}); 32 33// ドロップ時の処理 34fileArea.addEventListener("drop", function (e) { 35 e.preventDefault(); 36 fileArea.classList.remove("dragover"); 37 38 // ドロップしたファイルの取得 39 //dt.items.add(e.dataTransfer.files[0]); 40 41 // 取得したファイルをinput[type=file]へ 42 //fileInput.files = dt.files; 43 44 if (typeof files[0] !== "undefined") { 45 //ファイルが正常に受け取れた際の処理 46 } else { 47 //ファイルが受け取れなかった際の処理 48 } 49}); 50 51//ドロップ済ファイル表示 52fileInput.addEventListener('change', (e) => { 53 allDroppedFiles.forEach(allDroppedFile => { 54 allDroppedFile.removeEventListener('click', event); 55 }); 56 console.log('全てのイベントリスナーが削除されました'); 57 58 const files = e.target.files; 59 for (let i = 0; i < files.length; i++) { 60 const li = document.createElement('li'); 61 const btn = document.createElement('button'); 62 btn.textContent = "×"; 63 btn.className = 'deleteBtn'; 64 li.textContent = files[i].name; 65 li.appendChild(btn); 66 showFiles.appendChild(li); 67 fileList.items.add(files[i]); 68 } 69 70 allDroppedFiles = document.querySelectorAll('.deleteBtn'); 71 //console.log(allDroppedFiles.length); 72 for (let index = 0; index <allDroppedFiles.length; index++){ 73 allDroppedFiles[index].addEventListener("click",tagDelete); 74 //allDroppedFiles[index].addEventListener("click",fileDelete); 75 allDroppedFiles[index].addEventListener("click",{name: index, handleEvent: fileDelete}); 76 } 77}); 78

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

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

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

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

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

guest

回答2

0

ベストアンサー

とりあえず受け取る側の確認はPHPを想定しておきます

削除ボタンから削除するのはあくまでもリストだけにしておき、送信時にformdataイベントでリストにないものはfilelistから削除する

html

1<?PHP 2print_r($_FILES); 3?> 4<style> 5#dropArea{ 6 border:1px solid; 7 position:relative; 8 height:200px; 9} 10#uploadFile{ 11 position:absolute; 12 top:0; 13 width:100%; 14 height:100%;; 15 opacity:0; 16} 17</style> 18<script> 19window.addEventListener('DOMContentLoaded', ()=>{ 20 uploadFile.addEventListener("change",e=>{ 21 showFiles.textContent=""; 22 const fragment =[...uploadFile.files].reduce((x,y)=>{ 23 const li=tmp.content.querySelector('li').cloneNode(true); 24 li.querySelector('span').textContent=y.name; 25 x.appendChild(li); 26 return x; 27 },document.createDocumentFragment()); 28 showFiles.appendChild(fragment); 29 }); 30 document.addEventListener("click",e=>{ 31 const t=e.target; 32 if(t.matches('#showFiles .del')){ 33 t.closest('li').remove(); 34 } 35 }); 36 document.addEventListener('formdata', e=>{ 37 const f=e.formData; 38 const name=uploadFile.name; 39 const fileList=f.getAll(name).filter(i=>[...showFiles.querySelectorAll('span')].map(x=>x.textContent).includes(i.name)); 40 f.delete(name); 41 fileList.forEach(file=>{ 42 f.append(name,file); 43 }); 44 }); 45}); 46</script> 47<template id="tmp"> 48<li><span></span><input type="button" value="x" class="del"></li> 49</template> 50<form method="post" enctype="multipart/form-data" > 51<div id="dropArea"> 52<div>アップロードするファイルをドロップ<br />またはファイルを選択してください</div> 53<input type="file" name="uploadFile[]" id="uploadFile" multiple/> 54</div> 55<input type="submit"> 56<ul id="showFiles"></ul> 57</form>

投稿2025/06/25 03:41

編集2025/06/25 06:09
yambejp

総合スコア117975

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

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

ngk10

2025/06/26 05:48

ご回答ありがとうございました。 ご提供いただいたコードを自分なりに嚙み砕き、きちんと理解できた気がします。 とても助かりました、また機会がありましたらよろしくお願いいたします!
guest

0

for文で毎回ループしているのが原因ですので、btn.addEventListener("click", { name: i, handleEvent: fileDelete });などと、ボタンを作成したタイミングでイベントを設定すればいいのではないでしょうか。

ただ、インデックスを使った結合ですと、何度か削除をしているとFileListのインデックスとズレると思うのですが、それはどのように対処する予定だったのか気になります。

投稿2025/06/24 09:47

Lhankor_Mhy

総合スコア37517

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

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

Lhankor_Mhy

2025/06/24 09:53

あー、removeEventListener で毎回全部イベントを消そうとしているんですね。なるほど。 そうだとすると、イベントを設定したときの引数をきちんと再現しないと消えないですね。 https://developer.mozilla.org/ja/docs/Web/API/EventTarget/removeEventListener イベントハンドラをどこかに保存しておくぐらいだったら、ボタンとファイルをもう少し強く結合させておく方が早そうな気がします。 または、AbortSignal で全停止するとか。 https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener#options
Lhankor_Mhy

2025/06/24 10:08

よく考えると、tagDelete をしたときもインデックスがずれるはずなので、毎回全消去する方法ならそっちでもイベントのツケ直しが必要ですね。
ngk10

2025/06/26 05:51

ご回答ありがとうございました! よくわからないまま使ってしまいましたが今後のためにEventListenerの使い方をもっと勉強します。 またお世話になる機会がありましたらどうぞよろしくお願いします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.30%

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

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

質問する

関連した質問