I've created and exported one Angular Element (web component in Angular) as a single script tag (user-poll.js). To use this Angular Element I just need to specify below two lines in the host site:
<user-poll></user-poll>
<script src="path/to/user-poll.js"></script>
I've following requirements:
I've following issues:
JSBin example of the dynamically loading component inside the shadow dom
<body>
</body>
setTimeout(() => {
loadJS();
}, 2000);
function loadJS() {
var elm = document.createElement("div");
elm.attachShadow({mode: "open"});
elm.shadowRoot.innerHTML = `<user-poll><h2>Custom Web Component - user-poll loaded</h2><script src="https://cdn.rawgit.com/SaurabhLpRocks/795f67f8dc9652e5f119bd6060b58265/raw/d5490627b623f09c84cfecbd3d2bb8e09c743ed4/user-poll.js"><\/\script></user-poll>`;
document.body.appendChild(elm);
}
So, what is the best way to dynamically load multiple Angular Elements on a site?
The fact that the script is not executed is not related to Shadow DOM, but to the way you try to insert the <script>
element, that is via a string in innerHTML
.
In this case the string is not interpreted and the script not executed.
If you want it to work you must insert the <script>
via appendChild()
.
You can do it directly by adding a <script>
element created with createElement()
, or by using a <template>
element.
1. with createElement()
Create a <script>
element and append it to its parent:
var up = document.createElement( 'user-poll' )
var script = document.createElement( 'script' )
script.textContent = 'document.write( "executed" )'
up.appendChild( script )
elm.attachShadow( { mode: 'open' } )
.appendChild( up )
<div id="elm"></div>
2. with a <template>
tag
Append the content of a <template>
element:
elm.attachShadow( { mode: 'open' } )
.appendChild( tpl.content )
<template id="tpl">
<user-poll>
<script>document.write( 'exected' )</script>
</user-poll>
</template>
<div id="elm"></div>
The script is not executed when the <template>
element is parsed, but when its content
is appended to the DOM.
PS: anyway I'm not sure it's the best way to load multiple Angular elements: Shadow DOM won't act as a sandbox for Javascript code, as <iframe>
does. Instead maybe you'll have to use a module loader.