I am trying an example of custom web components from MDN. So I ended with this code
class Info extends HTMLElement
{
constructor()
{
super();
const shadow = this.attachShadow({mode: 'open'});
const wrapper = document.createElement('span');
wrapper.setAttribute('class', 'wrapper');
const icon = document.createElement('span');
icon.setAttribute('class', 'icon');
icon.setAttribute('tabindex', 0);
const info = document.createElement('span');
info.setAttribute('class', 'info');
// Take attribute content and put it inside the info span
const text = this.getAttribute('data-text');
info.textContent = text;
console.log(JSON.stringify(this.attributes['img']));
// Insert icon
const img = document.createElement('img');
img.src = this.hasAttribute('img') ? this.getAttribute('img') : 'img/default.png';
icon.appendChild(img);
// Create some CSS to apply to the shadow dom
const style = document.createElement('style');
style.textContent = `
.wrapper { position: relative; }
img { width: 1.2rem; }
`;
// Attach the created elements to the shadow dom
shadow.appendChild(style);
shadow.appendChild(wrapper);
wrapper.appendChild(icon);
wrapper.appendChild(info);
}
}
customElements.define('a-info', Info);
<html>
<head></head>
<body>
<a-info img="img/alt.png" data-text="Your card."></a-info>
</body>
</html>
It almost works. The element is created except this.getAttribute('data-text')
returns undefined.
I run it locally in Firefox.
Could someone explain what is the issue with this example, please?
Yes, in the Constructor phase there is no DOM available
see: https://andyogo.github.io/custom-element-reactions-diagram/
And don't rely too much on official documentation, it is bloated and sometimes plain wrong:
<script>
class Info extends HTMLElement {
constructor() {
let createElement = (name, className) => {
let el = document.createElement(name);
if (className) el.classList.add(className);
return el;
}
// yes you can add code *before* super()
const style = createElement('style');
style.textContent = `.wrapper {position:relative}img {width: auto}`;
const wrapper = createElement('span', 'wrapper');
const icon = createElement('span', 'icon');
icon.setAttribute('tabindex', 0);
super() // set AND return this scope
.attachShadow({mode: 'open'}) // set AND return this.shadowRoot
.append(style,wrapper);
this.info = createElement('span', 'info');
this.img = createElement('img');
icon.append(this.img);
wrapper.append(icon, this.info);
}
connectedCallback() {
this.info.textContent = this.getAttribute('data-text') || "card?";
this.img.src = this.getAttribute('img') || 'https://via.placeholder.com/42';
}
}
customElements.define('a-info', Info);
</script>
<a-info></a-info>
<a-info img="https://via.placeholder.com/110" data-text="Card #1"></a-info>
<a-info img="https://via.placeholder.com/120" data-text="Card #2"></a-info>