Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue submit button from component does not submit

I have a component in Vue which I use a substitute for submit buttons. I can pass a handler to it, which the component calls after disabling itself and settings it status as loaded, and it can recover (enable itself again) after errors and display a nifty success animation if all goes well. This works well, with the code below:

// Submit.vue
<template>
    <button :type="type" :class="classes" :disabled="loading" @click="onClick">
        <span class="flag" v-if="flag"></span>
        <slot></slot>
    </button>
</template>

<script>
    import _ from 'lodash'
    export default {
        name: 'submit',
        props: {
            brand: {
                type: String,
                default: 'primary'
            },
            // If no handler is provided, will fallback to normal submit button
            handler: {
                type: Function,
                required: false
            },
            flag: {
                type: Boolean,
                default: false
            }
        },
        data () {
            return {
                loading: false,
                success: false
            }
        },
        computed: {
            type () {
                return typeof this.handler !== 'undefined' ? 'button' : 'submit'
            },
            classes () {
                return [
                    `btn btn-${this.brand}`,
                    this.loading && !this.success ? 'loading' : null,
                    this.success ? 'success' : null
                ]
            }
        },
        methods: {
            onClick (event) {
                if (this.success) {
                    event.preventDefault()
                    return
                }
                this.loading = true
                if (typeof this.handler !== 'undefined') {
                    // Handler must return a Promise
                    this.handler.call()
                        .then(_.bind(() => {
                            this.onSuccess()
                        }, this))
                        .catch(() => {})
                        .then(_.bind(() => {
                            this.loading = false
                        }, this))
                }
            },
            resetSuccess () {
                this.success = false
            },
            onSuccess () {
                this.success = true
                setTimeout(this.resetSuccess, 2000)
            }
        }
    }
</script>

It falls back to a normal submit button if no handler is passed, assuming all you want is to auto-disable the button when the form is submitted. The only problem is the form is not submitted when I click the button created from the component.

I think it would be fairly easy to force the submission via JS with the onClick method, but I wanted to understand why it doesn't. Is it a browser issue? A security issue? A Vue issue? Or something else I'm missing that might be right in front of me?

Here's a JSFiddle for quick testing: https://jsfiddle.net/03fgwgy5/ The code is not exactly the same, as I'm using single-file components, but the gist is the same and the behaviour can be observed easily.

like image 388
Tomas Buteler Avatar asked Sep 27 '26 17:09

Tomas Buteler


2 Answers

You are setting loading to false before you check for the existence of the handler. Since you bind the button's disabled attribute to loading, you are disabling the button and preventing the native click event from firing.

Just set the loading property after you've checked for the handler:

if (typeof this.handler !== 'undefined') {
  this.loading = true;
  ...
}

Here's a fiddle.

like image 54
thanksd Avatar answered Sep 30 '26 14:09

thanksd


For the record, here's what I ended up doing:

onClick (event) {
    if (this.success) {
        event.preventDefault()
        return
    }
    this.loading = true
    if (typeof this.handler !== 'undefined') {
        // Handler must return a Promise
        this.handler.call()
            .then(_.bind(() => {
                this.onSuccess()
            }, this))
            .catch(() => {})
            .then(_.bind(() => {
                this.loading = false
            }, this))
    } else {
        this.$el.form.submit()
    }
}

This allows me disable the form on click and show the loading status, but still force submission.

like image 37
Tomas Buteler Avatar answered Sep 30 '26 13:09

Tomas Buteler



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!