Reputation: 4725
I want to force the user to only select a CSV or excel file.
Please see this minimum example:
<input type="file" accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel">
Although I can use accept
property to force the file selector not to select other files, I can still use drag and drop files directly from Finder, and it will works--the accept
property will be ignored.
Is it possible to prevent this?
Upvotes: 3
Views: 1708
Reputation: 961
You just have to add an event listener and function to either accept or reject the file:
fileInput.addEventListener("change", func);
var func = function() {
if(fileInput.files[0].type == /*insert your file types here*/) {
//accept file and do stuff with it
} else {
//reject and tell user that is was rejected and why
}
}
I am not sure this works with the drag & drop file input, but I know it works with the regular type. The change
event is called whenever the file changes.
Upvotes: 0
Reputation: 89442
You will need to perform server-side validation, but you can make the user experience better by checking the type of the file against a Set
of allowed types.
const allowedTypes = new Set(['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel']);
document.querySelector('input[type=file]').addEventListener('change', function(){
if(!allowedTypes.has(this.files[0].type)){
console.log("Not a CSV file");
this.value = '';//clear the input for invalid file
} else {
console.log("CSV file");
}
});
<input type="file" accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel">
Upvotes: 3
Reputation: 2829
Note that csv files has many MimeTypes so you should check for more than
"application/vnd.ms-excel"
=> .CSV Mimetypes, and you can check against that in client side
as well by comparing the type of the file against an array of your accepted types
that way you can add or delete the way that fits your needs
// the list of the accepted types since we need it always it's better to
// make it global instead of local to the onchange litener, and even you can
// add other types dynamically as well;
const acceptedTypes = ["text/csv", "text/x-csv", "application/x-csv", "application/csv", "text/x-comma-separated-values", "text/comma-separated-values", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-excel"];
document.querySelector("[type='file']").onchange = function() {
if(!acceptedTypes.includes(this.files[0].type)) {
console.log("This file is not allowed for upload");
// if the file is not allowed then clear the value of the upload element
this.value = "";
}
};
And if you want this behaviour only when the user drags and drops the file then you can customize it like this
const acceptedTypes = ["text/csv", "text/x-csv", "application/x-csv", "application/csv", "text/x-comma-separated-values", "text/comma-separated-values", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-excel"];
// global variable to hold if the user has dragged the file or not
let isDragged = false;
// the `ondragover` gets triggered before the `onchange` event so it works as expected
document.querySelector("[type='file']").ondragover = function() {
isDragged = true;
};
document.querySelector("[type='file']").onchange = function() {
// if there was no drag then do nothing
if(!isDragged) return;
if(!acceptedTypes.includes(this.files[0].type)) {
console.log("This file is not allowed for upload");
// if the file is not allowed then clear the value of the upload element
this.value = "";
}
isDragged = false;
};
Upvotes: 1