In a previous article, I demonstrated how to simplify the Resize Observer API:

“`javascript
// From this
const observer = new ResizeObserver(observerFn)

function observerFn (entries) {
for (let entry of entries) {
// Do something with each entry
}
}

const element = document.querySelector(‘#some-element’)
observer.observe(element);
“`

“`javascript
// To this
const node = document.querySelector(‘#some-element’)
const obs = resizeObserver(node, {
callback({ entry }) {
// Do something with each entry
}
})
“`

Today, we’ll do the same for `MutationObserver` and `IntersectionObserver`.

### Refactoring Mutation Observer

`MutationObserver` has a similar API to `ResizeObserver`, so we can adapt the code for `resizeObserver` to `mutationObserver`.

“`javascript
export function mutationObserver(node, options = {}) {
const observer = new MutationObserver(observerFn)
const { callback, …opts } = options
observer.observe(node, opts)

function observerFn(entries) {
for (const entry of entries) {
if (options.callback) options.callback({ entry, entries, observer })
else {
node.dispatchEvent(
new CustomEvent(‘mutate’, {
detail: { entry, entries, observer },
})
)
}
}
}
}
“`

You can now use `mutationObserver` with the `callback` pattern or event listener pattern.

“`javascript
const node = document.querySelector(‘.some-element’)

// Callback pattern
const obs = mutationObserver(node, {
callback ({ entry, entries }) {
// Do what you want with each entry
}
})

// Event listener pattern
node.addEventListener(‘mutate’, event => {
const { entry } = event.detail
// Do what you want with each entry
})
“`

Much easier!

#### Disconnecting the observer

`MutationObserver` only has the `disconnect` method to stop observing elements.

“`javascript
export function mutationObserver(node, options = {}) {
// …
return {
disconnect() {
observer.disconnect()
}
}
}
“`

Use `takeRecords` before `disconnect` to get unprocessed records.

“`javascript
export function mutationObserver(node, options = {}) {
// …
return {
disconnect() {
const records = observer.takeRecords()
observer.disconnect()
if (records.length > 0) observerFn(records)
}
}
}
“`

Now you can disconnect your mutation observer easily.

“`javascript
const node = document.querySelector(‘.some-element’)
const obs = mutationObserver(/* … */)

obs.disconnect()
“`

#### MutationObserver’s observe options

`MutationObserver`’s `observe` method can take in 7 options. Each defaults to `false`.

– `subtree`: Monitors the entire subtree of nodes
– `childList`: Monitors for addition or removal of child elements
– `attributes`: Monitors for a change of attributes
– `attributeFilter`: Array of specific attributes to monitor
– `attributeOldValue`: Records the previous attribute value if changed
– `characterData`: Monitors for change in character data
– `characterDataOldValue`: Records the previous character data value

### Refactoring Intersection Observer

The API for `IntersectionObserver` is similar to other observers.

1. **Create a new observer:** with the `new` keyword. This observer takes an observer function to execute.
2. **Do something with the observed changes:** via the observer function.
3. **Observe a specific element:** using the `observe` method.
4. **(Optionally) unobserve the element:** using the `unobserve` or `disconnect` method.

`IntersectionObserver` requires options in Step 1. Here’s the code to use the `IntersectionObserver` API.

“`javascript
// Step 1: Create a new observer and pass in relevant options
const options = {/*…*/}
const observer = new IntersectionObserver(observerFn, options)

// Step 2: Do something with the observed changes
function observerFn (entries) {
for (const entry of entries) {
// Do something with entry
}
}

// Step 3: Observe the element
const element = document.querySelector(‘#some-element’)
observer.observe(element)

// Step 4 (optional): Disconnect the observer
observer.disconnect(element)
“`

We can adapt the code for `mutationObserver` to `intersectionObserver`, remembering to pass options into `IntersectionObserver`.

“`javascript
export function intersectionObserver(node, options = {}) {
const { callback, …opts } = options
const observer = new IntersectionObserver(observerFn, opts)
observer.observe(node)

function observerFn(entries) {
for (const entry of entries) {
if (options.callback) options.callback({ entry, entries, observer })


Discover more from WIREDGORILLA

Subscribe to get the latest posts sent to your email.

Similar Posts