skip to content
dz

Back to the article 路 Zur眉ck zum Artikel (Deutsch)

Example 01: Upgrade and createElement side by side

Rule 1: Don't touch attributes or children in the constructor

Two elements, same code: the first is in the HTML and gets its upgrade when define() runs (a script with type="module" runs after parsing), the second is created with document.createElement() and gets its name with setAttribute(). The text is built in the constructor from the attribute on purpose, which is what rule 1 warns against.

How to try it

  1. Open the console of the developer tools (F12, Cmd+Opt+I on a Mac). The "Console output" box on this page shows the same lines. Reload the page to run it again.
  2. The first element says "馃憢 Hello, Ada!", the second says "馃憢 Hello, null!", although setAttribute('name', 'Grace') ran for it as well.
  3. In the console, the first three lines belong to the first element, the next three to the second one. Compare the two constructor lines.
Console output mirrored from console.log() and errors on this page, the same text as in the developer tools
Expected output what the lines above should say
constructor Ada
attributeChangedCallback name null Ada
connectedCallback
constructor null
attributeChangedCallback name null Grace
connectedCallback

The first constructor already sees the attribute (upgrade), the second one does not (createElement). The attributeChangedCallback comes afterwards in both cases.

Live example

Source

<p><hello-name name="Ada"></hello-name></p>

<script type="module">
	class HelloName extends HTMLElement {
		static observedAttributes = ['name'];

		constructor() {
			super();
			console.log('constructor', this.getAttribute('name'));
			// The mistake: the attribute is read in the constructor.
			this.attachShadow({ mode: 'open' }).textContent = `馃憢 Hello, ${this.getAttribute('name')}!`;
		}

		attributeChangedCallback(name, oldValue, newValue) {
			console.log('attributeChangedCallback', name, oldValue, newValue);
		}

		connectedCallback() {
			console.log('connectedCallback');
		}
	}

	customElements.define('hello-name', HelloName);

	const created = document.createElement('hello-name');
	created.setAttribute('name', 'Grace');
	document.body.append(created);
</script>