Have you ever had the case where ou have a file selector component, you clear the file model but then you can't select the same file again?

Codepen: https://codepen.io/schirrel/pen/YzRGrvq
Well its kinda hard and curious to explain.
First of all to the TL/DR:
You need to use Vue's $refs and set the input to null.
Now if you want to understand why, let's pass thru some important stuff:
First: Vue doesn't work with v-model and file input, even has a discussion about it on the offical Vue's repo: Discussion.
Now lets undestand why doesnt work, two main things:
- input with
type="file"only triggerschangeevent, while v-model listen toinputevent. -
v-modelneeds to set thevaluehtml attribute, if you ever try to do:value="myFileModel"this error will show up:
Error in nextTick: "InvalidStateError: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.
So with this comes a question: how to a clear a file, and most important, how make it possible to select again?
Lets paint a simple use case: You have your own file wrapper the uses a file input (obviously) but you save the file on the data. Example:
<template>
<label for="inputFile">
Click here to select you file
<input type="file" name="inputFile" id="inputFile" @change="selectFile" />
</label>
<span v-if="file">
File Selected {{ file.name }}
<button @click="clearFile">remove</button>
</span>
</template>
<script>
export default {
data() {
return {
file: null
};
},
methods: {
selectFile(event) {
this.file = event.target.files[0];
},
clearFile() {
this.file = null;
}
}
};
</script>
Even if clearFile is setting file as null, when selecting the file again the @change wont be triggered again. Thats why because the html value attribute still the same, the file prop on data doesn't affect it. Take a look at the codepen example.
Once we have seen that :value don't work with files, the proper way to do this is acessing the HTML <input type="file" /> and reset this value programmatically.
By adding a ref="fileInput" to the <input> and inside the clearFile method add:
this.$refs.fileInput.value = null
Now it works:
The codepen final solution: https://codepen.io/schirrel/pen/XWyjeOw
Note: this is common behavior across frameworks;

Top comments (1)
thanks for that!