open-wc / open-wc

Open Web Components: guides, tools and libraries for developing web components.
https://open-wc.org/
MIT License
2.25k stars 423 forks source link

Child component properties can not be accessed by parent in Vanilla JS #2553

Open antoinechampion opened 1 year ago

antoinechampion commented 1 year ago

Expected behavior

When there are two nested web-components ParentComponent and ChildComponent, and that the parent accesses the child through Shadow DOM, it should be able to access properties and methods from the child component just as in the browser.

Actual Behavior

The below test throws TypeError: this.childComponent.childMethod is not a function;

<html>
<head>
    <script type="module">
        export class Child extends HTMLElement {
            constructor() {
                super();
                const shadowRoot = this.attachShadow({ mode: "open" });
            }
            childMethod() {
                console.log("Called");
            }
        }
        window.customElements.define("child-component", Child);

        const templateParent = document.createElement('template');
        templateParent.innerHTML = `
            <child-component></child-component>
        `;

        export class Parent extends HTMLElement {
            childComponent;

            constructor() {
                super();
                const shadowRoot = this.attachShadow({ mode: "open" });
                shadowRoot.appendChild(templateParent.content.cloneNode(true));
                this.childComponent = shadowRoot.querySelector("child-component");
            }
            connectedCallback() {
                this.childComponent.childMethod();
            }
        }
        window.customElements.define("parent-component", Parent);
    </script>
</head>

<body>
<script type="module">
    import {html, fixture} from "@open-wc/testing";

    import { runTests } from '@web/test-runner-mocha';
    runTests(async () => {
        describe("Parent", () => {

            it("should call children", async () => {
                const el = await fixture(html`<parent-component></parent-component>`);
            });
        });
    });
</script>
</body>
</html>

Additional context

Stack trace:

[INFO]       Error: Uncaught TypeError: this.childComponent.childMethod is not a function (http://localhost:8000/demo.test.html?wtr-session-id=7L0lWcdRCn5ILddGDxUF2:178)
[INFO]         at N.O (node_modules/lit-html/src/lit-html.ts:1402:52)
[INFO]         at N.T (node_modules/lit-html/src/lit-html.ts:1442:35)
[INFO]         at N.$ (node_modules/lit-html/src/lit-html.ts:1548:11)
[INFO]         at N._$AI (node_modules/lit-html/src/lit-html.ts:1375:11)
[INFO]         at Z (node_modules/lit-html/src/lit-html.ts:2169:7)
[INFO]         at litFixtureSync (node_modules/@open-wc/testing-helpers/src/litFixture.js:32:3)
[INFO]         at litFixture (node_modules/@open-wc/testing-helpers/src/litFixture.js:63:14)
[INFO]         at fixture (node_modules/@open-wc/testing-helpers/src/fixture-no-side-effect.js:62:12)
[INFO]         at o.<anonymous> (demo.test.html:196:34)

Dependencies:

    "@open-wc/testing": "^3.1.7",
    "@web/test-runner": "^0.15.0",
    "@web/test-runner-mocha": "^0.7.5",
bennypowers commented 1 year ago

Define the child first

antoinechampion commented 1 year ago

@bennypowers same behavior if I define the child before the parent, I edited the snippet.