web-dev-qa-db-fra.com

Comment supprimer un fichier de la liste de fichiers

Je construis une application Web par glisser-déposer en utilisant HTML5, je dépose les fichiers sur une div et, bien sûr, je récupère l'objet dataTransfer, ce qui me donne le FileList .

Maintenant, je veux supprimer certains fichiers, mais je ne sais pas comment, ni même si c'est possible. 

De préférence, je voudrais simplement les supprimer de la FileList; Je n'ai aucune utilité pour eux. Mais si ce n'est pas possible, devrais-je plutôt écrire dans des vérifications dans du code qui interagit avec FileList? Cela semble lourd.

75
Heilemann

Si vous souhaitez supprimer uniquement plusieurs des fichiers sélectionnés: vous ne pouvez pas. La brouillon de travail de l'API de fichier à laquelle vous êtes lié contient une note:

L'interface HTMLInputElement [HTML5] a un readonlyFileList attribut, […]
[c'est moi qui souligne]

En lisant un peu du brouillon HTML 5 Working Draft, je suis tombé sur les API input élément communes . Il semble que vous puissiez supprimer la liste de fichiers entière en définissant la propriété value de l'objet input sur une chaîne vide, comme suit:

document.getElementById('multifile').value = "";

En outre, l'article (Utilisation de fichiers d'applications Web } pourrait également présenter un intérêt.

93
Marcel Korpel

Cette question a déjà été marquée comme ayant reçu une réponse, mais j'aimerais partager certaines informations qui pourraient aider les autres utilisateurs de FileList.

Il serait pratique de traiter une liste de fichiers comme un tableau, mais les méthodes telles que sort, shift, pop et slice ne fonctionnent pas. Comme d'autres l'ont suggéré, vous pouvez copier la liste de fichiers dans un tableau. Cependant, plutôt que d'utiliser une boucle, il existe une solution simple à une ligne pour gérer cette conversion.

 // fileDialog.files is a FileList 

 var fileBuffer=[];

 // append the file list to an array
 Array.prototype.Push.apply( fileBuffer, fileDialog.files ); // <-- here

 // And now you may manipulated the result as required

 // shift an item off the array
 var file = fileBuffer.shift(0,1);  // <-- works as expected
 console.info( file.name + ", " + file.size + ", " + file.type );

 // sort files by size
 fileBuffer.sort(function(a,b) {
    return a.size > b.size ? 1 : a.size < b.size ? -1 : 0;
 });

Testé OK dans FF, Chrome et IE10 +

22
Roberto

Si vous ciblez des navigateurs permanents (Chrome, Firefox, Edge, mais fonctionne également dans Safari 9+) ou si vous pouvez vous permettre un remplissage multiple, vous pouvez transformer la liste de fichiers en un tableau en utilisant Array.from() comme ceci:

let fileArray = Array.from(fileList);

Ensuite, il est facile de gérer le tableau de Files comme n'importe quel autre tableau.

14
adlr0

Puisque nous sommes dans le royaume HTML5, voici ma solution. Le Gist est que vous poussez les fichiers dans un tableau au lieu de les laisser dans une liste de fichiers, puis vous utilisez XHR2 pour pousser les fichiers dans un objet FormData. Exemple ci-dessous.

