web-dev-qa-db-ja.com

複数の「input:file」からFileListアイテムを削除する

私はこのDOMを持っています:

var id = 0;

$('input:file#upload')[0].files[ id ]

これは、0番目のインデックスの最初のファイルです。ファイルのプロパティが一覧表示され、すべて機能しますが...

DOMからアイテムを削除する方法[object FileList] with JavaScript?

13
user1386320

_FileList object_からオブジェクトを直接削除することはできません。 $('input:file#upload')[0].filesArrayに割り当て、spliceまたは任意のメソッドを使用してその配列から項目を削除し、そのArrayを使用するだけです。

12
Imran Latif

ついに道を見つけた!その前に知っていたinput.filesはFileListを受け入れますが、それを取得する唯一の方法はドラッグアンドドロップイベントを経由することでした。

しかし、今私は独自のFileListを作成する方法を知っています!

これはchrome(およびおそらく他のいくつか))で動作します

const dt = new DataTransfer()
dt.items.add(new File([], 'a.txt'))
input.files = dt.files

// This will remove the fist item when selecting many files
input.onchange = () => {
  const dt = new DataTransfer()

  for (let file of input.files)
    if (file !== input.files[0]) 
      dt.items.add(file)

  input.onchange = null // remove event listener
  input.files = dt.files // this will trigger a change event
}
<input type="file" multiple id="input">

これはFirefoxで動作します

const cd = new ClipboardEvent("").clipboardData
cd.items.add(new File(['a'], 'a.txt'))
input.files = cd.files

// This will remove the fist item when selecting many files
input.onchange = () => {
  const dt = new DataTransfer()

  for (let file of input.files)
    if (file !== input.files[0]) 
      dt.items.add(file)

  input.onchange = null // remove event listener
  input.files = dt.files // this will trigger a change event
}
<input type="file" multiple id="input">

重要なのは、入力内の各ファイルをループし、保持したいファイルを追加して、file.filesに新しいファイルのリストを割り当てる必要があることです。

8
Endless

FileList objectを削除する最も実用的な方法は、DOMからファイル入力自体を削除して、再度追加することです。これにより、ファイルリストからすべてのアイテムが削除されます。

多くの人がこれはエレガントなソリューションではないと言いますが、非常に簡単に実装でき、ほとんどの場合により優れたアプローチであり、入力ファイルで重要なこと、検証を行うことができます!

今では、FileList objectを制御するのは難しいことがわかります。個々のファイルアイテムを操作する必要がある場合は、 マルチファイルのアップロードと複数の選択(パート2)、by RAYMOND CAMDEN をお読みください。私は、ユーザーにファイルをもう一度選択させ(彼が間抜けになった場合)、何が問題かを示すエラーメッセージを表示することを好みます。これにより、ユーザーエクスペリエンスが悪くなることはありません。

注意として、入力ファイルはセキュリティ上の弱点をもたらすことに注意してください( 脆弱性:無制限のファイルアップロード )。

この投稿は実際には質問に回答しなかったので、ポイントを得られないことはわかっていますが、代替案を検討してください。私がファイルオブジェクトアイテムの削除を実装している場合、一部のファイルに問題がなくても、一部のファイルが検証に合格しなかった後にアップロードを続行しても意味がありませんでした。最終的に、ユーザーは入力ファイルを開いてプロセスをやり直す必要があります。したがって、私の場合、この機能は単に複雑さを増すだけであり、仕様では入力ファイルをそれほど制御していませんでした。

失敗したときにすべてのFileList objectを削除する検証の例を以下に示します。

function validateFormfile(inputTypeFile_id) {
  $(inputTypeFile_id).change((event) => {
    //check if files were select, if not, nothing is done
    if (event.target.files.length > 0) {
      let fileName;
      let totalsize = 0;
      let notvalidate = false;
      for (let i = 0; i < event.target.files.length; i++) {

        fileName = event.target.files[i].name;
        fileSize = event.target.files[i].size;
        if (fileName != undefined || fileName != "") {

          if (validate_fileExtension(fileName) === false) {
            notvalidate = true;
            let errorMessage = "File upload must be of 'audio', 'image', 'video', 'text', or 'pdf' format!";
            //write you error function to show error to user
            //alertpanel(errorMessage);
            console.log(errorMessage);
            break;
          }
          totalsize += Number(event.target.files[i].size);
          console.log(fileName, fileSize, "bytes");
        }
      }

      //check if file size is bigger than maxsize
      let maxsize = 10 * 1024 * 1024; //10Mb
      if (totalsize > maxsize && notvalidate === false) {
        notvalidate = true;
        let errorMessage = `Upload files cannot exceed the maximum of ${maxsize} bytes.`;
        //write you error function to show error to user
        //alertpanel(errorMessage);
        console.log(errorMessage);
      }

      if (notvalidate) {
        //select the node where to append the input file
        let inputlabel = $(inputTypeFile_id).siblings().first();
      
        //we delete the input file element to delete its FileList object content and re-append to the DOM
        $(inputTypeFile_id).remove();
        let input_file = $('<input type="file" id="upload" name="upload" accept="application/pdf, text/plain, audio/*, video/*, image/*" multiple required>');

        //append the input file after the selected inputlabel node 
        inputlabel.after(input_file);

        //re init any event listener for the re-appended element
        validateFormfile(inputTypeFile_id);
      }
    }
  });
}

