353

Is there any chance to detect every file selection the user made for an HTML input of type file element?

This was asked many times before, but the usually proposed onchange event doesn't fire if the user select the same file again.

7
  • 7
    Would your code then also have to fire if the user hits Cancel then? One expects that hitting Cancel will do nothing, and I think most users would further expect that re-selecting the same file would have the same effect as Cancel. I don't know if this is possible or not but I suggest you reconsider this design anyway. Commented Aug 19, 2012 at 23:10
  • 5
    On cancel it should not fire or make it otherwise detectable. It is more meant to remove an UI ceveat: If some action is invoked after the file is choosen, the user usually expect the action to repeat if he choose the file again. Commented Aug 19, 2012 at 23:48
  • Maybe we can have this behaviour if we set the inputs value to '' after doing something with the file. But that would remove the visible filename too. However, that may be ok, as the file is actually processed and the result of that action may appear somewhere else. Commented Aug 19, 2012 at 23:52
  • Plz Explain the Que What you want to do? Commented Aug 22, 2012 at 6:34
  • 2
    All I want is to simulate the old school behaviour desktop applications have. If I 'open' the same file again in an desktop application, it is usually reloaded, or if some action is done with the file (like converting it so another format for example) this action is done again. This is what desktop users may expect from a web app too, but the file input onchange event doesn't resemble. Commented Aug 24, 2012 at 19:59

11 Answers 11

450

Set the value of the input to null on each onclick event. This will reset the input's value and trigger the onchange event even if the same path is selected.

var input = document.getElementsByTagName('input')[0];

input.onclick = function () {
  this.value = null;
};
  
input.onchange = function () {
  console.log(this.value);
};
<input type="file" value="C:\fakepath">

Note: It's normal if your file is prefixed with 'C:\fakepath'. That's a security feature preventing JavaScript from knowing the file's absolute path. The browser still knows it internally.

Sign up to request clarification or add additional context in comments.

11 Comments

I tried the demo, but (using Chrome 21) I keep getting `C:\fakepath` + then the filename I selected (excluding the path). The alert is show on every select of the same file though.
@JasperdeVries That's a security feature preventing JavaScript from knowing a file's absolute path. The browser still knows the path internally.
As an aside, null is the only permitted value for <input type="file">. So if you're trying to set it to undefined and getting an exception then that's the reason why.
It doesn't work well in IE11 unless you make a small change: demo.
It's better to put this.value = null at the end of the onchange because it's possible to active an input element without clicking on it (by using the keyboard). You can store input.files if you need to reference it later.
|
59

Use onClick event to clear value of target input, each time user clicks on field. This ensures that the onChange event will be triggered for the same file as well. Worked for me :)

onInputClick = (event) => {
    event.target.value = ''
}

<input type="file" onChange={onFileChanged} onClick={onInputClick} />

Using TypeScript

onInputClick = ( event: React.MouseEvent<HTMLInputElement, MouseEvent>) => {
    const element = event.target as HTMLInputElement
    element.value = ''
}

Comments

29
<form enctype='multipart/form-data'>
    <input onchange="alert(this.value); this.value=null; return false;" type='file'>
    <br>
    <input type='submit' value='Upload'>
</form>

this.value=null; is only necessary for Chrome, Firefox will work fine just with return false;

Here is a FIDDLE

1 Comment

simple and effective just tested in latest IE and chrome and works like a charm. Thanks for sharing it
12
handleChange({target}) {
    const files = target.files
    target.value = ''
}

3 Comments

Hey ngCourse ! Code-only answers may solve the problem but they are much more useful if you explain how they solve it. Community requires theory as well as code both to understand your answer fully.
While this code may solve the question, including an explanation of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply. From Review
Yes, This worked. But as @double-beep said, you should explain the answer. And thanks btw
10

In this article, under the title "Using form input for selecting"

http://www.html5rocks.com/en/tutorials/file/dndfiles/

<input type="file" id="files" name="files[]" multiple />

<script>
function handleFileSelect(evt) {

    var files = evt.target.files; // FileList object

    // files is a FileList of File objects. List some properties.
    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
     // Code to execute for every file selected
    }
    // Code to execute after that

}

document.getElementById('files').addEventListener('change', 
                                                  handleFileSelect, 
                                                  false);
</script>

It adds an event listener to 'change', but I tested it and it triggers even if you choose the same file and not if you cancel.

2 Comments

Considering the potentially ambiguous meaning of "change" in this case, did you try this in multiple browsers? You may want to specify which ones you tried it on as on the web, browsers aren't exactly always in consensus about these things.
What environment you use for your test? My experience with Chrome was the one I stated in the question, the change event would fire only on filename changes.
4

The selected answer (using state to set input value null) gave me an error.

I use empty strings instead

    const [fileValue, setFileValue] = React.useState("")

    <input
        onClick={() => {
           setFileValue("");
        }}
        type="file"
        value={fileValue}
        onChange={handleAddFile}
    />


Comments

2

Usage of two way binding worked for me if you are working with Angular.

Here is my HMTL

<input type="file" #upload name="upload" [(ngModel)]="inputValue"(change)='fileEvent($event)'/>

and TS..

  @ViewChild('upload') uploadBtn: HTMLElement;

  fileEvent(e: any){
    
   //file upload part... 

    this.inputValue = "";
  }

2 Comments

I guess there are many frameworks (like angular) that would make this working out of the box. But the question was meant for vanilla JS.
it is also an issue in Angular, hence ibrahim's solution. Thanks Ibrahim.
2
<input #myInput type="file" id="imgFile" (click)="$event.target.value=null"
       (change)="detectUploadedImage($event)" accept="image/*" />

Comments

1

Clearing the value of 0th index of input worked for me. Please try the below code, hope this will work (AngularJs).

          scope.onClick = function() {
            input[0].value = "";
                input.click();
            };

Comments

0

Do whatever you want to do after the file loads successfully.just after the completion of your file processing set the value of file control to blank string.so the .change() will always be called even the file name changes or not. like for example you can do this thing and worked for me like charm

   $('#myFile').change(function () {
       LoadFile("myFile");//function to do processing of file.
       $('#myFile').val('');// set the value to empty of myfile control.
    });

Comments

0

I can't use javascript in the project i'm working on.

Simply used:

<input type="file" onclick="this.value = null;" ..>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.