I've crafted a custom built-in element that recursively invokes itself. However, the child elements generated in JavaScript are not inheriting from the custom built-in element. Given that the initial invocation from HTML is functioning correctly, I suspect the issue may stem from the page lifecycle when adding controls via JavaScript. Any thoughts on why this could be occurring?
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul is="test-list" id="testList">
</ul>
<script type="module" src="/js/test-list-element.js"></script>
<script>
let data = [
{
name: 'a',
data: [{
name: 'a',
data: []
},
{
name: 'b',
data: []
},
{
name: 'c',
data: []
},
{
name: 'd',
data: []
}]
},
{
name: 'b',
data: [{
name: 'a',
data: []
},
{
name: 'b',
data: []
},
{
name: 'c',
data: []
},
{
name: 'd',
data: []
}]
},
{
name: 'c',
data: [{
name: 'a',
data: []
},
{
name: 'b',
data: []
},
{
name: 'c',
data: []
},
{
name: 'd',
data: []
}]
},
{
name: 'd',
data: [{
name: 'a',
data: []
},
{
name: 'b',
data: []
},
{
name: 'c',
data: []
},
{
name: 'd',
data: []
}]
},
];
window.onload = (event) => {
let listElement = document.getElementById("testList");
listElement.data = data;
}
</script>
</body>
</html>
test-list-element.js
class testList extends HTMLUListElement {
constructor() {
super();
this.render = this.render.bind(this);
}
#data = null;
set data(value) {
this.#data = value;
this.render();
}
render(){
if(!this.#data) return;
this.#data.forEach(element => {
let newItem = document.createElement('li');
newItem.innerText = element.name;
this.appendChild(newItem);
if(element.data)
{
let newlist = document.createElement('ul');
newlist.setAttribute('is','test-list')
newlist.data = data;
newItem.appendChild(newlist);
}
});
}
}
customElements.define('test-list', testList, { extends: 'ul' });
Don't use
const newlist = document.createElement('ul');
newlist.setAttribute('is','test-list');
to create the element, as the is
part must be present on construction time; setting it after construction has no effect.
The correct way to instantiate a custom element is either the createElement
options parameter
const newlist = document.createElement('ul', {is: 'test-list'});
or just the constructor itself:
const newlist = new TestList();