Node.prototype.replaceWith = function(node)
{
    this.parentNode.replaceChild(node, this);
};
if(window.File && window.FileList)
{
    var topicForm = document.getElementById("yourForm");
    topicForm.fileZone = document.getElementById("fileDropZoneElement");
    topicForm.fileZone.files = new Array();
    topicForm.fileZone.inputWindow = document.createElement("input");
    topicForm.fileZone.inputWindow.setAttribute("type", "file");
    topicForm.fileZone.inputWindow.setAttribute("multiple", "multiple");
    topicForm.onsubmit = function(event)
    {
        var request = new XMLHttpRequest();
        if(request.upload)
        {
            event.preventDefault();
            topicForm.ajax.value = "true";
            request.upload.onprogress = function(event)
            {
                var progress = event.loaded.toString() + " bytes transfered.";
                if(event.lengthComputable)
                progress = Math.round(event.loaded / event.total * 100).toString() + "%";
                topicForm.fileZone.innerHTML = progress.toString();
            };
            request.onload = function(event)
            {
                response = JSON.parse(request.responseText);
                // Handle the response here.
            };
            request.open(topicForm.method, topicForm.getAttribute("action"), true);
            var data = new FormData(topicForm);
            for(var i = 0, file; file = topicForm.fileZone.files[i]; i++)
                data.append("file" + i.toString(), file);
            request.send(data);
        }
    };
    topicForm.fileZone.firstChild.replaceWith(document.createTextNode("Drop files or click here."));
    var handleFiles = function(files)
    {
        for(var i = 0, file; file = files[i]; i++)
            topicForm.fileZone.files.Push(file);
    };
    topicForm.fileZone.ondrop = function(event)
    {
        event.stopPropagation();
        event.preventDefault();
        handleFiles(event.dataTransfer.files);
    };
    topicForm.fileZone.inputWindow.onchange = function(event)
    {
        handleFiles(topicForm.fileZone.inputWindow.files);
    };
    topicForm.fileZone.ondragover = function(event)
    {
        event.stopPropagation();
        event.preventDefault();
    };
    topicForm.fileZone.onclick = function()
    {
        topicForm.fileZone.inputWindow.focus();
        topicForm.fileZone.inputWindow.click();
    };
}
else
    topicForm.fileZone.firstChild.replaceWith(document.createTextNode("It's time to update your browser."));
11
Vreenak

J'ai trouvé une solution de contournement très rapide et rapide pour cela. Testé dans de nombreux navigateurs populaires (Chrome, Firefox, Safari);

Tout d'abord, vous devez convertir FileList en un tableau

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

pour supprimer l'élément particulier utilisez cette

newFileList.splice(index,1);
8
Vicky

Je sais que c’est une vieille question, mais elle occupe une place importante dans les moteurs de recherche.

les propriétés de l'objet FileList ne peuvent pas être supprimées mais au moins sur Firefox elles peuvent être modifiées . Ma solution de contournement de ce problème consistait à ajouter une propriété IsValid=true à ces fichiers qui passaient check et IsValid=false à ceux qui ne le faisaient pas.

je passe ensuite à la liste pour vérifier que seules les propriétés avec IsValid=true sont ajoutées à FormData .

4
A. Richards

C'est impromptu, mais j'ai eu le même problème que j'ai résolu de cette façon. Dans mon cas, je téléchargeais les fichiers via une requête XMLHttp, ce qui m'a permis de poster les données clonées FileList via formdata. La fonctionnalité est que vous pouvez glisser-déposer ou sélectionner plusieurs fichiers autant de fois que vous le souhaitez (la sélection de fichiers à nouveau ne réinitialisera pas la liste de fichiers clonée), supprimez tout fichier souhaité de la liste de fichiers (clonés) et envoyez-le via xmlhttprequest tout ce qui restait là-bas. C'est ce que j'ai fait. C'est mon premier post ici, donc le code est un peu en désordre. Pardon. Ah, et j'ai dû utiliser jQuery au lieu de $ tel qu'il était dans le script Joomla.

// some global variables
var clon = {};  // will be my FileList clone
var removedkeys = 0; // removed keys counter for later processing the request
var NextId = 0; // counter to add entries to the clone and not replace existing ones

jQuery(document).ready(function(){
    jQuery("#form input").change(function () {

    // making the clone
    var curFiles = this.files;
    // temporary object clone before copying info to the clone
    var temparr = jQuery.extend(true, {}, curFiles);
    // delete unnecessary FileList keys that were cloned
    delete temparr["length"];
    delete temparr["item"];

    if (Object.keys(clon).length === 0){
       jQuery.extend(true, clon, temparr);
    }else{
       var keysArr = Object.keys(clon);
       NextId = Math.max.apply(null, keysArr)+1; // FileList keys are numbers
       if (NextId < curFiles.length){ // a bug I found and had to solve for not replacing my temparr keys...
          NextId = curFiles.length;
       }
       for (var key in temparr) { // I have to rename new entries for not overwriting existing keys in clon
          if (temparr.hasOwnProperty(key)) {
             temparr[NextId] = temparr[key];
             delete temparr[key];
                // meter aca los cambios de id en los html tags con el nuevo NextId
                NextId++;
          }
       } 
       jQuery.extend(true, clon, temparr); // copy new entries to clon
    }

// modifying the html file list display

if (NextId === 0){
    jQuery("#filelist").html("");
    for(var i=0; i<curFiles.length; i++) {
        var f = curFiles[i];
        jQuery("#filelist").append("<p id=\"file"+i+"\" style=\'margin-bottom: 3px!important;\'>" + f.name + "<a style=\"float:right;cursor:pointer;\" onclick=\"BorrarFile("+i+")\">x</a></p>"); // the function BorrarFile will handle file deletion from the clone by file id
    }
}else{
    for(var i=0; i<curFiles.length; i++) {
        var f = curFiles[i];
        jQuery("#filelist").append("<p id=\"file"+(i+NextId-curFiles.length)+"\" style=\'margin-bottom: 3px!important;\'>" + f.name + "<a style=\"float:right;cursor:pointer;\" onclick=\"BorrarFile("+(i+NextId-curFiles.length)+")\">x</a></p>"); // yeap, i+NextId-curFiles.length actually gets it right
    }        
}
// update the total files count wherever you want
jQuery("#form p").text(Object.keys(clon).length + " file(s) selected");
    });
});

function BorrarFile(id){ // handling file deletion from clone
    jQuery("#file"+id).remove(); // remove the html filelist element
    delete clon[id]; // delete the entry
    removedkeys++; // add to removed keys counter
    if (Object.keys(clon).length === 0){
        jQuery("#form p").text(Object.keys(clon).length + " file(s) selected");
        jQuery("#fileToUpload").val(""); // I had to reset the form file input for my form check function before submission. Else it would send even though my clone was empty
    }else{
        jQuery("#form p").text(Object.keys(clon).length + " file(s) selected");
    }
}
// now my form check function

function check(){
    if( document.getElementById("fileToUpload").files.length == 0 ){
        alert("No file selected");
        return false;
    }else{
        var _validFileExtensions = [".pdf", ".PDF"]; // I wanted pdf files
        // retrieve input files
        var arrInputs = clon;

       // validating files
       for (var i = 0; i < Object.keys(arrInputs).length+removedkeys; i++) {
         if (typeof arrInputs[i]!="undefined"){
           var oInput = arrInputs[i];
           if (oInput.type == "application/pdf") {
               var sFileName = oInput.name;
               if (sFileName.length > 0) {
                   var blnValid = false;
                   for (var j = 0; j < _validFileExtensions.length; j++) {
                     var sCurExtension = _validFileExtensions[j];
                     if (sFileName.substr(sFileName.length - sCurExtension.length, sCurExtension.length).toLowerCase() == sCurExtension.toLowerCase()) {
                       blnValid = true;
                       break;
                     }
                   }
                  if (!blnValid) {
                    alert("Sorry, " + sFileName + " is invalid, allowed extensions are: " + _validFileExtensions.join(", "));
                    return false;
                  }
              }
           }else{
           alert("Sorry, " + arrInputs[0].name + " is invalid, allowed extensions are: " + _validFileExtensions.join(" or "));
           return false;
           }
         }
       }

    // proceed with the data appending and submission
    // here some hidden input values i had previously set. Now retrieving them for submission. My form wasn't actually even a form...
    var fecha = jQuery("#fecha").val();
    var vendor = jQuery("#vendor").val();
    var sku = jQuery("#sku").val();
    // create the formdata object
    var formData = new FormData();
    formData.append("fecha", fecha);
    formData.append("vendor", encodeURI(vendor));
    formData.append("sku", sku);
    // now appending the clone file data (finally!)
    var fila = clon; // i just did this because I had already written the following using the "fila" object, so I copy my clone again
    // the interesting part. As entries in my clone object aren't consecutive numbers I cannot iterate normally, so I came up with the following idea
    for (i = 0; i < Object.keys(fila).length+removedkeys; i++) { 
        if(typeof fila[i]!="undefined"){
            formData.append("fileToUpload[]", fila[i]); // VERY IMPORTANT the formdata key for the files HAS to be an array. It will be later retrieved as $_FILES['fileToUpload']['temp_name'][i]
        }
    }
    jQuery("#submitbtn").fadeOut("slow"); // remove the upload btn so it can't be used again
    jQuery("#drag").html(""); // clearing the output message element
    // start the request
    var xhttp = new XMLHttpRequest();
    xhttp.addEventListener("progress", function(e) {
            var done = e.position || e.loaded, total = e.totalSize || e.total;
        }, false);
        if ( xhttp.upload ) {
            xhttp.upload.onprogress = function(e) {
                var done = e.position || e.loaded, total = e.totalSize || e.total;
                var percent = done / total;
                jQuery("#drag").html(Math.round(percent * 100) + "%");
            };
        }
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
         var respuesta = this.responseText;
         jQuery("#drag").html(respuesta);
        }
      };
      xhttp.open("POST", "your_upload_handler.php", true);  
      xhttp.send(formData);
    return true;
    }
};

