Skip to content

watchAttributes

ts
watchAttributes(el: Element, callback: (change: AttributeChange) => void): () => void

Observes every attribute of one element, through a second, unfiltered observer.

ts
interface AttributeChange {
  name: string;
  value: string | null;
  previousValue: string | null;
}

Why it exists

attributeFilter takes exact names and the DOM has no wildcard, so the engine cannot see an attribute the framework cannot name. This is the opt-in, and the page pays for the elements that ask.

Usage

js
import { 
Base
,
watchAttributes
} from '@studiometa/js-toolkit';
class
Bindings
extends
Base
{
static
config
= {
name
: 'Bindings' };
mounted
() {
return
watchAttributes
(this.
$el
, ({
name
,
value
,
previousValue
}) => {
if (!
name
.
startsWith
('data-my-')) return;
// … }); } }

The caller owns it. The helper returns one idempotent cleanup and knows nothing about Base: a component calls it from mounted() and returns the cleanup.

The contract

  • The records join the shared queue. They are drained wherever the engine drains its own, whenDOMSettled() included, and they are reported from the same background task — as the last step of the batch.
  • A callback runs after the framework work of the batch. So a component that stops its watcher during the same batch in which its own declaration is withdrawn hears nothing about the attribute change.
  • Changes are coalesced, with the rule of option<Name>Changed(): several writes in one batch give one change, from the value before the first write to the value at the end, and a write that ends where it started is not a change.
  • The payload covers the element's whole attribute set, framework names included, with raw strings and null for an absent attribute. A caller narrows by prefix.
  • A failing callback is reported as callback.attribute-watcher-failed, so one watcher cannot stop another.

What to reach for instead

WantUse
a declared optionoption<Name>Changed()
a whole namespace, with keyed bindingswatchAttributeNamespace()
a subtree, character data, or a foreign nodeuseMutation()

A declared option is already in the one page-wide filter, and costs no second observer.

MIT Licensed