2
votes

I am creating two custom elements, both are added to index.html using link rel="import". One is a container with slots and the other is something to put a number in the slots. Both elements each have an HTML file with the template and a link to a js file that defines them as custom elements. To link the custom element class declaration to the HTML template I am using:

class PuzzlePiece extends HTMLElement{

constructor(){
    super();
    console.dir(document.currentScript);
    const t = document.currentScript.ownerDocument.getElementById('piece-puzzle');
    const shadowRoot = this.attachShadow({mode: 'open'});
    shadowRoot.appendChild(t.content.cloneNode(true));
 }

This puzzle-piece element and the container render properly and it all works when you manually put them in the index.html light dom

<special-puzzle id="grid">
    <puzzle-piece id="hello"></puzzle-piece>
 </special-puzzle>

However, once I try and create and append a puzzle-piece using JS in index.html:

<script>
    const addToGrid = document.createElement("puzzle-piece");
    document.getElementById("grid").appendChild(addToGrid);
</script>

I see a new puzzle-piece in the special-puzzle light dom but it is not taking up a slot, doesn't render, and the console has the error:

Uncaught TypeError: Cannot read property 'content' of null at new PuzzlePiece (puzzle-piece.ts:8) at HTMLDocument.createElement (:3:492) at (index):37

As far as I can tell the problem is when using document.createElement the browser is getting to the class define but the document.currentScript.ownerDocument is different from when just manually using HTML tags. I believe because of this, the component can't find it's template. This is my first Stack Overflow question so any feedback/help would be appreciated!

1
Here is the code on githubArjun Yelamanchili
Take a look at this answer: stackoverflow.com/a/42093412/4600982Supersharp
@Supersharp WOW you are a lifesaver! I spent 30 minutes searching around and hours trying to fix this but I guess I was using the wrong phrases. Thank you so much for your help!Arjun Yelamanchili

1 Answers

2
votes

Solved thanks to the awesome @Supersharp and their Stack Overflow post

Basically, in order to preserve the correct document.currentScript.ownerDocument I need to declare it in a var before the class then use that var in the class.

Old:

class PuzzlePiece extends HTMLElement{
constructor(){
super();
const t = document.currentScript.ownerDocument.getElementById('piece-puzzle');
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(t.content.cloneNode(true));}

New:

var importedDoc = document.currentScript.ownerDocument;
class PuzzlePiece extends HTMLElement{
constructor(){
super();
const t = importedDoc.getElementById('piece-puzzle');
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(t.content.cloneNode(true));}