karol-f / vue-custom-element

Vue Custom Element - Web Components' Custom Elements for Vue.js
https://karol-f.github.io/vue-custom-element/
MIT License
1.97k stars 187 forks source link

Setting Props programmatically on nested custom elements #135

Closed RBrNx closed 6 years ago

RBrNx commented 6 years ago

In my current application I have two vue-custom-elements set up, one of which is inserted into the slot of the other.

I have the vue-custom-elements set up in main.js

Vue.customElement('parent-custom-element', ParentElement);
Vue.customElement('child-custom-element', ChildElement);

I then have the following code in a function in a Vue component to add the custom-elements to the DOM.

var  parent = document.createElement("parent-custom-element");
parent.parentProp = "Testing";

var child = document.createElement('child-custom-element');
child.childProp = "Another Test";

parent.appendChild(child);

document.body.appendChild(parent);

The parent receives the parentPropwithout any issue, however the child's childProp is undefined once the element has been added to the DOM, is there any way to solve this?

I have set up this barebones example of the issue: https://codesandbox.io/s/2oyjywo2mr

karol-f commented 6 years ago

Hi, as stated in documentation, slots are for static content only. So after Vue put rendered custom element into slot it's just HTML, without any handlers.

I don't think that it could be solved easily, however in https://github.com/vuejs/vue-web-component-wrapper you have reactive slots - you can try that solution and if browser support suits You you can switch to it.

You could also try to register child custom elements only after root custom element is rendered. That way in it's slot will be only e.g. <vue-widget-test></vue-widget-test> and will render from inside and hopefully you woun't loose any handlers etc. You can do this on vce-ready events, which is triggered on every custom element after vue instance creation.

I will try to fiddle with code a bit - maybe I will find simple solution.

RBrNx commented 6 years ago

Thanks for your help Karol. Unfortunately IE9 support is a must so that throws vue-web-component-wrapper out of the window.

I will try out your suggestion and let you know if I can get it working!

RBrNx commented 6 years ago

OK so with some small changes as per your suggestion I managed to get it working!

By appending the child after the parent has been added to the DOM it seems like it keeps it's props.

var  parent = document.createElement("parent-custom-element");
parent.parentProp = "Testing";

var child = document.createElement('child-custom-element');
child.childProp = "Another Test";

document.body.appendChild(parent);

parent.appendChild(child);

You can see it working in this modified example: https://codesandbox.io/s/1qqnol5ol

EDIT: Although I have just noticed that this wont target the <slot>, it just appends the child. There might be a way around that?

karol-f commented 6 years ago

@RBrNx Hi, in https://codesandbox.io/s/vy900nj5o5 it's working as we pass child's custom element HTML to parent and register it only when parent is rendered. I will think about simpler solution.

You can also think about adding child custom elements to parent's vue component template so it won't be change due to slot usage.

karol-f commented 6 years ago

@RBrNx Maybe the problem is that var child = document.createElement('child-custom-element'); no longer points to correct DOM node as after Vue put element to slot its moved to other place.

You can execute something like var child = parent.querySelector('child-custom-element')

To see what I'm talking about please select child-custom-element in Dev Tools and change it's prop - it should be working. If so the problem is with incorrect DOM node refference.

RBrNx commented 6 years ago

@karol-f Looks like you might be right!

Changing the child's prop using the querySelector after the parent + child have been appending to the DOM seems to work.

parent.querySelector("custom-child-element").childProp = "This works!";

You can see it working in: https://codesandbox.io/s/n1w9yxxnol

karol-f commented 6 years ago

Nice, also if you update to vue-custom-element@3.2.3 you can use a little bit simpler version - https://codesandbox.io/s/zr7o1kr8wx

Regards!