Keegan
Keegan

Reputation: 12207

Why can't you use v-on shorthand to bind "on"?

The docs say

<a @click="doSomething"> ... </a>

is short-hand for

<a v-on:click="doSomething"> ... </a>

Why does this short-hand not work in all cases? For example,

<v-dialog v-model="dialog" width="500">
  <template v-slot:activator="{ on }">
    <v-btn dark v-on="on">Working button</v-btn>
    <v-spacer />          
    <v-btn dark @on="on">Non-working button</v-btn>
  </template>
  <v-card>
    <v-card-title>Some Dialog</v-card-title>
      <v-card-text>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
     </v-card-text>
  </v-card>
</v-dialog>

The "Working button" works, but the "Non-working button" doesn't. It seems like the v-on shorthand only works for events. But if that's true, I haven't seen it documented.

I'm using Vuetify in this example, but my question is about Vue.js in general.

Here's a CodePen of above: https://codepen.io/keeganwitt/pen/bGGVeZY

Upvotes: 3

Views: 2995

Answers (2)

thanksd
thanksd

Reputation: 55644

So, @on in your example is shorthand for v-on:on, meaning that the event handler is listening for the child component to emit an on event. The v-btn component does not ever emit an on event, so nothing ever happens.

This isn't the thrust of your question, but you technically can use the v-on shorthand to bind to an on event:

Vue.config.devtools = false;
Vue.config.productionTip = false;

Vue.component('toggle', {
  template: `
    <button @click="onClick"> 
      {{ isOn ? 'On' : 'Off' }}
    </button>
  `,
  data() {
    return {
      isOn: false
    };
  },
  methods: {
    onClick() {
      this.isOn = !this.isOn;
    
      if (this.isOn) {
        this.$emit('on');
      } else {
        this.$emit('off');
      }
    }
  }
});

new Vue({
  el: '#app',
  methods: {
    alert(val) {
      alert(val);
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <toggle @on="alert('on')" @off="alert('off')"/>
</div>


I think what is confusing you is the v-on="on" syntax. It's not obvious from the code, but the on variable being set as the value for v-on in this case is not a function, but an object.

From the vue docs on v-on:

Starting in 2.4.0+, v-on also supports binding to an object of event/listener pairs without an argument. Note when using the object syntax, it does not support any modifiers.

So the on variable in this case probably looks something like this:

{ click: onClick, mouseover: onMouseover }

Passing all of the event listeners this way allows for less boilerplate code. The way you would need to do this before v2.4 was like this:

<template v-slot:activator="{ onClick, onMouseover }">
  <v-btn 
    dark 
    @click="onClick" 
    @mouseover="onMouseover"
  > 
    Working button
  </v-btn>
</template>

Upvotes: 2

Ja9ad335h
Ja9ad335h

Reputation: 5075

v-on:click short hand is @click not @on

so you can use @click instead of v-on="on". But here slotProp on is an Object with click (function) property. so you can use it like below

<v-btn dark @click="on.click">Now working button</v-btn>

but it is recommended to use v-on="on" since there could be multiple properties under on Object

Ex: if on is { click: fn(), mouseup: fn() }

<v-btn dark @click="on.click" @mouseup="on.mouseup" >Now working button</v-btn>
<!-- same as -->
<v-btn dark v-on="on">Now working button</v-btn>

Upvotes: 3

Related Questions