52

I'm using Vuetify.js components for my front-end in Vue.js and want to create a user registration form with file upload. I'm able to create the form using v-text-field (a Vuetify component).

  • How can I upload the file that is selected (input)?
  • Which component should I use or is there any other alternative way?
mcd
  • 706
  • 4
  • 25
praneet drolia
  • 671
  • 1
  • 6
  • 15

4 Answers4

61

Vue JS do not have file-input feature till today, so you can tweak v-text-field to work like image input field. The concept is, create an file input field and then hide it using css, and add an event in v-text-field to trigger that specific file input field to upload image. I have attached snippet please do play with that, and I also do have a fiddle created using vue and vuetify, visit here. Thanks!

new Vue({
  el: '#app',
  data: () => ({
    title: "Image Upload",
    dialog: false,
    imageName: '',
    imageUrl: '',
    imageFile: ''
  }),

  methods: {
    pickFile() {
      this.$refs.image.click()
    },

    onFilePicked(e) {
      const files = e.target.files
      if (files[0] !== undefined) {
        this.imageName = files[0].name
        if (this.imageName.lastIndexOf('.') <= 0) {
          return
        }
        const fr = new FileReader()
        fr.readAsDataURL(files[0])
        fr.addEventListener('load', () => {
          this.imageUrl = fr.result
          this.imageFile = files[0] // this is an image file that can be sent to server...
        })
      } else {
        this.imageName = ''
        this.imageFile = ''
        this.imageUrl = ''
      }
    }
  }
})
<link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet">
<link href="https://unpkg.com/vuetify/dist/vuetify.min.css" rel="stylesheet">
<div id="app">
  <v-app>
    <v-toolbar dark color="primary">
      <v-toolbar-side-icon></v-toolbar-side-icon>
      <v-toolbar-title class="white--text">{{ title }}</v-toolbar-title>
      <v-spacer></v-spacer>
      <v-btn icon @click="dialog = !dialog">
        <v-icon>link</v-icon>
      </v-btn>
    </v-toolbar>
    <v-content>
      <v-container fluid>
        <v-flex xs12 class="text-xs-center text-sm-center text-md-center text-lg-center">
          <img :src="imageUrl" height="150" v-if="imageUrl"/>
          <v-text-field label="Select Image" @click='pickFile' v-model='imageName' prepend-icon='attach_file'></v-text-field>
          <input
            type="file"
            style="display: none"
            ref="image"
            accept="image/*"
            @change="onFilePicked"
          >
        </v-flex>
        <v-dialog v-model="dialog" max-width="290">
          <v-card>
            <v-card-title class="headline">Hello World!</v-card-title>
            <v-card-text>
              Image Upload Script in VUE JS
              <hr>
              Yubaraj Shrestha
              <br>http://yubarajshrestha.com.np/
            </v-card-text>
            <v-card-actions>
              <v-spacer></v-spacer>
              <v-btn color="green darken-1" flat="flat" @click.native="dialog = false">Close</v-btn>
            </v-card-actions>
          </v-card>
        </v-dialog>
      </v-container>
    </v-content>
  </v-app>
</div>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify/dist/vuetify.js"></script>

Latest version (V2.0.5) while editing this post dated Aug 11, 2019, there's a dedicated file input option. Please follow the link below for official documentation: https://vuetifyjs.com/en/components/file-inputs.

avi12
  • 2,000
  • 5
  • 24
  • 41
Yubaraj Shrestha
  • 864
  • 1
  • 10
  • 16
  • For the click function in the v-text-field I had to do like this @click.stop="pickFile" to get it to work – Lars Ladegaard Jul 25 '18 at 10:08
  • 1
    I've been using this solution, which looks so nice and clean by the way, for the past few months, and we just started noticing some strange behavior. The `@change="onFilePicked"` event doesn't seem to fire after uploading a document and leaves the `v-text-field` for the file blank. Has anyone seen similar behavior? – Purple Lady Mar 20 '19 at 21:30
  • Avoid using arrow functions for 'data'. In simple scenarios it'll work but if you need some values from the vue instance it'll break the code because 'this' in arrow functions doesen't point to the vue instance. – Hexodus Aug 20 '20 at 20:12
  • @Hexodus I myself really don't use `this` inside data and I also think, that will make no sense at all. If you ever encounter the case where you need to use `this` inside data, I suggest using computed properties instead. – Yubaraj Shrestha Aug 21 '20 at 04:41
  • 1
    @YubarajShrestha It's still better to point it out for anyone who might just copy+paste+extend code from Stackoverflow. `this` using inside data is rather common in conjunction with route params like `id : this.$route.params.id` - have seen it a lot being done this way. – Hexodus Aug 21 '20 at 15:12
  • 1
    @Hexodus :) thank you for your suggestion. You are absolutely right about the route case you've shown, it all depends on developers' comfort. I prefer better readability over common use cases, hence I put those route param things in computed property with a proper name for it to better understand the system in the long run. – Yubaraj Shrestha Aug 24 '20 at 05:05
  • This is incredible! Thank you! The lack of documentation out there on this surprises me – ckhatton Sep 21 '22 at 08:45
