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

2

15

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);
Marj answered 10/3, 2017 at 13:47 Comment(0)
M
36

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

document.createElement("x-product")

is 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.

Matusow answered 10/3, 2017 at 14:26 Comment(1)
Very true! now i understand why now it is "suddenly" working after i have moved the functionality to connectedCallback(), Thank you!Marj
D
2

I also ran into this issue where getAttribute returned null when called from within the constructor. I noticed that in the example index file, the tag has the defer attribute. Once I added the defer attribute to my script tag, the getAttribute call from within the constructor started working.

Doorstone answered 17/3, 2021 at 6:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.