20

I wanted to upload file using vue.js version 3.

I can able to import ref but not sure how to use it for fetching file data?

FileUploadTest.vue

<template>
<h1>File Upload</h1>
<div class="container">
    <div>
      <label>File
        <input type="file" id="file" ref="file" v-on:change="onChangeFileUpload()"/>
      </label>
        <button v-on:click="submitForm()">Upload</button>
    </div>
  </div>
</template>

<script src="./FileUploadTest.ts" lang="ts"></script>

FileUploadTest.ts

import { Options, Vue } from "vue-class-component";
import { ref } from 'vue';
import axios from "../../axios/index";

@Options({})
export default class FileUploadTest extends Vue {

    protected file: any;

    submitForm() {
        const formData = new FormData();
        formData.append('bytes', this.file);

        axios.post('https://localhost:44313/api/app/file/save',
            formData,
            {
                headers: {
                    'Content-Type': 'multipart/form-data'
                }
            }
        ).then(function (data) {
            console.log(data.data);
        })
        .catch(function () {
            console.log('FAILURE!!');
        });
    }

    onChangeFileUpload() {
        debugger;
        this.file = ref(["file"]).value; 
    }
};

The actual file content is not storing in the this.file variable

this.file = ref(["file"]).value; 
3
  • please share more code Commented Jan 13, 2021 at 14:22
  • @BoussadjraBrahim added code. thanks Commented Jan 13, 2021 at 14:48
  • may be useful this... Upload File Commented Jul 26, 2023 at 13:45

8 Answers 8

22

I can summarize the answer as below.

FileUpload.vue

<template>
  <div>
    <input
      type="file"
      @change="onFileChanged($event)"
      accept="image/*"
      capture
    />
  </div>
</template>

FileUpload.ts

import { defineComponent, ref } from "vue";

export default defineComponent({

    name: "FileUpload",

    setup() {
        const file = ref<File | null>();
        const form = ref<HTMLFormElement>();

        function onFileChanged($event: Event) {
            const target = $event.target as HTMLInputElement;
            if (target && target.files) {
                file.value = target.files[0];
            }
        }

        async function saveImage() {
            if (file.value) {
                try {
                // save file.value
                } catch (error) {
                    console.error(error);
                    form.value?.reset();
                    file.value = null;
                } finally {
                }
            }
        };

        return {
            saveImage,
            onFileChanged,
        }
    }
});
Sign up to request clarification or add additional context in comments.

Comments

19

Vue3.js upload file to server using composition api

<template>
      <input ref="file" v-on:change="handleFileUpload()"  type="file">
</template>
<script>

import { ref} from "vue"

export default{
    name:'Add',

    setup() {
        const file = ref(null)

        const handleFileUpload = async() => {
           // debugger;
            console.log("selected file",file.value.files)
            //Upload to server
        }

        return {
          handleFileUpload,
          file
       }
    }
}

</script>

3 Comments

This was helpful. I was trying to attach a v-model to my <FileUpload> tag, but I should have been using ref. Thanks for this info!
The right path for file list is this, On template: <input ref="fileInput" > On script: this.$refs.fileInput.files
@NavidShad This won't work with the composition api. You need to use a ref and then access the ref. e.g. const fileInput = ref() and fileInput.value.files
11

2023 approach with the latest syntax

I'm using the <script setup lang="ts"> for the composition API in Vuejs 3. lang="ts" specifies that the language is TypeScript instead of JavaScript.

<template>
    <main>
        <input ref="fileInput" type="file" @change="handleFileChange" />
        <button @click="doSomething">do something</button>
    </main>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const fileInput = ref<HTMLInputElement | null>(null)
const files = ref()

function handleFileChange() {
    files.value = fileInput.value?.files
}

function doSomething() {
    const file = files.value[0]
    console.log(file)
    // and do other things...
}
</script>

What's exactly happening ?

The ref is a special attribute that allows us to obtain reference to a DOM element or child.

To access the ref in the template we need to declare a ref in the script with the same name const fileInput = ref<HTMLInputElement | null>(null);

The files variable is an array-like object that can contain multiple files. To access the first or only file we can access it like so: const file = files.value[0] this will extract the first file object in files and then you are ready to use the file as you wish.

You may want to get the name:

file.name

Or the extension:

file.name.split('.').pop();

Or the name without the extension:

file.name.substring(0, file.name.lastIndexOf('.'))

Comments

8

Here's a simple component you could use for a file upload with the options api. No ref needed.

fileUpload.vue

<template>
    <input type="file" @change="onChange($event)">
</template>

<script>
export default {
    props: ['modelValue'],
    methods: {
        onChange(event) {
            this.$emit('update:modelValue', event.target.files[0]);
        },
    },
};
</script>

Your component...

<template>
    <form novalidate @submit.prevent="onSubmit">
        <file-upload v-model="form.file"></file-upload>
    </form>
</template>

<script>
import fileUpload from 'fileUpload';
export default {
    components: { fileUpload },
    data: () => ({ form: { file: null } }),
    methods: {
        onSubmit() {
            console.log(this.form);
            // post the form to the server
        }
    }
}
</script>

Comments

3

Since you're using the option api you don't need the ref just use this.$refs.file :

   onChangeFileUpload() {
        debugger;
        this.file = this.$refs.file[0]; 
    }

2 Comments

When using the Vue 3 Composition API via the setup() method, we don’t have access to this.$refs
Yes but we could use returned ref as explained here
0

In as much as it's a frontend library, I'll still up in the core JavaScript function to play. Since every onchange listener has an parameter that hold the entire element, I'll use that to get the file value onced clicked.

<template>
  <form novalidate @submit.prevent="onSubmit">
    <input type="file" @change="addFile" />
  </form>
</template>

<script>
export default {
  name: "MyForm",

  data() {
    return {
      file: null,
    };
  },
  methods: {
    addFile(e) {
      this.file = e.target.files[0];
    },
    onSubmit() {
      console.log(this.file);
      // post the form to the server
    },
  },
};
</script>


This way you can modify it to whatever you want or upload it on the background while you fill other parts of the form.

Comments

0

make sure you dont have a v-model on your file input

1 Comment

You are contradicting an existing answer and a comment. You might want to improve clarity and helpfulness of your answer by adding an explanation of the reason to avoid v-models.
0

For example Your can use v-file-input

<v-card-text>
    <v-container>
        <v-row>
            <v-col cols="12" sm="12" md="12">
                <v-file-input v-model="file" show-size label="Template input"></v-file-input>
            </v-col>
        </v-row>
   </v-container>
</v-card-text>

Example

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.