0

I'm trying to validate a simple form that contains two fields:

  • A select box
  • A file field

If one of the fields aren't filled in, a div (containing an error label) should be rendered next to the corresponding input field.

The problem: My 'error divs' aren't rendered when pushing data to the errors object (if the form is invalid). Please note my console.log statement, that tells me that my error object has a key 'file' and a key 'selectedSupplier'.

Side note: I'm following this example: https://v2.vuejs.org/v2/cookbook/form-validation.html Differences are, that I'd like to show error labels next to the corresponding field and that I'm setting errors in my errors object, instead of a simple array. So what could I be doing wrong?

Thanks.

This is my Main.vue file:

<template>
    <div>
        <form @submit="upload">
            <div class="mb-8">
                <h1 class="mb-3 text-90 font-normal text-2xl">Import Order Csv</h1>
                <div class="card">
                    <div class="flex border-b border-40">
                        <div class="w-1/5 px-8 py-6">
                            <label for="supplier_id" class="inline-block text-80 pt-2 leading-tight">Supplier</label>
                        </div>

                        <div class="py-6 px-8 w-1/2">
                            <select v-model="selectedSupplier" id="supplier_id" name="supplier_id" ref="supplier_id" class="w-full form-control form-input form-input-bordered">
                                <option v-for="supplier in suppliers" v-bind:value="supplier.id">{{ supplier.name }}</option>
                            </select>

                            <div v-if="errors.hasOwnProperty('selectedSupplier')" class="help-text error-text mt-2 text-danger">
                                Required.
                            </div>
                        </div>
                    </div>

                    <div class="flex border-b border-40">
                        <div class="w-1/5 px-8 py-6">
                            <label for="csv_file" class="inline-block text-80 pt-2 leading-tight">File</label>
                        </div>

                        <div class="py-6 px-8 w-1/2">
                            <input id="csv_file" type="file" name="file" ref="file" @change="handleFile">

                            <div v-if="errors.hasOwnProperty('file')" class="help-text error-text mt-2 text-danger">
                                Required.
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="flex items-center">
                <button type="submit" class="btn btn-default btn-primary inline-flex items-center relative">Import</button>
            </div>
        </form>
    </div>
</template>

<script>
    export default {
        mounted() {
            this.listSuppliers();
        },
        data() {
            return {
            errors: [],
            file: '',
            suppliers: [],
        };
    },
    methods: {
        checkForm() {
            if (!this.selectedSupplier) {
                this.errors.selectedSupplier = 'Supplier required';
            }

            if (!this.file) {
                this.errors.file = 'File required';
            }
        },
        listSuppliers() {
            const self = this;

            Nova.request()
                .get('/tool/import-order-csv/suppliers')
                .then(function (response) {
                    self.suppliers = response.data.data;
                })
                .catch(function (e) {
                    self.$toasted.show(e, {type: "error"});
                });
        },
        handleFile: function (event) {
            this.file = this.$refs.file.files[0];
        },
        upload: function (event) {
            this.checkForm();

            if (this.errors.hasOwnProperty('selectedSupplier') || this.errors.hasOwnProperty('file')) {
                console.log(this.errors); // this actually shows both errors!
                event.preventDefault();
            }

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

            formData.append('supplier_id', this.$refs.supplier_id.value);

            const self = this;

            Nova.request()
                .post('/tool/import-order-csv/upload',
                    formData,
                    {
                        headers: {
                            'Content-Type': 'multipart/form-data'
                        }
                    }
                ).then(function (response) {
                    self.$toasted.show(response.data.message, {type: "success"});
                })
                .catch(function (e) {
                    self.$toasted.show(e.response.data.message, {type: "error"});
                });
            }
        }
    }
</script>
2
  • you are using errors as object, but in data() you pass an empty array as initial value Commented Feb 25, 2020 at 9:19
  • Thanks for the feedback. This didn't fix it yet though :( Commented Feb 25, 2020 at 9:24

4 Answers 4

1

Apparently I had to use v-show instead of v-if, because v-if would be 'lazy' and will not render my error-div when the errors var gets filled.

It's working now, but not 100% sure if this is the best way, as I found another tutorial where v-if is used for form validation.(https://medium.com/@mscherrenberg/laravel-5-6-vue-js-simple-form-submission-using-components-92b6d5fd4434)

Sign up to request clarification or add additional context in comments.

Comments

1

I was getting the same error, this is how I solved the problem,

<div v-if="errors.field1.length > 0 ? true : false"> // true or false 

If you fix the code like this it will work

1 Comment

Select your code and press Ctrl + K to format your code
0

The reason might because the way you reassign object is not reactive, which not trigger v-if to re-calculate

this.errors.selectedSupplier = 'Supplier required';
this.errors.file = 'File required';

If you still want to use v-if , try change to this approach

this.errors = {...this.errors, selectedSupplier: 'Supplier required' }

this.errors = {...this.errors, file: 'File required' }

Comments

0

The way I handle my errors with VueJS is through lists and their length attribute.

I have an errors object in my data that looks like this:

errors: {
  field1: [],
  field2: [],
}

Then, when I submit the form, I will:

  • Empty all the lists for the errors (ie clearing the previous errors)
  • .push() new errors in the right lists (and .push() makes the Vue reactive)

Finally, in my form, my respective errors divs are displayed based on the length of the list:

<div class="error" v-if="errors.field1.length > 0">
    use a v-for to display all the errors from the list
</div>

Hope it helps

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.