File Input
by Tim McKay
HTML
<div id="app">
<label :for="id">Attachments</label>
<div>
<input type="file" :id="id" :ref="id" :model="test" multiple
class="input--file" @change="fileChange">
<div v-if="attachments.length" class="input-field">
<span class="input-field--trigger" @click="triggerInput(id)"></span>
<span>{{ attachments[0].name }}</span>
<button class="remove-file" @click="remove(id)">X</button>
</div>
<div v-else class="input-field" @click="triggerInput(id)">No File Selected</div>
<button @click="triggerInput(id)">
Select File
</button>
</div>
</div>
SCSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
.input--file {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
.input-field {
display: inline-block;
position: relative;
&--trigger {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
cursor: pointer;
}
}
.remove-file {
position: relative;
}
Vue
new Vue({
el: "#app",
data() {
return {
test: '',
attachments: '',
}
},
computed: {
id() {
return 'fileInput-1';
}
},
methods: {
fileChange(e) {
const files = e.target.files || e.dataTransfer.files;
console.log(files);
// reassign Object for reactivity
// files.length isn't carried over in the reassign, have to manually target it
this.attachments = Object.assign({ length: files.length }, files);
},
triggerInput(ref) {
this.$refs[ref].click();
},
remove(ref) {
const fileInput = this.$refs[ref];
fileInput.value = ''; // reset input
fileInput.dispatchEvent(new Event('change')); // trigger change event
}
}
});