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 triggerschange
event, while v-model listen toinput
event. -
v-model
needs to set thevalue
html 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!