42

An easy trick is:

<v-btn color="success" @click="$refs.inputUpload.click()">Success</v-btn>
<input v-show="false" ref="inputUpload" type="file" @change="yourFunction" >

Just create an input with the following properties:

  • type=file
  • ref=inputUpload this works like an id, you could name it like you want
  • v-show=false this hides input

Then make a button that when you click it, it fires a click event on the input Upload Button.

Pepperized
  • 317
  • 2
  • 10
Ing Oscar MR
  • 769
  • 7
  • 7
  • 3
    haha "it looks like a joke" - I'm kinda shocked Vuetify didn't cover file input, thanks for the trick :-) – coleman-benjamin Apr 26 '19 at 16:21
  • 2
    Great solution! Thanks for this.. just one update needed.. the `@click` on the `btn` needs to be this: `$refs.inputUpload.$el.click()` just need that `$el` and it works like a champ! – ToddT Jul 15 '19 at 20:08
31

This is something we will add in the future, but not currently. There is discussion on github with several users posting their implementations that they are using for the time being, https://github.com/vuetifyjs/vuetify/issues/238

John Leider
  • 720
  • 4
  • 5
24

Good news.

Starting with version 2.0.0.-beta.8 v-file-input is available in Vuetify. You're supposed to use it like:

<template>
  <v-file-input accept=".txt" label="Select File..."></v-file-input>
</template>

EDIT (SNIPPET ADDITION):

A basic usage for handling an image file can be implemented as follows.

Thanks to @Begueradj pointing there is even no need for handling @change event for tracking the file change and making the example even more precise:

new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data: () => ({
    file: null,
    imageUrl: null
  }),
  methods: {
    onUpload() {
      console.log(this.file)
    }
  }
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@3.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">

<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>

<div id="app">
  <v-app>
    <v-content>
      <v-container>
        <v-file-input 
          v-model="file" 
          label="Select Image File..." 
          accept="image/*"
        ></v-file-input>
        <v-btn color="primary" @click="onUpload">Upload</v-btn>
      </v-container>
    </v-content>
  </v-app>
</div>
vahdet
  • 6,357
  • 9
  • 51
  • 106
  • 2
    How do I send this file to my server? – yukashima huksay Aug 21 '19 at 05:02
  • 1
    You can handle the file with `v-model` attribute of `v-file-input`. I have added an example logging the file, you can send it to server ot whatsoever instead. – vahdet Aug 21 '19 at 07:54
  • 1
    When trying to run it outputs [Vue warn]: Error in beforeCreate hook: "TypeError: t.observable is not a function" – Marcelo Fonseca Sep 03 '19 at 13:38
  • im having some troubles trying to use v-file-input and created a question. Can you help me? https://stackoverflow.com/questions/57773556/file-upload-using-vuetify-2-v-file-input-and-axios – Marcelo Fonseca Sep 03 '19 at 14:29
  • @MarceloFonseca I have edited my script imports (converted from unpkg to jsdelivr) and it does not throw no exception now. If not enough, I also created a codepen which also allows non-image files: https://codepen.io/vahdet/pen/dybZpQg – vahdet Sep 04 '19 at 07:41
  • 1
    Why did you add that `onFileChange()` function ? – Billal Begueradj Dec 16 '19 at 09:07
  • 1
    @Begueradj You're right: change detection is actually coming out of the box with `v-file-input`. Edited the answer. – vahdet Dec 16 '19 at 09:53