How to detect input type=file "change" for the same file?
Asked Answered
T

23

221

I want to fire an event when the user select a file. Doing so with .change event it works if the user changes the file every time.

But I want to fire the event if the user select the same file again.

  1. User select file A.jpg (event fires)
  2. User select file B.jpg (event fires)
  3. User select file B.jpg (event doesn't fire, I want it to fire)

How can I do it?

Telestich answered 5/11, 2010 at 19:19 Comment(1)
Does this answer your question? HTML input file selection event not firing upon selecting the same fileIcecap
D
103

You can trick it. Remove the file element and add it in the same place on change event. It will erase the file path making it changeable every time.

Example on jsFiddle.

Or you can simply use .prop("value", ""), see this example on jsFiddle.

  • jQuery 1.6+ prop
  • Earlier versions attr
Diastasis answered 7/11, 2010 at 15:14 Comment(3)
@Pekka: Not exactly. But he can just adapt it. Let's say he needs to post the file. After the post he can call a js function that will remove and add the new file selector. It is doable.Diastasis
be aware that when you use .attr("value", "") or .val("") (like suggested by @wagner-leonardi below) internet explorer will fire the change event while chrome don'tChute
since "value" is a property and not an attribute of input, the recommended jQuery usage would be .prop("value", "")Harbor
S
147

You can simply set to null the file path every time user clicks on the control. Now, even if the user selects the same file, the onchange event will be triggered.

<input id="file" onchange="file_changed(this)" onclick="this.value=null;" type="file" accept="*/*" />
Sunsunbaked answered 29/1, 2018 at 10:50 Comment(4)
I needed a solution like this. It is really short and gets the work done. Nice thinking Mariusz Wiazowski.Inalterable
Other solution is that changing value when input tag changed. But We do not expect the value be changed after select a file.Flintlock
Cool, way better than removing and adding the element in the dom again, thxMonotheism
My issue with this solution is that if the user subsequently clicks cancel that won't trigger a change event, at least in Chrome.Polychaete
D
103

You can trick it. Remove the file element and add it in the same place on change event. It will erase the file path making it changeable every time.

Example on jsFiddle.

Or you can simply use .prop("value", ""), see this example on jsFiddle.

  • jQuery 1.6+ prop
  • Earlier versions attr
Diastasis answered 7/11, 2010 at 15:14 Comment(3)
@Pekka: Not exactly. But he can just adapt it. Let's say he needs to post the file. After the post he can call a js function that will remove and add the new file selector. It is doable.Diastasis
be aware that when you use .attr("value", "") or .val("") (like suggested by @wagner-leonardi below) internet explorer will fire the change event while chrome don'tChute
since "value" is a property and not an attribute of input, the recommended jQuery usage would be .prop("value", "")Harbor
P
78

If you have tried .attr("value", "") and didn't work, don't panic (like I did)

just do .val("") instead, and will work fine

Peroxy answered 20/3, 2014 at 0:47 Comment(0)
G
64

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 = ''
}
Gettogether answered 11/2, 2019 at 14:28 Comment(0)
J
27

Here's the React-y way solution i've found that worked for me:

onClick={event => event.target.value = null}

Jacquard answered 23/10, 2019 at 17:1 Comment(2)
Thanks! Modifying your answer to @click="(e) => e.target.value = null" got me a Vue solution.Goodish
Awesome, simple and concise!Annelieseannelise
B
19

I got this to work by clearing the file input value onClick and then posting the file onChange. This allows the user to select the same file twice in a row and still have the change event fire to post to the server. My example uses the the jQuery form plugin.

$('input[type=file]').click(function(){
    $(this).attr("value", "");
})  
$('input[type=file]').change(function(){
    $('#my-form').ajaxSubmit(options);      
})
Bolick answered 24/2, 2012 at 4:34 Comment(2)
onClick fires before onChange, so this method works great for me.Uwton
I had to use $(this).val(""); for jQuery 2.2.4.Also
M
15

VueJs solution

<input
                type="file"
                style="display: none;"
                ref="fileInput"
                accept="*"
                @change="onFilePicked"
                @click="$refs.fileInput.value=null"
>
Moke answered 30/1, 2019 at 18:11 Comment(1)
Thank you for this variation answerAmylopsin
P
11

