Luca Braun
Luca Braun

Reputation: 57

VueJs dynamic v-on event possible?

Is it possible to set dynamic on event in VueJS? I try to build a dynamic form as component with inputs that can listen on everything. Here an example:

import Vue from 'vue';

let formItems = {
  {type: 'checkbox', id: 'some-id', on:'change', model: 'someId'},
  {type: 'url', id: 'another-id', on:'keyup', model:'anotherId'},
};

let params = {
  someId: true,
  anotherId: 'http://www.example.com',
};

new Vue({
  el: '#app',
  data: {
    formItems: formItems,
    params: params,
  },
  methods: {
    checkInputParams(e) {
      e.preventDefault();
      // Do some stuff.
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>

<div id="app">
  <div class="form-group" v-for="item in formItems">
      <input type="checkbox" <!-- Also need a workaround for dynamic type and v-model -->
          :id="item.id"
          :class="(item.class ? item.class : '')"
          :title="(item.title ? item.title : '')"
          :placeholder="(item.placeholder ? item.placeholder : '')"
          :autocomplete="(item.autocomplete ? item.autocomplete : false)"
          :disabled="(item.disabled ? item.disabled : false)"
          :max="(item.max ? item.max : '')"
          :min="(item.min ? item.min : '')"
          :maxlength="(item.maxLength ? item.maxLength : '')"
          :multiple="(item.multiple ? item.multiple : '')"
          :name="(item.name ? item.name : '')"
          :readonly="(item.readonly ? item.readonly : false)"
          :required="(item.required ? item.required : false)"
          v-on="{{ item.on }}:checkInputParams" <!-- Here I try the dynamic v-on -->
          v-model="params[item.model]"/>
  </div>
</div>

Is it possible to set a dynamic v-on event like v-on="<variable>:<function>"?

Upvotes: 5

Views: 10196

Answers (4)

sanchit
sanchit

Reputation: 2538

From Vue 2.4.0+, v-on accepts an object syntax

Refer this documentation

<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>

Upvotes: 16

Unmitigated
Unmitigated

Reputation: 89472

In Vue 3, you can pass a dynamic argument to v-on with square brackets.

<input @[item.on]="checkInputParams" />

Vue SFC Playground example.

Upvotes: 1

Asef Hossini
Asef Hossini

Reputation: 753

Check out this custom input component. I'm also using event modifiers(kind of) dynamically through the callback event function. I'm passing the event name and callback to the custom component.

BaseFormTextInput.vue

<script setup>
import { computed } from 'vue'

const props = defineProps(['modelValue', 'label', 'id', 'type', 'event', 'eventHandler'])
const emit = defineEmits(['update:modelValue'])

const value = computed({
  get() {
    return props.modelValue
  },
  set(value) {
    emit('update:modelValue', value)
  }
})
</script>

<template>
  <div class="o-form__textControl">
    <label :for="id" class="o-form__label">{{ label }}</label>
    <slot name="input">
      <input @[event]="eventHandler($event)" :type="type" name="email" :id="id" v-model="value" />
    </slot>
  </div>
</template>

Parent.vue

<script setup>
import { reactive, ref } from 'vue'
import BaseFormTextInput from '../components/BaseFormTextInput.vue'

const skills = reactive([])
const tempSkill = ref('')

const addSkill = (e) => {
  if (e.key === ',' && e.altKey === true) {
    if (!skills.includes(this.tempSkill)) {
      skills.push(this.tempSkill)
    }
    this.tempSkill = ''
  }
}
</script>

<template>
  <BaseFormText
    label="skills (press alt + comma to add):"
    id="skills"
    v-model="registerModel.tempSkill"
    :event-handler="addSkill"
    event="keyup"
  />
</template.

Upvotes: 0

Nikita Fedorov
Nikita Fedorov

Reputation: 41

Try:

<button v-on="buttonListeners"></button>
// ...
{
  data() {
    return {
      listeners: {
        'mousedown': 'doThis',
      },
    };
  },
  computed: {
    buttonListeners() {
      return Object
        .entries(this.listeners)
        .reduce((acc, [eventName, methodName]) => ({
          ...acc,
          [eventName]: this[methodName],
        }), {});
    },
  },
};

Upvotes: 0

Related Questions