Amalin Amalin - 9 months ago 28
Javascript Question

Custom Element class: this.getAttribute('data-*') returns null

I have copy & pasted to code from the Mozzila example
https://developer.mozilla.org/en-US/docs/Web/Web_Components/Custom_Elements#Observed_attributes
to files on my computer, and when i run it, i get null from every call to this.getAttribute.
I see it working on the link above but when i run my copied project, it's null, the same is happening in another project i wrote, based on this example:

HTML file:

If nothing appeared below, then your browser does not support Custom Elements yet.
<x-product data-name="Ruby" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/ruby.png" data-url="http://example.com/1"></x-product>
<x-product data-name="JavaScript" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/javascript.png" data-url="http://example.com/2"></x-product>
<x-product data-name="Python" data-img="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4621/python.png" data-url="http://example.com/3"></x-product>


JS file:

// Create a class for the element
class XProduct extends HTMLElement {
constructor() {
// Always call super first in constructor
super();

// Create a shadow root
var shadow = this.attachShadow({mode: 'open'});

// Create a standard img element and set it's attributes.
var img = document.createElement('img');
img.alt = this.getAttribute('data-name');
img.src = this.getAttribute('data-img');
img.width = '150';
img.height = '150';
img.className = 'product-img';

// Add the image to the shadow root.
shadow.appendChild(img);

// Add an event listener to the image.
img.addEventListener('click', () => {
window.location = this.getAttribute('data-url');
});

// Create a link to the product.
var link = document.createElement('a');
link.innerText = this.getAttribute('data-name');
link.href = this.getAttribute('data-url');
link.className = 'product-name';

// Add the link to the shadow root.
shadow.appendChild(link);
}
}

// Define the new element
customElements.define('x-product', XProduct);

Answer Source

You should use this.getAttribute() in the connectedCallback() method as attributes may be not defined yet when the constructor() method is called.

It's the case here where constructor() is called as soon as <x-product> is parsed, when its attributes are not attached yet.


Note that it could still work if you place the customElement.define() statement after the html code <x-product data-...>. This because the attributes are already attached to the <x-product> elements when the tag is defined as a Custom Element.

Look at this question for more details.