This was just taking the final React code in the article and rewriting it in vanilla as close as possible.
Your comment is fully correct, but I would like to point out:
- with such a tiny DOM to rerender, it is equivalent, probably even faster
- custom element encapsulates DOM and it is fairly trivial and extremely fast to pick DOM (like you can even use id's everywhere) in the 'old jquery' way, with simple library functions
- updating DOM with simple render() call is way more elegant, but if you keep custom elements DOM small (and one should), this way is not that bad at all
Like this:
<!doctype html>
<body>
<custom-element></custom-element>
<script>
const CHECKBOX_ID = "my-checkbox";
const defaultLabelContent = "Toggle me, you newbies";
const beforeDiscountText = "You have not availabled discount";
const afterDiscountText = "Discount Availed!";
const beforeLabelText = "Click on me to remove fake discount"
const afterLabelText = "Click me to apply fake discount!"
const state = new WeakMap();
// 'library' code
function qs(selector) {
return this.shadowRoot.querySelector(selector);
}
function getElem(nodeOrSelector) {
return nodeOrSelector === String(nodeOrSelector) ? qs.call(this, nodeOrSelector) : nodeOrSelector;
}
function replaceText(nodeOrSelector, text) {
let elem = getElem.call(this, nodeOrSelector);
if (elem) elem.textContent = text;
}
function updateAttribute(nodeOrSelector, name, value = '') {
let elem = getElem.call(this, nodeOrSelector);
if (elem) elem[(value ? 'set' : 'remove') + 'Attribute'](name, value);
}
// end of 'library' code
class CustomElement extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<input type="checkbox" id=${CHECKBOX_ID}>
<label for=${CHECKBOX_ID}></label>
<div></div>
`;
this.shadowRoot.addEventListener('change', (event) => {
state.set(this, event.target.checked);
this.update();
})
this.update();
}
update() {
let isChecked = state.get(this);
updateAttribute.call(this, 'input', 'checked', isChecked);
replaceText.call(this, 'label', isChecked ? beforeLabelText : afterLabelText);
replaceText.call(this, 'div', isChecked ? afterDiscountText : beforeDiscountText);
}
}
customElements.define('custom-element', CustomElement);
</script>