Subscribe on changes!

emits property blocks $attrs injection

avatar
Oct 5th 2021

Version

3.2.19

Reproduction link

codesandbox.io

Steps to reproduce

Having a component that both declares emits because it itself emits an event (see Mid component in sandbox) and that also expects to pass down onMyEvent down as $attr fallthrough to a Child does not work.

The emits option effectively makes the onMyEvent attribute disappear from $attrs, and the chain is broken.

What is expected?

emits property should not remove onX from $attrs

What is actually happening?

It gets removed and breaks attribute event inheritance

avatar
Oct 5th 2021

There's a workaround by defining the event in props instead of emits:

<template>
  <div>
    <Child v-bind="{ ...$attrs, onMyEvent }" />

    <button @click="$emit('my-event')">Mid emit</button>
  </div>
</template>

<script>
import Child from "./Child.vue";

export default {
  //emits: ["myEvent"],
  props: {
    onMyEvent: Function,
  },
  inheritAttrs: false,
  components: { Child },
};
</script>

The cleaner solution would likely be to provide a way of accessing the events that were declared with emits. They should not be part of $attrs, IMHO, as the default usecase of $attrs is to access anything that was not declared in props/emits.

avatar
Oct 5th 2021

Thanks @LinusBorg that's a nice workaround! Hopefully, we can get a proper solution 🙏🏻 I agree with you that $attrs should not include it as it does feel like the magic box of "everything else".

avatar
Oct 5th 2021

To document another workaround, explicitly listening for and then re-emitting the event also works.

<template>
  <div>
    <Child v-bind="$attrs" @myEvent="$emit('myEvent')" />

    <button @click="$emit('my-event')">Mid emit</button>
  </div>
</template>

<script>
import Child from "./Child.vue";

export default {
  emits: ["myEvent"],
  inheritAttrs: false,
  components: { Child },
};
</script>
avatar
Oct 5th 2021

This behavior is expected (https://github.com/vuejs/rfcs/pull/154#issuecomment-614724480) so it should maybe be documented instead.

This is a duplicate of https://github.com/vuejs/vue-next/issues/3432, #4736, #4489.

Given https://github.com/vuejs/vue-next/issues/3432#issuecomment-812237075, this should go into a discussion in the rfcs repo with a proposal to enable $attrs still have the listeners that are declared in emits. Maybe a new option similar to inheritAttrs to explicitly state that $attrs should also have listeners declared in emits.

You can find a well-described example of how to handle this in this reply by @LinusBorg

@marina-mosti can you open a new discussion in the rfcs repo?

avatar
Oct 5th 2021

As suggested, discussion open here: https://github.com/vuejs/rfcs/discussions/397