Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

emits property blocks $attrs injection #4736

Closed
marina-mosti opened this issue Oct 5, 2021 · 5 comments
Closed

emits property blocks $attrs injection #4736

marina-mosti opened this issue Oct 5, 2021 · 5 comments
Labels
has workaround A workaround has been found to avoid the problem ✨ feature request New feature or request

Comments

@marina-mosti
Copy link

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

@LinusBorg LinusBorg added ✨ feature request New feature or request has workaround A workaround has been found to avoid the problem labels Oct 5, 2021
@LinusBorg
Copy link
Member

LinusBorg commented Oct 5, 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.

@marina-mosti
Copy link
Author

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".

@marina-mosti
Copy link
Author

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>

@posva
Copy link
Member

posva commented Oct 5, 2021

This behavior is expected (vuejs/rfcs#154 (comment)) so it should maybe be documented instead.

This is a duplicate of #3432, #4736, #4489.

Given #3432 (comment), 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?

@posva posva closed this as completed Oct 5, 2021
@marina-mosti
Copy link
Author

As suggested, discussion open here: vuejs/rfcs#397

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
has workaround A workaround has been found to avoid the problem ✨ feature request New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants