I am trying to build a webcomponent and import it in main HTML file.
my index.html
:
<!DOCTYPE html>
<html>
<head>
<link rel="import" href="./tile.html">
</head>
<body>
<a href="javascript:;" onclick="buildTile()">Build</a>
<ns-tile /> <!-- Works -->
<div id="ns-search-results"></div>
<script>
async function buildTile() {
const results = document.getElementById('ns-search-results');
for(let i = 0; i < 10; i++) {
var nsTile = document.createElement('ns-tile');
results.appendChild(nsTile);
}
}
</script>
</body>
</html>
tile.html
<template id="ns-item-tile">
<style> </style>
<div class="tile"> Tile content </div>
</template>
<script>
class NSTile extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
var importedDoc = document.currentScript.ownerDocument;
let shadowRoot = this.attachShadow({ mode: 'open' });
const t = importedDoc.querySelector('#ns-item-tile');
const instance = t.content.cloneNode(true);
shadowRoot.appendChild(instance);
function init() {
const head = shadowRoot.querySelector('.tile');
head.addEventListener("click", function () {
console.log('click');
});
}
init();
}
} // init the element
customElements.define("ns-tile", NSTile);
</script>
When I use <ns-tile />
directly in index.html, content renders properly. But when I try to render it inside a for
loop in buildTile
method, I am getting an error Uncaught TypeError: Cannot read property 'ownerDocument' of null
at HTMLElement.connectedCallback (tile.html:16)
How can I access the html template inside tile.html
so I can build using for
loop?
A few things:
<ns-tile />
should be replaced with <ns-tile></ns-tile>
<link rel="import" href="">
is dead. Just load the script file normally or use ES6 Import instead.link rel="import"
then you must move var importedDoc = document.currentScript.ownerDocument;
outside of your class.customElements.define('tag-name', className);
Here are some changes to the component file. If you change it to a JS file then it can look like this:
const template = `<style></style>
<div class="tile"> Tile content </div>
`;
class NSTile extends HTMLElement {
constructor() {
super();
let shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = template;
const head = shadowRoot.querySelector('.tile');
head.addEventListener("click", function () {
console.log('click');
});
}
}
customElements.define('ns-tile', NSTile);
<ns-tile></ns-tile>