1

I am trying to simulate a input[type=file] through a normal <button>, in most time it works well, but sometimes the change event would just not be fired.

var count = 0;
button.addEventListener('click', function (e) {
  const input = document.createElement('input');
  input.setAttribute('type', 'file');
  input.onchange = function (e) {
    const file = e.target.files && e.target.files[0];
    if (file) {
        $('span').text(`file size: ${file.size}, action count: ${++ count}`);
    }
  };
  document.body.appendChild(input);
  input.click();
  document.body.removeChild(input);
}, false)

jsfiddle

Here are the steps to reproduce the problem:

  1. click on the button, and select a file.
  2. see if the action count increases.
  3. repeat steps above

Normally, the action count increases by 1 each time after selecting a file, even if the same file as before (so this is not the value-not-changed kind of problem).

However, sometimes after choosing a file, nothing happens. Actually this happens quite often but irregular. For example, I just repeated the steps above for 7 times and got an event loss. Sometimes I have to repeat it for tens of times before a loss. To users who choose files very often, this becomes an obvious problem.

This seems to happen only on Chrome, reproduced on Chrome 48-51, I'm wondering if anyone happens to meet the same problem and gets a solution for it? Thanks.

Gerald
  • 888
  • 1
  • 7
  • 17

1 Answers1

0

Reusing the input element helps:

const input = document.createElement('input');
input.type = 'file';

button.addEventListener('click', function() {
  input.onchange = function() {
    // deal with input.files here
  };

  input.value = '';
  input.click();
}, false);

In your case it isn't even necessary to replace input.onchange every time, since it doesn't depend on the closure of button's onClick handler (so you just reset the value and trigger a click event), but I decided to write it this way in case somebody does need the closure (like I did).

Putting input.click() in a setTimeout seemed to help too, but then it broke on a heavier page.

As to why this is happening - I have no idea. Been digging and debugging for hours, nada. There's a very similar question posted a month after yours, still unanswered too.

Alec Mev
  • 4,663
  • 4
  • 30
  • 44