Search code examples
web-componentextendscustom-elementnative-web-component

extend custom element web components v1


I have a custom Web Component, <app-list> that I'm trying to extend into <calcs-list>.

// app-list.html

<script>
    window.customElements.define('app-list',

        class AppList extends HTMLElement {
            constructor() {
                super();
            }
        }

    );
</script>

In calcs-list.html I've got:

<link rel="import" href="app-list.html">
<script>

window.customElements.define('calcs-list',

    class CalcsList extends AppList {

        constructor() {
            super();
            console.log('CalcsList constructed');
        }

    }

);

</script>

However, I get the error

Uncaught ReferenceError: AppList is not defined at calcs-list.html:11

Line 11 references class CalcsList extends AppList {

Both files are siblings of the same folder. I tried using an absolute path when importing app-list.html into calcs-list.html but got the same result.

I also tried importing both components into my main index.html file:

//index.html
<link rel="import" href="/src/components/app-list.html">
<link rel="import" href="/src/components/calcs-list.html">

<app-list></app-list>
<calcs-list></calcs-list>

But experience the same result.

The app-list component works in my application without any issue.

I'm scratching my head on this one and because Web Components are considerably new, there isn't a whole lot of troubleshooting info online, especially with V1 of Web Components.

Thanks!


Solution

  • Thanks to @Supersharp, I re-wrote my custom component declaration as such:

    // app-list.html    
    <script>
        class AppList extends HTMLElement { ... }
        customElements.define('app-list', AppList);
    </script>
    

    And calcs-list.html:

    <script>
        class CalcsList extends AppList { ... }
        customElements.define('calcs-list', CalcsList);
    </script>
    

    A note of caution: If you declare a tag within the parent element (the element that's being extended) with an id then this will conflict with the extended element's call to super().

    For example:

    <template id="app-list"> 
        ... 
    </template>
    

    The way to work around this is to use a JavaScript string literal, as referenced by the Google Developers, and not use an id at all.

    <script>
    
        let template = document.createElement('template');
        template.innerHTML = `
            <style> ... </style>
            <div> ... </div>
        `;
    
        class AppList extends HTMLElement {
            constructor() {
                super();
                let shadowRoot = this.attachShadow({mode: 'open'}).appendChild(template.content.cloneNode(true));
            }
        }
    
    </script>