Rewind Rewind - 24 days ago 7
Javascript Question

FileReader - Preparing for new file, even the same one

I have several load file html elements, eg:

<input type="file" id="loadFiles0" class="filesclass" name="file" />
<input type="file" id="loadFiles1" class="filesclass" name="file" />


I have added an event listener to them to catch changes:

// Elsewhere
function myFunction(event){
// Stuff
}

var el;
el = document.getElementById("loadFiles0");
el.addEventListener('change', myFunction, false);


As many will know, to get the load working the second time, EVEN WHEN IT IS THE SAME FILE NAME, you must set the html element's 'value' to "". This is the problem. I need to know which one of the load file elements did the call. Was it 'loadFiles0' or 'loadFiles1' etc.

myFunction looks like this - just the important bits:

function myFunction(evt){

...


// We need to remove it so this is not handled again when we set value = ""
this.removeEventListener('change', myFunction, false);

...

var reader = new FileReader();
reader.onload = function (e) {
...

// HERE IS THE PROBLEM
// I need a reference to the dom element that this is working on - call it 'ptr'
// I cannot use 'this' in this function, because that refers to 'reader'
// I need it so I can set its value to "", so even if the person reloads the same file, it will trigger a change
// But I cannot be certain if it was 'loadFiles0' or 'loadFiles1' etc
ptr.value = "";
ptr.addEventListener('change', myFunction, false);
};
}


So the question is, how can I get ptr in the reader's onload function?

Answer

I need to know which one of the load file elements did the call. Was it 'loadFiles0' or 'loadFiles1' etc.

It will be this within the event callback to myFunction, which you can then either remember in a variable (ptr, perhaps), or if you want to use ES2015 (with transpiling if necessary) you can use an arrow function.

With ptr:

function myFunction(evt){

    // ...


    this.removeEventListener('change', myFunction, false);

    var ptr = this; // *******

    // ...

    var reader = new FileReader();
    reader.onload = function (e) {
        ptr.value = "";
        ptr.addEventListener('change', myFunction, false);
    };
}

Or with an ES2015+ arrow function:

function myFunction(evt){

    // ...


    this.removeEventListener('change', myFunction, false);

    // ...

    var reader = new FileReader();
    reader.onload = e => {                                   // ***
        this.value = "";                                     // ***
        this.addEventListener('change', myFunction, false);  // ***
    };
}

Example using setTimeout to emulate the reader.onload callback:

function myFunction(e) {
  var ptr = this;
  // This emulates the reader.onload callback:
  setTimeout(function() {
    console.log("reader.onload for " + ptr.id);
  }, 10);
}
Array.prototype.forEach.call(
  document.querySelectorAll("input[type=file]"),
  function(input) {
    input.addEventListener("change", myFunction, false);
  }
);
<input type="file" id="loadFiles0">
<input type="file" id="loadFiles1">
<input type="file" id="loadFiles2">

Example with an arrow function:

// ES2015 or higher (you can transpile if necessary)
function myFunction(e) {
  // This emulates the reader.onload callback:
  setTimeout(() => {
    console.log("reader.onload for " + this.id);
  }, 10);
}
Array.prototype.forEach.call(
  document.querySelectorAll("input[type=file]"),
  function(input) {
    input.addEventListener("change", myFunction, false);
  }
);
<input type="file" id="loadFiles0">
<input type="file" id="loadFiles1">
<input type="file" id="loadFiles2">

Comments