Skip to content

Commit 88cfaef

Browse files
authored
fix(observedom): Callback not being called for changes other than childList changes (bootstrap-vue#1025)
* fix(observedom): Callback not being called for changes other than node inert/remove Allow callback to be called based on passed options. Previously it was only being called if nodes were added or inserted, regardless of which options were passed (i.e. attribute changes, childList, textnode changes, etc.) This fix remove this restriction. * Create loose-equal.js * Update index.js * Update observe-dom.js * Update index.js * Delete loose-equal.js * Update observe-dom.js * Update observe-dom.js * Update observe-dom.js * Update observe-dom.js
1 parent 72ffba9 commit 88cfaef

File tree

1 file changed

+32
-3
lines changed

1 file changed

+32
-3
lines changed

lib/utils/observe-dom.js

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

2-
import { assign } from '../utils/object';
2+
import { assign } from './object';
3+
34
/**
45
* Observe a DOM element changes, falls back to eventListener mode
56
* @param {Element} el The DOM element to observe
@@ -14,14 +15,42 @@ export default function observeDOM(el, callback, opts) {
1415
if (MutationObserver) {
1516
// Define a new observer
1617
const obs = new MutationObserver(mutations => {
17-
if (mutations[0].addedNodes.length > 0 || mutations[0].removedNodes.length > 0) {
18+
let changed = false;
19+
// A Mutation can contain several changes, so we loop through them to see what has changed
20+
// We break out of the loop early if any "significant" change has been detected
21+
for (let i = 0; i < mutations.length && !changed; i++) {
22+
// The muttion record
23+
const mutation = mutations[i];
24+
// Mutation Type
25+
const type = mutation.type;
26+
// DOM Node
27+
const target = mutation.target;
28+
// Previous Value (only for characterData and attributes)
29+
const old = mutation.oldValue;
30+
if (type === 'characterData' && target.nodeType === Node.TEXT_NODE && old !== target.data) {
31+
// We ignore nodes that are not TEXt (i.e. comments, etc) as they don't change layout
32+
// Updating character data with the same value still triggers a mutation
33+
// So we compare the old value to the new value
34+
changed = true;
35+
} else if (type === 'attributes' && target.getAttribute(mutation.attributeName) !== old) {
36+
// Updating an attribute with the same value still triggers a mutation
37+
// So we compare the old value to the new value
38+
changed = true;
39+
} else if (type === 'childList' && (mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0)) {
40+
// This includes HTMLElement and Text Nodes being added/removed
41+
changed = true;
42+
}
43+
}
44+
if (changed) {
45+
// We only call the callback if a change that could affect layout/size truely happened.
1846
callback();
1947
}
2048
});
2149

22-
// Have the observer observe foo for changes in children
50+
// Have the observer observe foo for changes in children, etc
2351
obs.observe(el, assign({childList: true, subtree: true}, opts));
2452
} else if (eventListenerSupported) {
53+
// Legacy interface. most likely not used in modern browsers
2554
el.addEventListener('DOMNodeInserted', callback, false);
2655
el.addEventListener('DOMNodeRemoved', callback, false);
2756
}

0 commit comments

Comments
 (0)