Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

manshu's avatar
Level 28

VueJS File Upload, Not working

Here is my Vue Component and im having trouble upload image. Any idea why it's not taking image? I am able to submit the form, but having issue submitting image.

<template>
  <div class="container mx-auto py-10">
    <form @submit.prevent="submitListing">
      <div class="w-full px-3">
        <label
          class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2 mt-2"
          for="grid-company-name"
        >Company Name</label>
        <input
          class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
          id="grid-company-name"
          type="text"
          placeholder="Company Name"
          required
          v-model="form.name"
        >
      </div>
      <div class="w-full px-3">
        <label
          class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2 mt-2"
          for="grid-email"
        >Email</label>
        <input
          class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
          id="grid-email"
          type="text"
          required
          v-model="form.email"
          placeholder="Company Email"
        >
      </div>
      <div class="w-full px-3">
        <label
          class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2 mt-2"
          for="grid-website"
        >Your Website</label>
        <input
          class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
          id="grid-website"
          type="text"
          required
          v-model="form.website"
          placeholder="Company Website"
        >
      </div>
      <div class="w-full px-3">
        <label
          class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2 mt-2"
          for="grid-phone"
        >Company Phone</label>
        <input
          class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
          id="grid-tollfreephone"
          type="text"
          required
          v-model="form.tollfree_phone"
          placeholder="Company Toll Free Phone"
        >
      </div>
      <div class="w-full px-3">
        <label
          class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2 mt-2"
          for="grid-phone"
        >Company Local Phone</label>
        <input
          class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
          id="grid-localphone"
          type="text"
          required
          v-model="form.local_phone"
          placeholder="Company Local Phone"
        >
      </div>
      <div class="w-full px-3">
        <label
          class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2 mt-2"
          for="grid-phone"
        >Address</label>
        <input
          class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
          id="grid-address"
          type="text"
          required
          v-model="form.address_1"
          placeholder="Company Address"
        >
      </div>
      <div class="w-full px-3">
        <label
          class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2 mt-2"
          for="grid-phone"
        >Address 2</label>
        <input
          class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
          id="grid-phone"
          type="text"
          required
          v-model="form.address_2"
          placeholder="Suite 200"
        >
      </div>
      <div class="w-full px-3">
        <label
          class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2 mt-2"
          for="grid-phone"
        >Address 2</label>
        <textarea
          class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
          placeholder="Company Details"
          v-model="form.description"
          rows="6"
        ></textarea>
      </div>
      <div class="flex flex-wrap mb-2">
        <div class="w-full md:w-1/3 px-3 mb-6 md:mb-0">
          <label
            class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"
            for="grid-state"
          >State</label>
          <div class="relative">
            <select
              class="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
              id="grid-state"
              required
              v-model="form.state_id"
              @change="getCities($event.target.value)"
            >
              <option selected>Select one</option>
              <option v-for="state in states" :key="state.id" :value="state.id">{{ state.name }}</option>
            </select>
            <div
              class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
            >
              <svg
                class="fill-current h-4 w-4"
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 20 20"
              >
                <path
                  d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"
                ></path>
              </svg>
            </div>
          </div>
        </div>
        <div class="w-full md:w-1/3 px-3 mb-6 md:mb-0">
          <label
            class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"
            for="grid-state"
          >City</label>
          <div class="relative">
            <select
              class="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
              id="grid-state"
              required
              v-model="form.city_id"
            >
              <option selected>Select one</option>
              <option v-for="city in cities" :key="city.id" :value="city.id">{{ city.name }}</option>
            </select>
            <div
              class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
            >
              <svg
                class="fill-current h-4 w-4"
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 20 20"
              >
                <path
                  d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"
                ></path>
              </svg>
            </div>
          </div>
        </div>
        <div class="w-full md:w-1/3 px-3 mb-6 md:mb-0">
          <label
            class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"
            for="grid-zip"
            required
          >Zip</label>
          <input
            class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
            id="grid-zip"
            type="text"
            v-model="form.zip"
            placeholder="90210"
          >
        </div>
      </div>
      <div class="w-full px-3">
        <label
          class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2 mt-2"
          for="grid-phone"
        >Company Image</label>
        <input
          class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
          id="grid-phone"
          type="file"
          accept="image/*"
          @change="onFileChanged"
          placeholder="Company Local Phone"
        >
      </div>
      <div class="w-full px-3 mt-4">
        <div class>
          <button class="btn btn-raisin-light" type="submit">Sign Up</button>
        </div>
      </div>
    </form>
  </div>
