My goal is to set observedAttributes
dynamically, so my web component will watch only attributes following a pattern, like a colon (:attr) <my-element static="value1" :dynamic=${dynamic}/>
In this case, <my-element>
should set observedAttributes
only for the attribute :dynamic
The problem is that static get observedAttributes()
runs before there's even a this
, explained in https://andyogo.github.io/custom-element-reactions-diagram/
So this won't work
static get observedAttributes() {
return this.getAttributeNames().filter((item) => item.startsWith(':'));
}
and of course neither does
constructor() {
super();
this._observedAttributes = this.getAttributeNames().filter((item) => item.startsWith(':'));
}
static get observedAttributes() {
return this._observedAttributes;
}
Thanks!
<!DOCTYPE html>
<body>
<my-element static="value1" :dynamic="value2" ></my-element>
<script>
class MyElement extends HTMLElement {
constructor() {
super();
this._observedAttributes= this.getAttributeNames().filter((item) => item.startsWith(':'));
console.log('observedAttributes',this._observedAttributes);
}
static get observedAttributes() {
return this._observedAttributes;
}
attributeChangedCallback(name, oldValue, newValue) {
console.log(name, oldValue, newValue); //doesn't log anything
}
}
customElements.define("my-element", MyElement);
setTimeout(() => {
console.log('setting dynamic attribute. This should trigger attributeChangedCallback. But no.');
document.querySelector('my-element').setAttribute(':dynamic', 'value3');
}, 2000);
</script>
</body>
</html>
Following @Danny '365CSI' Engelman's suggestion, I looked at the MutationObserver API and came up with a simple solution that I think offers more than observedAttributes
<my-element static="value1" :dynamic="value2"></my-element>
<script>
class MyElement extends HTMLElement {
constructor() {
super();
}
mutationObserverCallback(mutationList, observer) {
for (const mutation of mutationList) {
if (mutation.type === 'attributes' &&
mutation.attributeName.startsWith(':') &&
mutation.oldValue !== mutation.target.getAttribute(mutation.attributeName)) {
console.log(`The dynamic ${mutation.attributeName} attribute was modified.`);
}
}
}
connectedCallback() {
this.mutationObserver = new MutationObserver(this.mutationObserverCallback);
this.mutationObserver.observe(this, {
attributes: true,
attributeOldValue: true
});
}
disconnectedCallback() {
this.mutationObserver.disconnect();
}
}
customElements.define("my-element", MyElement);
setTimeout(() => {
console.log('setting dynamic attribute for :dynamic and static attributes. This should trigger mutationObserverCallback for :dynamic only.');
// ▼ will trigger mutationObserverCallback
document.querySelector('my-element').setAttribute(':dynamic', 'value3');
// ▼ will not trigger mutationObserverCallback
document.querySelector('my-element').setAttribute('static', 'value4');
}, 200);
</script>