My question is can my Custom Element observe Dataset/Data-* attributes and reacted to changes in such attributes?
I've seem a couple of similar posts that imply the answer is "No, you have to use a DOM Mutation Observer".
Can someone please confirm one way or the other?
Edit: Just thought the real answer is "It's a "custom" element; just add a real attribute and stop using the dataset!
Example: -
static get observedAttributes() {
return ['data-clicked'];
}
connectedCallback() {
console.log('Connected ' + this.isConnected);
if (!this.isConnected) return;
this.#button.addEventListener("click", this.#menuClicked)
}
disconnectedCallback()
{
this.#button.removeEventListener("click", this.menuClicked)
}
attributeChangedCallback(name, oldValue, newValue) {
if (!this.isConnected) return;
if (newValue == null) {
this[name] = "";
delete this[name];
return;
}
if (typeof newValue != "boolean")
throw new Error(this.tagName + ", Illegal value. [" + name + "] must be a boolean.");
}
#menuClicked(e) {
var menu = e.target.classList.contains("menu_btn") ? e.target : e.target.closest(".menu_btn");
if (menu.dataset["clicked"] != undefined) {
menu.addEventListener("animationend",
(e) => {
menu.classList.remove('menuClick');
} , {"once": true}
);
menu.classList.add('menuClick');
if (menu.dataset.clicked == "false") {
menu.dataset.clicked = true;
} else {
menu.dataset.clicked = false;
}
}
}
And yes there are good reasons for not "Just use CSS"
Using the static get observedAttributes(){} with attributeChangedCallback, yes, the attributes can be observed to change...
Below example demonstrates reacting to these changes of attributes. The defined function is provided the new value and the old value.
The dataset attribute is THE way to go! If your element needs to use data, use the dataset attribute.
After clicking the buttons, have a gander at / inspect the HTML element, it now lists these data-* attributes.
class TestComponent extends HTMLElement {
static get observedAttributes() {
return [
'data-test',
'data-value'
];
};
attributeChangedCallback(name, oldValue, newValue) {
// signature includes name of attribute, old value and new value
// so, this fires for any listed attribute, in the shared ( static )
switch (name) {
case 'data-value':
{
// no alert this way
console.log(`${name} has changed from ${oldValue} to ${newValue}`);
break;
};
default:
{
alert(`${name} has changed from ${oldValue} to ${newValue}`);
break;
};
};
};
};
customElements.define('test-component', TestComponent);
function pushTest(att, val) {
let tC = document.querySelector('test-component');
tC.dataset[att] = val;
console.log(tC);
};
let ptC = document.querySelector('#push-button-test');
ptC.onclick = (e) => pushTest('test', 'test');
let ptV = document.querySelector('#push-button-value');
ptV.onclick = (e) => pushTest('value', 'value');
<test-component>
</test-component>
<button id='push-button-test'>Push "Test" value</button><br>
<button id='push-button-value'>Push "Value" value</button>