1

I'm creating a button component in VueJS. I've made a dynamic event with a prop, plus event function and params as props as well. That works fine, the parent can set whatever event to trigger a method. However I want to be able to set modifiers on that event as well but don't see a way to do that. Is it possible?

The button component:

<button class="btn" :class="[styles, cssClasses]" role="button"
    @[event]="onEvent(eventParams)" 
    :disabled="disabled">
    <slot></slot>
</button>

The parent:

<Button 
    :event="'click'" 
    :onEvent="logEvent" 
    :eventParams="'This is a test message'">Test button</Button>

Adding a static modifier to the dynamic event works @[event].prevent=... but I want to be able to set the modifier from a prop, or not have it at all.

I also tried setting up an event listeners object but can't see a way to add modifiers to those either. At least in this option I can pass the event and preventdefault the old fashioned way, like our grandparents did.

moveAllListeners() {
    const me = this
    return Object.assign({},
        this.$listeners,
        {
            click(e) {
                e.preventDefault()
                me.moveAll()
            },
            mouseenter(e) {
                console.log('Mouse entered');
            }
        }
    )
}

2 Answers 2

2

Event modifiers cannot be dynamic because they are applied at "compile time" (when the template is compiled).

You'll have to implement this all manually; how you do it exactly is up to you, but it could be something like this:

<button @[event]="onEvent">
props: [
  'event',
  'eventParams',
  'eventPrevent', 
],

methods: {
  onEvent(e) {
    if (this.eventPrevent) {
      e.preventDefault()
    }

    // Use this.eventParams here...
  }
}

I'm not sure what your requirements are, but it seems like this is a bad approach from the start. Why does a custom Button component need this kind of behavior? Why do you need Button to operate like this?

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

1 Comment

What if we want to use a general/base component with dynamic events and modifiers?
0

I am not quite sure why you would need to operate such magic. Can you provide a bit more informations about your requirements please ?

Why can't you just do like this :

<button
    class="btn"
    :class="[styles, cssClasses]"
    role="button"
    :disabled="disabled"
    v-on="$listeners"
>
    <slot></slot>
</button>
<Button @click="logEvent('This is a test message')">
    Test button
</Button>

The only reason I can imagine that would require to have these in a prop, would be because of some dynamic actions set up.

But you could have something like this in your parent component:

<template>
    <Button
        v-for="(button, i) in dynamicButtons"
        :key="`button_${i}`"
        @[button.event]="button.action"
    >
        Test button
    </Button>
</template>

<script>
    export default {
        name: 'Sandbox',
        
        data () {
            dynamicButtons: [
                {
                    content: 'Test button 1',
                    event: 'click',
                    action:  () => logEvent('Click w/o prevention')
                },
                {
                    content: 'Test button 2',
                    event: 'click',
                    action:  (e) => {
                        e.preventDefault()

                        logEvent('Click with prevention')
                    }
                },
                {
                    content: 'Test button 3'
                    event: 'mouseenter',
                    action: logEvent('Mouse entered')
                }
            ]
        },

        /* ... */
    }
</script>

1 Comment

Thank you! The piece I was missing was the v-on="$listeners" in the component so the @event functionality wasn't working. To get around this I was having to pass the parent method as a prop and the parameters as a separate prop. A dumb error on my part. Thanks again.

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.