I have a MutationObserver
binded to a #foo
html element.
var target = document.querySelector("#foo");
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
// ...
});
});
When user clicks #button
element, the #foo
is removed and appears again after a second.
<div id="button">Click me to remove the Foo!</div>
<div id="foo">Hello, I'm Foo!</div>
And as I noticed, after the #foo
was removed and recreated, the observer stopped working.
And the third quesion:
and appears again after a second
The behavior will depend entirely on what you mean by that.
If you mean a new element with the same id
is created, then yes, this is expected behavior: When you call observer.observe
on an element, you're calling it on that specific element, not any element matching its ID. If you remove that element from the DOM and replace it with another, different element that looks the same, the observer is not magically hooked up to that new, different element:
var target = document.querySelector("#foo");
var observer = new MutationObserver(function(mutations) {
console.log("#foo was modified");
});
observer.observe(target, {subTree: true, childList: true});
var counter = 0;
tick();
setTimeout(function() {
console.log("Replacing foo with a new one");
target.parentNode.removeChild(target);
target = document.createElement("div");
target.id = "foo";
target.innerHTML = "This is the new foo";
document.body.insertBefore(target, document.body.firstChild);
}, 1000);
function tick() {
target.appendChild(document.createTextNode("."));
if (++counter < 20) {
setTimeout(tick, 200);
}
}
<div id="foo">This is the original foo</div>
If you mean you're putting the same element back in the DOM, then no, that wouldn't be expected behavior, and not what happens in this example:
var target = document.querySelector("#foo");
var observer = new MutationObserver(function(mutations) {
console.log("#foo was modified");
});
observer.observe(target, {subTree: true, childList: true});
var counter = 0;
tick();
setTimeout(function() {
console.log("Removing foo for a moment");
target.parentNode.removeChild(target);
setTimeout(function() {
console.log("Putting the same foo back in");
document.body.insertBefore(target, document.body.firstChild);
}, 100);
}, 1000);
function tick() {
target.appendChild(document.createTextNode("."));
if (++counter < 20) {
setTimeout(tick, 200);
}
}
<div id="foo">This is the original foo</div>
The key take-away message here is that the observer is observing the one specific element you pass into observe
.
These questions only apply if you're removing the old element and replacing it with a whole new one:
So, I need to launch the observer again?
If you're removing the original element and putting a new one in its place, you should tell the observer to stop observing:
observer.disconnect();
Once you have a new element, you can connect the observer to it:
observer.observe(theNewElement, /*...options go here...*/);
Is the first observer is totally removed? Or, instead of that, it is still running, with just "doing nothing"?
In theory, since the spec makes it clear that it's the element that has a reference to its observers, then if you release your only reference to the element, in theory the observer gets disconnected because the element and its list of observers gets cleaned up. However, it's unclear how the observer's disconnect
method can be implemented without the observer having a reference back to the element, so they may have mutual references. If you keep your reference to the observer, that would keep the mutual references in memory. I'd disconnect it on purpose, to be sure.
I'm asking about it, because I don't want the multiple observers run, if only one of them doing the real work.
Observers don't "run," they react. The observer will continue observing the original element until/unless you disconnect it. If you're not doing anything to the original element, the observer isn't doing anything other than taking up memory. But again, if you're going to remove the element, you should disconnect the observer.