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
- 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.
- The first element says "馃憢 Hello, Ada!", the second says "馃憢 Hello, null!", although
setAttribute('name', 'Grace')ran for it as well. - In the console, the first three lines belong to the first element, the next three to the second one. Compare the two
constructorlines.
console.log() and errors on this page, the same text as in the developer toolsconstructor 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>