function validate_fileExtension(fileName) {
  let image_extensions = new Array("bmp", "jpg", "jpeg", "jpe", "jfif", "png", "gif");
  let text_extensions = new Array("txt", "pdf");
  let video_extensions = new Array("avi", "mpeg", "mpg", "mp4", "mkv");
  let audio_extensions = new Array("mp3", "acc", "wav", "ogg");
  let allowed_extensions = image_extensions.concat(text_extensions, video_extensions, audio_extensions);
  // split function will split the fileName by dot(.), and pop function will pop the last element from the array which will give you the extension as well. If there will be no extension then it will return the fileName.
  let file_extension = fileName.split('.').pop().toLowerCase();

  for (let i = 0; i <= allowed_extensions.length; i++) {
    if (allowed_extensions[i] == file_extension) {
      return true; // valid file extension
    }
  }
  return false;
}
//init event listener to input file
$(document).ready(
    validateFormfile("#upload")
  );
label,
input {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<label for="upload">Choose File(s) (Max: 10Mb)</label>
<input type="file" id="upload" name="upload" accept="application/pdf, text/plain, audio/*, video/*, image/*" multiple required>
<br><small>text|pdf|audio|image|video</small>

これが何らかの形で役立つことを願っています。

2
Volfegan

これに対する非常に迅速で短い回避策を見つけました。多くの一般的なブラウザー(Chrome、Firefox、Safari)でテスト済み。

まず、FileListを配列に変換する必要があります

var newFileList = Array.from(event.target.files);

特定の要素を削除するには、これを使用します

newFileList.splice(index,1);
1
Vicky

いいえ、取り外し可能です。私はこれを実装し、それは間違いなく動作します。

まず、この変数を初期化する必要があります

var newImageObj = [];
var ImageNo = 0;

次に、このコードをファイル入力の変更時に記述します

$("#exampleInputFileProduct").change(function () {

            var fileUpload = document.getElementById("exampleInputFileProduct");

            //$("#mainImages").html('');
            //$("#subImages").html('');

            if (typeof (FileReader) != "undefined") {

                //Here Check File Extension
                var regex = /^([a-zA-Z0-9\s_\\.\-:])+(.jpg|.jpeg|.gif|.png)$/;


                for (var i = 0; i < fileUpload.files.length; i++) {
                    var j = 0;
                    var file = fileUpload.files[i];
                    var NewFile = fileUpload.files[i];
                    //Here Check File Size 1MB = 1000000 Bytes
                    if (file.size < 2048000) {
                        if (regex.test(file.name.toLowerCase())) {
                            var reader = new FileReader();
                            reader.onload = function (e) {

                                if ($("#mainImages").find(".item").attr("id") == "FirstSlider") {
                                    $("#mainImages").html('');
                                    $("#subImages").html('');
                                    $("#subImages").append("<div class='item active'></div>");
                                }

                                if ($("#mainImages").find(".item").hasClass("active")) {
                                    $("#mainImages").append("<div class='item " + ImageNo + "_CClass\'><i class='fa fa-times customIcon' onclick='RemoveImage(\"" + ImageNo + "_CClass\",\"" + fileUpload.files[j].name.toLowerCase() + "\")'></i><img class='CImage' src='" + e.target.result + "' alt='' /></div>");
                                } else {
                                    $("#mainImages").append("<div class='item active " + ImageNo + "_CClass'><i class='fa fa-times customIcon' onclick='RemoveImage(\"" + ImageNo + "_CClass\",\"" + fileUpload.files[j].name.toLowerCase() + "\")'></i><img class='CImage' src='" + e.target.result + "' alt='' /></div>");
                                }

                                //if ($("#subImages").find(".item").length == 0) {
                                //    $("#subImages").append("<div class='item active'></div>");
                                //} else {
                                if (($("#subImages").find(".item").find("div").length / 5) >= $("#subImages").find(".item").length) {
                                    $("#subImages").append("<div class='item'></div>");
                                }
                                //}

                                var append = 0;

                                $.each($("#subImages").find(".item"), function (p, pelement) {
                                    if (append == 0) {
                                        if ($(pelement).find("div").length != 5) {
                                            var newID = $(pelement).find("div").length;
                                            newID = newID;
                                            $(pelement).append("<div onclick='LoadImage(\"" + ImageNo + "_CClass\")' data-slide-to='" + newID + "' class='thumb " + ImageNo + "_CClass'> <img src='" + e.target.result + "' alt=''></div>");
                                            append = append + 1;
                                        }
                                    }
                                })

                                j = j + 1;

                                ImageNo = ImageNo + 1;
                            }

                            newImageObj.Push(file);

                            reader.readAsDataURL(file);
                        }
                    }
                }
            } else {
                alert("This browser does not support HTML5 FileReader.");
            }
        });

そして、ついにこの2つの機能が残りの作業に役立ちます

function LoadImage(objclass) {
            $("#mainImages").find(".item").removeClass("active");
            $("#mainImages").find("." + objclass + "").addClass("active");
        }

        function RemoveImage(objclass, ImageName) {

            $.each(newImageObj, function (e, element) {
                if ($(this)[0].name.toLowerCase().trim() == ImageName.trim()) {
                    newImageObj.pop(this);
                }
            });

            $("#mainImages").find("." + objclass + "").remove();
            $("#subImages").find(".item").find("." + objclass + "").remove();

            if ($("#mainImages").find(".item").length == 0) {
                $("#mainImages").append("<div class='item active'><i class='fa fa-times customIcon'></i><img class='CImage' src='/Content/img/DefaultProduct.gif' alt='' /></div>");
                $("#subImages").append("<div class='item active'><div data-target='#carousel' data-slide-to='0' class='thumb'> <img src='/Content/img/DefaultProduct.gif' alt=''></div></div></div>");
            } else {
                $("#mainImages").find(".item").removeClass("active");
                $("#mainImages").find(".item:first-child").addClass("active");
                $("#subImages").find(".item").removeClass("active");
                $("#subImages").find(".item:first-child").addClass("active");
            }
        }

最後に、フォームからファイルを送信すると、配列からファイルが取得されます

0
Rush.2707