web-dev-qa-db-fra.com

L'entrée de fichier générée/activée par programme ne déclenche pas toujours l'événement `input`

J'ai un bouton sur mon application Web, qui a le code suivant dans le gestionnaire d'événements click:

const fileInputEl = document.createElement('input');
fileInputEl.type = 'file';
fileInputEl.accept = 'image/*';

fileInputEl.addEventListener('input', (e) => {
  if (!e.target.files.length) {
    return;
  }

  // Handle files here...
});  

fileInputEl.dispatchEvent(new MouseEvent('click'));

Parfois (environ 1 sur 8), après la sélection du fichier, l'événement input ne se déclenche pas après la sélection d'un fichier. J'imagine qu'il s'agit d'un bug de navigateur lié au cycle de vie de l'élément.

N'y a-t-il pas moyen d'ajouter l'élément à la page et de le supprimer plus tard? Quelle est la bonne façon de gérer cela dans les navigateurs modernes de nos jours?

Je teste avec Google Chrome sous Windows.

JSFiddle: http://jsfiddle.net/pja1d5om/2/

14
Brad

C’est un bug très intéressant que vous avez eu ici, je n’ai pas pu le reproduire.

Y a-t-il une raison pour laquelle vous abordez une entrée de fichier comme vous le faites? Est-ce parce que vous voulez essayer de le coiffer?

J'ai lu cet article , et j'ai appliqué ce qu'il faisait. J'ai trouvé que cela fonctionnait bien. Ce que cet article essaie de faire est d’avoir une étiquette connectée à l’entrée avec un attribut for sur la balise label. Ensuite, en CSS et en JavaScript, la balise d’entrée de fichier est masquée et l’étiquette sert essentiellement de "bouton".

Par exemple...

Note J'ai apporté quelques modifications au code, mais tout en revient à Osvaldas Valutis, l'auteur de l'article mentionné ci-dessus chez CoDrops.

var inputs = document.querySelectorAll('.inputfile');

inputs.forEach(input => {

  var label = input.nextElementSibling,
    labelVal = label.innerHTML;

  input.addEventListener('change', function(e) {

    var fileName = '';

    if (this.files && this.files.length > 1)
      fileName = (this.getAttribute('data-multiple-caption') || '').replace('{count}', this.files.length);
    else
      fileName = e.target.value.split('\\').pop();

    if (fileName)
      label.querySelector('span').innerHTML = fileName;
    else
      label.innerHTML = labelVal;

  });

});
* {
  font-family: sans-serif;
  font-weight: 300;
}

.inputfile {
  display: none;
}

.inputfile+label {
  font-size: 1.25em;
  font-weight: 700;
  color: white;
  background-color: darkred;
  display: inline-block;
  padding: 10px;
  border-radius: 10px;
  border: 1px darkred solid;
  cursor: pointer;
}

.inputfile+label:hover {
  background-color: darkred;
}
<input type="file" name="file" id="file" class="inputfile" data-multiple-caption="{count} files selected" multiple />
<label for="file">Choose a file <span></span></label>

Maintenant, je sais que cela peut ne pas être exactement ce que vous recherchez, mais cela pourrait être une solution alternative que vous pourriez essayer.

0
Andrew Gremlich