This work for me

<input type="file" onchange="function();this.value=null;return false;">
Proscribe answered 5/1, 2014 at 10:36 Comment(1)
i guess you meant something like function() { this.value = null; return false; }Fleshings
W
10

Probably the easiest thing you can do is set the value to an empty string. This forces it to 'change' the file each time even if the same file is selected again.

<input type="file" value="" />

Waterrepellent answered 11/6, 2019 at 1:9 Comment(2)
this should be the accepted answer - it requires no javascript at all.Hoskins
@AlexanderMihailov It still does, when the user actually selects the file.Vieira
K
7

Inspiring from @braitsch I have used the following in my AngularJS2 input-file-component

<input id="file" onclick="onClick($event) onchange="onChange($event)" type="file" accept="*/*" />

export class InputFile {

    @Input()
    file:File|Blob;

    @Output()
    fileChange = new EventEmitter();

    onClick(event) {
        event.target.value=''
    }
    onChange(e){
        let files  = e.target.files;
        if(files.length){
            this.file = files[0];
        }
        else { this.file = null}
        this.fileChange.emit(this.file);
    }
}

Here the onClick(event) rescued me :-)

Kopple answered 8/11, 2018 at 16:36 Comment(0)
M
6

Create for the input a click event and a change event. The click event empties the input and the change event contains the code you want to execute.

So the click event will empty when you click the input button(before the select file windows opens), therefor the change event will always trigger when you select a file.

$("#input").click(function() {
  $("#input").val("")
});

$("#input").change(function() {
  //Your code you want to execute!
});
<input id="input" type="file">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js">
</script>
Mannie answered 26/8, 2019 at 8:16 Comment(0)
M
4

The simplest way would be to set the input value to an empty string directly in the change or input event, which one mostly listens to anyways.

onFileInputChanged(event) {
     // todo: read the filenames and do the work
     
     // reset the value directly using the srcElement property from the event
     event.srcElement.value = ""
}
Malacostracan answered 30/8, 2020 at 19:5 Comment(0)
L
3

If you don't want to use jQuery

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

It works fine in Firefox, but for Chrome you need to add this.value=null; after alert.

Lafave answered 20/9, 2014 at 12:58 Comment(0)
W
3

By default, the value property of input element cleared after selection of files if the input have multiple attributes. If you do not clean this property then "change" event will not be fired if you select the same file. You can manage this behavior using multiple attribute.

<!-- will be cleared -->
<input type="file" onchange="yourFunction()" multiple/>
<!-- won't be cleared -->
<input type="file" onchange="yourFunction()"/>

Reference

Wavelet answered 30/5, 2018 at 9:40 Comment(0)
W
3

Depending on the type of event being fired, for React you may need to adjust the solution to:

onClick={(event): string => (event.currentTarget.value = "")}

Whisenant answered 11/6, 2021 at 17:50 Comment(0)
K
3

If you are using React, just add a key so that you can solve this problem.

let uid = 0;

function Example() {
  const [fileState, setFileState] = useState({
    key: uid,
  });

  function handleChangeSelectFile() {
    setFileState({
      key: ++uid,
    })
  }

  return (
    <input
      type="file"
      accept="image/jpeg,image/png"
      key={fileState.key}
      onChange={handleChangeSelectFile}
    />
  )
}
Kodiak answered 20/9, 2022 at 6:58 Comment(0)
K
2

You can't make change fire here (correct behavior, since nothing changed). However, you could bind click as well...though this may fire too often...there's not much middle ground between the two though.

$("#fileID").bind("click change", function() {
  //do stuff
});
Kellam answered 5/11, 2010 at 19:20 Comment(2)
It seems you are just repeating his words and .click() is not "fire on re-select".Diastasis
@Diastasis - No, it's not...but I think you read over the portion where I say you can't do this, the click is as close as it gets.Kellam
T
2

Same issue with Angular 11. I needed to display a list of downloaded files. Once in the list, these files can be deleted. So I couldn't delete a file and re-upload it directly or upload the same file several times in a row.

Previous code: https://stackblitz.com/edit/angular-bxpsgn?file=src/app/app.component.ts

I solved the issue by adding a controller to the input file and resetting its value when a file is uploaded. I just had to fetch the files via the reference of the input, as the value of the input is the path of the uploaded files.

Fixed code : https://stackblitz.com/edit/angular-ivy-noynch?file=src/app/app.component.ts

Topi answered 4/3, 2022 at 13:52 Comment(0)
A
1

You can use form.reset() to clear the file input's files list. This will reset all fields to default values, but in many cases you may be only using the input type='file' in a form to upload files anyway. In this solution there is no need to clone the element and re-hook events again.

Thanks to philiplehmann

Antepast answered 9/2, 2016 at 15:20 Comment(0)
V
1

I ran into same issue, i red through he solutions above but they did not get any good explanation what was really happening.

This solution i wrote https://jsfiddle.net/r2wjp6u8/ does no do many changes in the DOM tree, it just changes values of the input field. From performance aspect it should be bit better.

Link to fiddle: https://jsfiddle.net/r2wjp6u8/

<button id="btnSelectFile">Upload</button>

<!-- Not displaying the Inputfield because the design changes on each browser -->
<input type="file" id="fileInput" style="display: none;">
<p>
  Current File: <span id="currentFile"></span>
</p>
<hr>
<div class="log"></div>


<script>
// Get Logging Element
var log = document.querySelector('.log');

// Load the file input element.
var inputElement = document.getElementById('fileInput');
inputElement.addEventListener('change', currentFile);

// Add Click behavior to button
document.getElementById('btnSelectFile').addEventListener('click', selectFile);

function selectFile() {
  if (inputElement.files[0]) {
    // Check how manyf iles are selected and display filename
    log.innerHTML += '<p>Total files: ' + inputElement.files.length + '</p>'
    // Reset the Input Field
    log.innerHTML += '<p>Removing file: ' + inputElement.files[0].name + '</p>'
    inputElement.value = '';
    // Check how manyf iles are selected and display filename
    log.innerHTML += '<p>Total files: ' + inputElement.files.length + '</p>'
    log.innerHTML += '<hr>'
  }

  // Once we have a clean slide, open fiel select dialog.
  inputElement.click();
};

function currentFile() {
    // If Input Element has a file
  if (inputElement.files[0]) {
    document.getElementById('currentFile').innerHTML = inputElement.files[0].name;
  }
}

</scrip>
Vizor answered 20/7, 2018 at 22:32 Comment(0)
S
1

Believe me, it will definitely help you!

// there I have called two `onchange event functions` due to some different scenario processing.

<input type="file" class="selectImagesHandlerDialog" 
    name="selectImagesHandlerDialog" 
    onclick="this.value=null;" accept="image/x-png,image/gif,image/jpeg" multiple 
    onchange="delegateMultipleFilesSelectionAndOpen(event); disposeMultipleFilesSelections(this);" />


// delegating multiple files select and open
var delegateMultipleFilesSelectionAndOpen = function (evt) {

  if (!evt.target.files) return;

  var selectedPhotos = evt.target.files;
  // some continuous source

};


// explicitly removing file input value memory cache
var disposeMultipleFilesSelections = function () {
  this.val = null;
};

Hope this will help many of you guys.

Serilda answered 20/10, 2018 at 19:12 Comment(0)
F
1

For the Angular applications, you can do the following:

Template of the component (.html)

<input
  #uploadInput
  type="file"
  multiple
  (change)="yourMethod(uploadInput.files)"
  (click)="resetUploadedDocuments($event)"
/>

TypeScript file of the component (.ts)

resetUploadedDocuments(event: MouseEvent) {
  (event.target as HTMLInputElement).value = null;
}
Fribourg answered 20/10, 2023 at 7:41 Comment(0)
P
0

So, there is no way to 100% be sure they are selecting the same file unless you store each file and compare them programmatically.

The way you interact with files (what JS does when the user 'uploads' a file) is HTML5 File API and JS FileReader.

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

https://scotch.io/tutorials/use-the-html5-file-api-to-work-with-files-locally-in-the-browser

These tutorials show you how to capture and read the metadata (stored as js object) when a file is uploaded.

Create a function that fires 'onChange' that will read->store->compare metadata of the current file against the previous files. Then you can trigger your event when the desired file is selected.

Passerby answered 9/10, 2018 at 13:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.