Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

POST file along with form data Vue + axios

I have a method for Vuejs component:

async submit () {
        if (this.$refs.form.validate()) {
          let formData = new FormData()
          formData.append('userImage', this.avatarFile, this.avatarFile.name)
          this.avatarFile = formData
          try {
            let response = await this.$axios.post('http://localhost:3003/api/test.php', {
              avatar: this.avatarFile,
              name: this.name,
              gender: this.gender,
              dob: this.DOB,
            }, {
              headers: {
                'Content-Type': 'multipart/form-data; boundary=' + formData._boundary
              }
            })
            if (response.status === 200 && response.data.status === 'success') {
              console.log(this.response)
            }
          } catch (e) {
           console.log(e)
          }
        }
      }

And in test.php, I'm using json_decode(file_get_contents("php://input"), TRUE); to read data as $_POST variables.

While I am able to read name, gender and dob correctly, I can't fetch avatar properly.

Any solutions for the same?

Note: I don't to append every variable as formData.append(.., ..) as I am planning to handle over 14 variables.

Note for moderators: I didn't find any question where formData was being used along with other data objects.

like image 684
Dev Aggarwal Avatar asked Mar 25 '18 17:03

Dev Aggarwal


People also ask

How do you pass body form data in Axios?

To send multipart form data with Axios, you need to use the FormData class. Browsers have a built-in FormData class, but Node. js doesn't, so you need to use the form-data npm module. To create the form, you must append the data to the form that will be sent to the server using the append() method.

How do I append a form's data to FormData in Vue?

new Vue({ el: 'body', methods: { submit: function(e) { var form = document. getElementById('form'); var formData = new FormData(form); axios. post('/someUrl', formData) . then((response) => { // success callback }, (response) => { // error callback }); } } });

How does multipart form data work?

Multipart/form-data is one of the most used enctype/content type. In multipart, each of the field to be sent has its content type, file name and data separated by boundary from other field. No encoding of the data is necessary, because of the unique boundary. The binary data is sent as it is.


2 Answers

So, I figured this one out in a simpler way:

    let rawData = {
                name: this.name,
                gender: this.gender,
                dob: this.dob
              }
              rawData = JSON.stringify(rawData)
    let formData = new FormData()
          formData.append('avatar', this.avatarFile, this.avatarFile.name)
          formData.append('data', rawData)
    try {
            let response = await this.$axios.post('http://localhost:3003/api/test.php', formData, {
              headers: {
                'Content-Type': 'multipart/form-data'
              }
         })

test.php:

$_POST = json_decode($_POST['data'],true);

Note: I had an option of using:

Object.keys(rawData).map(e => {
            formData.append(e, rawData[e])
          })

but since I was dealing with nested objects (name: { first: '', last: ''} ) in rawData, I chose not to do that as it would require recursive methods on either client side or server side.

like image 158
Dev Aggarwal Avatar answered Oct 22 '22 23:10

Dev Aggarwal


PHP ( process.php )

<?php
    $data = array(
        "post"  => $_POST,
        "files" => $_FILES
    );

    echo json_encode($data);
?>

Vue and form HTML

let vm = new Vue({
    el: "#myApp",
    data: {
        form: {}
    },
    methods: {
        submit: async function (e) {
            e.preventDefault();

            /* formData */
            var formData = new FormData( this.$refs.formHTML );

            /* AJAX request */
            await axios({
                method: "post",
                url: "process.php",

                data: formData,

                config: { headers: { "Content-Type": "multipart/form-data" } }
            })

            /* handle success */
            .then( response => { console.log(response.data); } )

            /* handle error */
            .catch( response => { console.log(response) } );
        }
    }
});
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.js"></script>

<div id="myApp" >

    <form @submit="submit" ref="formHTML" >

        Name: <input type="text" name="name" v-model="form.name" /><br />

        Gender:
        <input type="radio" name="gender" value="male" v-model="form.gender" /> Male
        <input type="radio" name="gender" value="female" v-model="form.gender" /> Female <br />

        File: <input type="file" name="upload" v-model="form.upload" /><hr />

        <input type="submit" name="submit" value="Submit" />

    </form>

</div>
like image 2
antelove Avatar answered Oct 22 '22 21:10

antelove