</template>

<script>
import axios from "axios";
export default {
  components: {},
  data() {
    return {
      selectedCountry: "",
      states: [],
      cities: {},
      form: {
        name: "",
        description: "",
        email: "",
        website: "",
        tollfree_phone: "",
        local_phone: "",
        address_1: "",
        address_2: "",
        state_id: "",
        city_id: "",
        zip: "",
        imageUrl: null
      }
    };
  },
  created() {
    axios.get("/api/users/states").then(response => {
      this.states = response.data;
    });
  },
  methods: {
    getCities(state) {
      axios.get("/api/users/cities/" + state).then(response => {
        this.cities = response.data;
      });
    },
    submitListing() {
      const config = {
        headers: { "content-type": "multipart/form-data" }
      };

      let formData = new FormData();
      formData.append("imageUrl", this.form.imageUrl.data, config);
      axios.post("/listings", this.form, formData).then(response => {
        console.log(response.data);
      });
    },
    onFileChanged(event) {
      let selectedFile = event.target.files[0];
      this.form.imageUrl = selectedFile;
    }
  }
};
</script>

<style>
</style>
0 likes
22 replies
manshu's avatar
Level 28

Please check the code. It's already there

munazzil's avatar

Have you added error.console and check,sometimes error can be capture.

catch (error) 
 {
   console.log(error)
 }
manshu's avatar
Level 28

@MUNAZZIL - Nope, that's not the issue. Issue is, with sending image with the form. I have tried many ways, it sends an object of imageUrl instead of image data. So validation in laravel is seeing the "ImageUrl" property as null.

munazzil's avatar

As suggested have you add as like below in your html form tag? ,

    <form method="post" @submit.prevent="submitListing"  enctype="multipart/form-data">
manshu's avatar
Level 28

@MUNAZZIL - Please look at the code with arrow.

submitListing() {
      const config = {
        headers: { "content-type": "multipart/form-data" } <---------------
      };

      let formData = new FormData();
      formData.append("imageUrl", this.form.imageUrl.data, config);
      axios.post("/listings", this.form, formData).then(response => {
        console.log(response.data);
      });
    },
    onFileChanged(event) {
      let selectedFile = event.target.files[0];
      this.form.imageUrl = selectedFile;
    }
1 like
munazzil's avatar

@MANSHU - Your missing method="post" in form check with that yes I got that you added multipart/form-data.

munazzil's avatar

No i also have same problem that why i try to implement with you.

   <template>
