I want to create <slot>
s for each child, so for example here I have a menu and I want each child to be placed inside a <div>
with item
class.
I have created a little utility function to map the children:
export function ChildrenMap(el: LitElement, map: (el: HTMLElement, index: number) => TemplateResult): TemplateResult[] {
console.log(el.children.length) // Returns 0 in Google Chrome and I guess Edge too.
return (Array.prototype.slice.call(el.children) as HTMLElement[])
.map(map);
}
And then I am using it in the render function:
render() {
return html`
<nav>
${ChildrenMap(this, (ele, index) => {
let id = ele.id ? ele.id : `item-${index}`;
ele.setAttribute('slot', id);
let klass = 'item';
if(this.selected && this.selected == index) {
klass += " selected";
}
return html`
<div class="${klass}" data-index="${index}">
<slot name="${id}"></slot>
</div>`;
})}
</nav>
`;
}
This works fine in FireFox, but as my comment above says, in Google Chrome, the element has 0 children at the point of render, so the <nav>
is empty.
Can anybody explain why the element has 0 children at the point of render?
Perhaps I am going about this the wrong way, does anybody have any alternatives to do this?
Many thanks
Actually FireFox is wrong at this point, it invokes the connectedCallback
too late
Bug confirmed by Mozilla engineer Anne van Kesteren:
For details see StackOverflow thread:
There are no DOM children to read yet in the connectedCallback
because all DOM children are still being parsed. (it could potentially be a very large DOM structure)
The work-around (like you found) is to wait:
connectedCallback(){
setTimeout(()=>{
// now you can access this. DOM children
},0);
}
All suggestions with Promises etc. effectively do the same: Wait till the Event Loop is empty