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!