Loading html document with head and scripts into element

Viewed 230

I'm using custom web components with shadow dom to load an html file into the element, I can't seem to find a way to load it as an html file without having a delay the header scripts and style links.

In other words, scripts are not loading and external css files in the head tag are delayed till after the html is fully loaded.

the html file looks like this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html lang="en">

<head>
    <title>My Document</title>
    <link href="/MyStyles.css" rel="stylesheet" type="text/css" />
    <script src="/MyScripts.js" type="text/javascript"></script>
</head>

<body>
    <!-- Other Main Tags -->

    <script src="/AnotherScript.js" type="text/javascript"></script>
</body>

</html>

Javascript:


customElements.define('ui-include', class extends HTMLElement {

    async connectedCallback() {
        let ref = this.getAttribute('ref')

        const shadow = this.attachShadow({ mode: 'open' })
        shadow.innerHTML = 'Loading...';

        fetch(`/documentviewer.aspx/GetContent`,
            {
                body: JSON.stringify({ reference: ref }),
                method: "post",
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                },
            })
            .then(r => r.json())
            .then(r => {
                // r.d is the response html string (html file example above)
                shadow.innerHTML = r.d ;
            })
            .catch(e => {
                console.error(e)
            })
            .then(() => {
                console.log('done')
            })
    }
})

HTML:

<ui-include ref="Document_123"></ui-include>

After the page is loaded, when inspecting the ui-include. header tag is not showing anymore. like it was unwraped, heres a screenshot:

enter image description here

Please Note that the selected script in the image is /MyScripts.js not /MyScripts

How can I treat the html response string as an actual document and load it into the web component?

2 Answers

You can take help of DOM Parser like this:

customElements.define('ui-include', class extends HTMLElement {
    async connectedCallback() {
        let ref = this.getAttribute('ref')
        const shadow = this.attachShadow({ mode: 'open' })
        shadow.innerHTML = 'Loading...';
        fetch(`/documentviewer.aspx/GetContent`, {
                body: JSON.stringify({ reference: ref }),
                method: "post",
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                },
            })
            .then(r => r.json())
            .then(r => {
                shadow.children[0].remove();
                const dp = new DOMParser();
                const f = document.createDocumentFragment();
                const pDom = dp.parseFromString(r.d, 'text/html');
                f.appendChild(pDom.documentElement)
                shadow.appendChild(f);
            })
            .catch(e => console.error(e))
            .then(() => console.log('done'));
    }
})

How can I treat the html response string as an actual document and load it into the web component?

If you want to transform a string into a document you should use createHTMDocument. But the content a Web Component is not a document but only a DocumentFragment.

For this reason you cannot have or elements in a Custom Element or in a Shadow DOM.

The way you loaded the string with innerHTML is valid as much as using appendChild() with an Element or a DocumentFragment.

Related