Subscribe on changes!

In defineCustomElement does not send event's params

avatar
Aug 27th 2022

Vue version

3.2.37

Link to minimal reproduction

https://codesandbox.io/s/vue-custom-element-prueba-concepto-c6b846

Steps to reproduce

Issue

I have been doing a solution to implement Web components with Vue. This solution needs to use plugins, so I had to implement the defineCustomElement by overwriting the setup. When this procedure is done, the emit does not send parameters. It is also not recognizing custom events; it is only recognizing native events like click. So, in short, I need to send parameters through the emit and overwriting the setup of the defineCustomElement (to be able to inject plugins like the router).

What is expected?

I am waiting to receive the parameters sent through the event and the custom event

What is actually happening?

does not recognize the custom event or the event parameters

System Info

System:
    OS: Linux 5.15 Manjaro Linux
    CPU: (8) x64 AMD Ryzen 7 3700U with Radeon Vega Mobile Gfx
    Memory: 11.43 GB / 17.52 GB
    Container: Yes
    Shell: 5.9 - /usr/bin/zsh
  Binaries:
    Node: 16.14.2 - ~/.nvm/versions/node/v16.14.2/bin/node
    Yarn: 1.22.19 - /usr/bin/yarn
    npm: 8.18.0 - ~/.nvm/versions/node/v16.14.2/bin/npm
  npmPackages:
    vue: ^3.2.37 => 3.2.37

Any additional comments?

It is webComponent.

avatar
Aug 27th 2022

well, you are mounting a child component in your custom element, but don't re-remit its events.

If this was a normal vue app, would you expect the child's event to be available in the component above the component that mounted the child just like that? No - you would need to re-emit the event.

In its most minimal form, this could look like this:

h(component, {
  ...props,
  onDemo: (...args) => emit("demo", ...args)
});

Its up to you to figure out a way to config this dynamically for each of your wrapped custom elements, i.e. by reading the child's emits option.

avatar
Aug 27th 2022

Thank you very much for your help. @LinusBorg Unfortunately what you said makes a lot of sense, but I implemented it and it still doesn't work. You can look at the code and verify that it still doesn't work.

import {
  defineCustomElement as VueDefineCustomElement,
  h,
  createApp,
  getCurrentInstance
} from "vue";

export const defineCustomElement = (component, { plugins = [] } = {}) =>
  VueDefineCustomElement({
    ...component,
    setup(props) {
      const app = createApp(component);

      // install plugins
      plugins.forEach(app.use);

      const inst = getCurrentInstance();
      Object.assign(inst.appContext, app._context);
      Object.assign(inst.appContext, app._context.provides);
      return () =>
        h(component, {
          ...props,
          ondemo: (...args) => inst.emit("demo", ...args),
          click: (...args) => inst.emit("click", ...args)
        });
    }
  });

What I think is that you have to forward the events, as you say, but I don't know if this is done by prototyping or if I am missing something in the h function.

I add that this code is to make a Webcomponent, that is to say, it will be used in any framework or natively; not necessarily in a Vue project.

https://codesandbox.io/s/vue-custom-element-prueba-concepto-c6b846?file=/src/utils.js:0-794

avatar
Aug 27th 2022
- setup(props) {
+ setup(props, { emit }) {
// ....
- ondemo: (...args) => inst.emit("demo", ...args),
+ onDemo: (...args) => emit("demo", ...args),

you have a misspelled prop, and also don't need to use getCurrentInstance()

avatar
Aug 27th 2022

Thank you very much @LinusBorg . It worked wonderfully!