Maintenant, le HTML et les styles pour cela. Je suis un débutant, mais tout cela a fonctionné pour moi et m'a pris du temps pour le comprendre.

<div id="form" class="formpos">
<!--    Select the pdf to upload:-->
  <input type="file" name="fileToUpload[]" id="fileToUpload" accept="application/pdf" multiple>
  <div><p id="drag">Drop your files here or click to select them</p>
  </div>
  <button id="submitbtn" onclick="return check()" >Upload</button>
// these inputs are passed with different names on the formdata. Be aware of that
// I was echoing this, so that's why I use the single quote for php variables
  <input type="hidden" id="fecha" name="fecha_copy" value="'.$fecha.'" />
  <input type="hidden" id="vendor" name="vendorname" value="'.$vendor.'" />
  <input type="hidden" id="sku" name="sku" value="'.$sku.'"" />
</div>
<h1 style="width: 500px!important;margin:20px auto 0px!important;font-size:24px!important;">File list:</h1>
<div id="filelist" style="width: 500px!important;margin:10px auto 0px!important;">Nothing selected yet</div>

Les styles pour ça. Je devais en marquer quelques-unes! Important de remplacer le comportement de Joomla.

.formpos{
  width: 500px;
  height: 200px;
  border: 4px dashed #999;
  margin: 30px auto 100px;
 }
.formpos  p{
  text-align: center!important;
  padding: 80px 30px 0px;
  color: #000;
}
.formpos  div{
  width: 100%!important;
  height: 100%!important;
  text-align: center!important;
  margin-bottom: 30px!important;
}
.formpos input{
  position: absolute!important;
  margin: 0!important;
  padding: 0!important;
  width: 500px!important;
  height: 200px!important;
  outline: none!important;
  opacity: 0!important;
}
.formpos button{
  margin: 0;
  color: #fff;
  background: #16a085;
  border: none;
  width: 508px;
  height: 35px;
  margin-left: -4px;
  border-radius: 4px;
  transition: all .2s ease;
  outline: none;
}
.formpos button:hover{
  background: #149174;
  color: #0C5645;
}
.formpos button:active{
  border:0;
}

J'espère que ça aide.

1
Eric

Si vous avez la chance d’envoyer une demande de publication à la base de données avec les fichiers et que vous avez les fichiers que vous souhaitez envoyer dans votre DOM

vous pouvez simplement vérifier si le fichier dans la liste de fichiers est présent dans votre DOM et bien sûr, si ce n'est pas le cas, n'envoyez pas cet élément à de DB.

0
Neku80

Merci @Nicholas Anderson simple et direct, voici votre code appliqué et mon code utilise jquery.

HTML.

<input class="rangelog btn border-aero" id="file_fr" name="file_fr[]" multiple type="file" placeholder="{$labels_helpfiles_placeholder_file}">
<span style="cursor: pointer; cursor: hand;" onclick="cleanInputs($('#file_fr'))"><i class="fa fa-trash"></i> Empty chosen files</span>

JS CODE

   function cleanInputs(fileEle){
    $(fileEle).val("");
    var parEle = $(fileEle).parent();
    var newEle = $(fileEle).clone()
    $(fileEle).remove();
    $(parEle).prepend(newEle);
}
0
Sultanos

Il y a peut-être un moyen plus élégant de faire cela, mais voici ma solution. Avec jquery

fileEle.value = "";
var parEle = $(fileEle).parent();
var newEle = $(fileEle).clone()
$(fileEle).remove();
parEle.append(newEle);

Fondamentalement, vous écrivez la valeur de l'entrée. Clonez-le et mettez le clone à la place de l'ancien.

0