<div>
    <div class="alert alert-success" v-if="saved">
        <strong>Success!</strong> Inserted data successfully added.
    </div>

    <div class="well well-sm" id="formfill">
        <form class="form-horizontal" method="post" @submit.prevent="onSubmit" enctype="multipart/form-data">
        
            <fieldset>
                <legend class="text-center">Book insert</legend>
                
                  <div class="form-group">
                    <label class="col-md-3 control-label" for="isbn">isbn</label>
                    <div class="col-md-9" :class="{'has-error': errors.isbn}">
                        <input id="isbn"
                               v-model="books.isbn"
                               type="text"
                               placeholder="Your isbn"
                               class="form-control" >
                        <span v-if="errors.isbn" class="help-block text-danger">{{ errors.isbn[0] }}</span>
                    </div>
                </div>
                <div class="form-group">
                   <label class="col-md-3 control-label" for="title">title</label>
                    <div class="col-md-9" :class="{'has-error': errors.title}">
                        <input id="title"
                               v-model="books.title"
                               type="text"
                               placeholder="Your title"
                               class="form-control">
                        <span v-if="errors.title" class="help-block text-danger">{{ errors.title[0] }}</span>
                    </div>
                </div>
                <div class="form-group">
                   <label class="col-md-3 control-label" for="price">price</label>
                    <div class="col-md-9" :class="{'has-error': errors.price}">
                        <input id="price"
                               v-model="books.price"
                               type="text"
                               placeholder="Your price"
                               class="form-control">
                        <span v-if="errors.price" class="help-block text-danger">{{ errors.price[0] }}</span>
                    </div>
                </div>
                <div class="form-group">
                   <label class="col-md-3 control-label" for="description">description</label>
                    <div class="col-md-9" :class="{'has-error': errors.description}">
                        <textarea id="description"
                               v-model="books.description"
                               type="text"
                               placeholder="Your description"
                               rows="5"
                               class="form-control" ></textarea>
                        <span v-if="errors.description" class="help-block text-danger">{{ errors.description[0] }} </span>
                    </div>
                </div>
                <div class="form-group">
                   <label class="col-md-3 control-label" for="filename">filename</label>
                    <div class="col-md-9" :class="{'has-error': errors.filename}">
                        <input id="filename"
                               v-on="books.filename"
                               type="file"
                                >
                        <span v-if="errors.filename" class="help-block text-danger">{{ errors.filename[0] }}</span>
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-md-12 text-right">
                        <button type="submit" class="btn btn-primary btn-lg">Submit</button>
                    </div>
                </div>
            </fieldset>
        </form>
    </div>
</div>

<script>

export default {
    data() {
        return {
            errors: [],
            saved: false,
            books: {                    
                isbn:null,
                title: null,
                price:null,
                description:null,
                filename:null
            }
        };          
    },
    
    methods: {
        onSubmit() {
        this.saved = false;
            axios.post('api/books', this.books)
            .then(({data}) => this.setSuccessMessage())
            .catch(({response}) => this.setErrors(response));          
        },
        
        setErrors(response) {
            this.errors = response.data.errors;
        },
        
        setSuccessMessage() {
            this.reset();
            this.saved=true;                
        },
        
        reset() {
            this.errors = [];
            this.books = {isbn:null,title:null,price:null,description:null,filename:null};
        }
    }
}

</script>

munazzil's avatar

@manashu My other data is saving in database and i can view in frontend but image only not saving and display or view from database.

chatty's avatar

Laraception - Laracasts thing that happens when an op helps a guy who is supposed to help the op

manshu's avatar
Level 28

@KANE - You're right. Lol !! im still struggling to find an answer. I think im almost there.

MaverickChan's avatar

@MANSHU - i think formdata.append has only the file path , you are missing the file itself

onFileChanged(e) {

    let selectedFile = event.target.files[0];
        this.form.imageUrl = selectedFile;

    let reader = new FileReader();
                reader.readAsDataURL(selectedFile);
                reader.onload = e => {
                   
            //do your things here ,send file to payload with path with your own settings

                };

}

@kane could not agree with you more , that guy is .... you know.

manshu's avatar
Level 28

My file key name is imageUrl. How do i capture that on the reader? I am confused about that.

MaverickChan's avatar
Level 47

@MANSHU -

onFileChanged(e) {

    let selectedFile = event.target.files[0]; 
        this.form.imageUrl = selectedFile;

    let reader = new FileReader();
                reader.readAsDataURL(selectedFile);
                reader.onload = e => {

        let src = e.target.result 
                   
             this.submitListing(selectedFile , src)

                };

}

submitListing(file,src) {
      const config = {
        headers: { "content-type": "multipart/form-data" }
      };

      let formData = new FormData();
      formData.append(src,file, config);
      axios.post("/listings", this.form, formData).then(response => {
        console.log(response.data);
      });
    },

you should really use enctype in form , it is cleaner.

manshu's avatar
Level 28

it's not working. It submits the form, once the image is uploaded. Backend validation error, and form is not captured fully. Tried both ways.

MaverickChan's avatar

@MANSHU - i am just giving you the idea , you might optimize your code in your way to make it work.

manshu's avatar
Level 28

Thanks guys, I was able to use base/64 image and converted it to get my solution. If anyone is interested, i can upload the code.

1 like

Please or to participate in this conversation.