Vue.js - validation fails for file upload in axios

2020-01-25 11:22发布

问题:

I am building a Laravel+Vue.js SPA (Single Page Application) with BootstrapVue, VeeValidate and axios as the HTTP client.

Inside axios, when I use multipart/form-data; boundary=${uploadForm._boundary} as the Content-Type in headers then all the validations in Laravel Controller method fail.

But if I use 'content-type': 'multipart/form-data' in header then validation works except the file input field. The file field becomes empty in Laravel controller method.

This happens within the component EditProfile.vue. The content there is :

<template>
<ValidationObserver ref="form" v-slot="{ passes }">

        <div id="registration_form">

            <div id="form_title" class="text-center">Edit Your Profile</div>
            <div v-html="result" class="result text-center"></div>


            <b-form name="uploadForm" @submit.prevent="passes(onSubmit)" @reset="resetForm"  enctype="multipart/form-data">


                <ValidationProvider vid="name" rules="required|min:2" name="name" v-slot="{ valid, errors }">
                    <b-form-group
                            label="User Name:"
                            label-for="exampleInput1"

                    >
                        <b-form-input
                                type="text"
                                disable-leading-trailing-space
                                v-model="name"
                                plaintext
                                :state="errors[0] ? false : (valid ? true : null)"
                                placeholder="Enter your name"
                        ></b-form-input>
                        <b-form-invalid-feedback id="inputLiveFeedback">{{ errors[0] }}</b-form-invalid-feedback>
                    </b-form-group>
                </ValidationProvider>



                <ValidationProvider vid="photo" rules="required" name="photo" v-slot="{ valid, errors }">
                    <b-form-group
                            label="Photo:"
                            label-for="exampleInput1"
                    >


                        <b-form-file

                                accept="image/x-png,image/gif,image/jpeg"
                                v-model="file"
                                :state="Boolean(file)"
                                placeholder="Choose a file or drop it here..."
                                drop-placeholder="Drop file here..."
                                @change="onFileChange" enctype="multipart/form-data"
                        ></b-form-file>
                        <b-form-invalid-feedback id="inputLiveFeedback">{{ errors[0] }}</b-form-invalid-feedback>
                        <div class="mt-3">Selected file: {{ file ? file.name : '' }}</div>

                        <!-- Plain mode -->
                        <!--<b-form-file v-model="file2" class="mt-3" plain></b-form-file>
                        <div class="mt-3">Selected file: {{ file2 ? file2.name : '' }}</div>-->

                        <div id="preview">
                            <img v-if="url" :src="url" />
                        </div>

                    </b-form-group>
                </ValidationProvider>





                <b-button type="submit" variant="primary">Submit</b-button>
                <b-button type="reset" variant="danger">Reset</b-button>
            </b-form>

        </div><!-- end of id registration_form-->
    </ValidationObserver>
</template>

In JS part, I have :

<script>


    import { ValidationObserver, ValidationProvider } from "vee-validate";

     export default {
        name: "EditProfile",
        props: {

        },

        components: {
            ValidationObserver,
            ValidationProvider


        },
        data: () => ({

            name: "",
            photo:"",
            file:"",
            url:"",  
            result:''

        }),

        methods: {
            onFileChange(e) {
                this.file = e.target.files[0];
                this.url = URL.createObjectURL(this.file);
            },
        onSubmit() {
                console.log("Form submitted yay!");


                this.result='<span class="wait">Please wait ...</span>';

                axios.post('/update_profile_now',
                    {
                       name: this.name,
                       photo:this.file

                    }, // the data to post
                    {


                        headers: {

                            //Accept: 'application/json',

                           'Content-Type':  `multipart/form-data; boundary=${uploadForm._boundary}`

                        }



                    })
                    .then(response => {

                        if(response.data.success){

                            this.result='<span class="succes">Registration completed !!</span>';
                        }else{

                            this.$refs.form.setErrors(response.data.errors);

                            this.result='<span class="error">Invalid data !!</span>';
                        }




                    })
                    .catch(error => {

                        if(typeof error !=="undefined"){

                            console.log(error);
                        }

                    });

                //    .finally(() => this.loading = false)
            },
            resetForm() {
                this.name = "";

                this.result='';

                requestAnimationFrame(() => {
                    this.$refs.form.reset();
                });
            }
        }
    };

</script>

In corresponding Laravel controller method I have :

 public function update_profile_now(Request $request)
    {


        $rules = array(

            'name' => 'required | min:4',
            'photo'=> 'image|mimes:jpeg,png,jpg|max:2048'
        );

        $validator = Validator::make(Input::all(), $rules);

        // Validate the input and return correct response
        if ($validator->fails())
        {
            return Response::json(array(
                'success' => false,
                'errors' => $validator->getMessageBag()->toArray()

            ), 200); 
        }

        //file uploading code goes here 

        return Response::json(array('success' => true), 200);




   }

What I want is the form with a file input inside it will be submitted and then a JSON response will be sent from the method after file upload and other works.

So what should be the correct header or do I need to adopt any other means ?

回答1:

I guess using FormData API would work.

Below some examples:

How to post a file from a form with Axios axios post request to send form data



回答2:

I Recommend using VeeValidation for validating your form after submitting it.

Its really simple and sweetest validation methods.

You can install it from here. VeeValidation Link