web-dev-qa-db-fra.com

Comment définir la valeur d'entrée d'un fichier lors de la suppression d'un fichier sur une page?

J'essaie de créer un contrôle dans lequel vous pouvez à la fois sélectionner un fichier à soumettre dans le formulaire et y déposer un fichier pour faire la même chose. J'ai quelque chose comme ceci où il montrera également un aperçu du fichier s'il s'agit d'une image:

<div class="preview-image-container">

  <input type="file" name="File" id="File" accept="image/*" 
         class="image-url form-control" style="display:none;" />

  <div class="preview-image-dummy"></div><img class="preview-image-url" />
  <div class="preview-image-instruction">
    <div class="preview-image-btn-browse btn btn-primary">Select file</div>
    <p>or drop it here.</p>
  </div>

</div>

Voici un violon avec MCVE .

L'utilisateur dépose le fichier dans le preview-image-container. Le fichier n'est pas soumis avec AJAX, l'utilisateur doit soumettre le formulaire contenant davantage de données.

Pour des raisons de sécurité, nous ne sommes pas autorisés à modifier la valeur du fichier d'entrée avec JavaScript. Cependant, je sais que le fichier d’entrée par défaut supporte la suppression et qu’il existe de nombreux sites Web qui nous permettent de sélectionner des fichiers en les déposant sous la forme. J’imagine donc qu’il existe un moyen de le faire.

Comme vous pouvez le voir sur le site MCVE, je ne suis intéressé que par l’utilisation de jQuery ou de JavaScript pur sans bibliothèques supplémentaires.

Bien que dropzone.js puisse être utilisé, il ne correspond pas à mes besoins et il faudrait un temps considérable pour personnaliser son apparence. De plus, dropzone.js a certaines exigences de configuration qui ne peuvent pas être satisfaites dans mon application ASP.NET.


Il y a une question similaire mais n'a pas de réponse appropriée:
Comment définir un objet fichier dans un fichier d’entrée sous la forme HTML?

Également pas similaire à glisser le fichier d'entrée des images glisser et aperçu avant le téléchargement parce que j'ai déjà réalisé l'action glisser-déposer et aperçu. Ma question concerne spécifiquement le problème de la saisie d'un fichier vide lors de la suppression du fichier dans un conteneur parent.

49
Tristan

Avertissement: correct à compter de décembre 2017 et uniquement pour les navigateurs modernes.


TL; DR: Oui, maintenant vous pouvez!

* si vous avez un objet dataTransfer ou FileList

Auparavant , la modification par programme du champ de fichiers input[type=file] était désactivée en raison de vulnérabilités de sécurité héritées, résolues dans les navigateurs modernes.

Le dernier des principaux navigateurs (Firefox) nous a récemment permis de définir les fichiers pour le champ de fichier d'entrée. Selon Test du W3C , il semble que vous puissiez déjà le faire sur Google Chrome!

Capture d'écran pertinente et texte cité de MDN:

enter image description here

Vous pouvez définir et obtenir la valeur de HTMLInputElement.files dans tous les navigateurs modernes.
Compatibilité source et navigateur, voir MDN

Le fil Firefox discussion sur la correction de bugs a cette démonstration ) que vous pouvez tester , et voici la source si vous voulez l'éditer . Pour référence future au cas où ce lien mourrait, je l'inclurai également en tant qu'extrait exécutable ci-dessous:

let target = document.documentElement;
let body = document.body;
let fileInput = document.querySelector('input');

target.addEventListener('dragover', (e) => {
  e.preventDefault();
  body.classList.add('dragging');
});

target.addEventListener('dragleave', () => {
  body.classList.remove('dragging');
});

target.addEventListener('drop', (e) => {
  e.preventDefault();
  body.classList.remove('dragging');
  
  fileInput.files = e.dataTransfer.files;
});
body {
  font-family: Roboto, sans-serif;
}

body.dragging::before {
  content: "Drop the file(s) anywhere on this page";
  position: fixed;
  left: 0; width: 100%;
  top: 0; height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 1.5em;
  background-color: rgba(255, 255, 0, .3);
  pointer-events: none;
}

button, input {
  font-family: inherit;
}

a {
  color: blue;
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
      <link href="https://fonts.googleapis.com/css?family=Roboto:400,400i,700" rel="stylesheet"> 

  <title>JS Bin</title>
</head>
<body>
  
  <h1>Drag and drop files into file input</h1>
  
  <p><small>Supported in <a href="https://github.com/whatwg/html/issues/2861">WebKit and Blink</a>. To test, drag and drop one or more files from your operating system onto this page.</small></p>
  
  <p>
    <input type="file">
  </p>

</body>
</html>

Remarque importante:

Vous ne pouvez le faire que si vous avez un objet FileList OR dataTransfer que vous pouvez affecter à l'élément de fichier d'entrée (car la méthode setter n'accepte pas les chaînes de texte brut). ).

Pour plus d'informations, voir la réponse de Kaiido ici: Comment définir les propriétés File et length sur les objets FileList où les fichiers sont également répercutés sur les objets FormData?


Maintenant, pour répondre à votre question initiale, cela devrait être aussi simple que cela:

document.querySelector('.preview-image-instruction')
    .addEventListener('drop', (ev) => {
        ev.preventDefault();
        document.querySelector('.image-url').files = ev.dataTransfer.files;
    });
65
Samuel Liew