How to detect input type=file "change" for the same file?
I want to fire an event when the user select a file. Doin开发者_JAVA百科g 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.
- User select file
A.jpg
(event fires) - User select file
B.jpg
(event fires) - User select file
B.jpg
(event doesn't fire, I want it to fire)
How can I do it?
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="*/*" />
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
If you have tried .attr("value", "")
and didn't work, don't panic (like I did)
just do .val("")
instead, and will work fine
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 = ''
}
Here's the React-y way solution i've found that worked for me:
onClick={event => event.target.value = null}
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);
})
VueJs solution
<input
type="file"
style="display: none;"
ref="fileInput"
accept="*"
@change="onFilePicked"
@click="$refs.fileInput.value=null"
>
This work for me
<input type="file" onchange="function();this.value=null;return false;">
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="" />
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 :-)
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>
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 = ""
}
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.
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
Depending on the type of event being fired, for React you may need to adjust the solution to:
onClick={(event): string => (event.currentTarget.value = "")}
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
});
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
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
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>
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.
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}
/>
)
}
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.
精彩评论