I’m trying to have a MutationObserver watch for changes to a page title and immediately reset the title back to the original text. This partially works, but the first time the page title is changed, my callback keeps firing and the page grinds to a halt. I’ve tried disconnecting the observer in my callback, and that stops it from looping, but I actually need it to keep observing, so it isn’t a solution.
What am I doing wrong?
function resetTitle(title) {
document.title = title[0].oldValue;
console.info("Reset the page title.");
}
let observer = new MutationObserver(resetTitle);
observer.observe(document.querySelector('title'), {
childList: true,
subtree: true,
characterDataOldValue: true
});
4
Answers
First, when the
document.title
is set, the string replace all algorithm is used, which will replace all the previous content of the<title>
element with a newTextNode
.Doing so, there is no
CharacterData
mutation occurring, only achildList
one, which will not fill thepreviousValue
field.You could have used that if the title was set by modifying the existing
TextNode
directly:So what you need is actually to handle both the possible
CharacterData
mutation, and thechildList
one, by looking at theremovedNodes[0].data
to get the old value.But if you’re going to modify the title again in your handler, you will trigger once more the observer’s callback, with this time, the new title being set as the old one.
So instead, the best is to store the original value that you want to keep from outside of the observer’s callback, and to check in the callback if the title needs an update or not:
You need to detach the observer, undo the title value programmatically & controlled, and only then you can reattach the same function with observer options.
This is how you want to do that (updated based on Kaiido’s correction below).
You have created a feedback loop. A simple way to avoid the feedback loop, without having to micromanage the subscription, is to simply compare the change to the current value.
You might also want to cache your original title
As another approach, just ignore the event contents and check the title against the cached. This will also avoid the feedback.