I have a dynamic DOM structure where nodes get inserted and deleted all the time, in order to react to new nodes I'm using a MutationObserver that gets activated when the user clicks on a Button. The MutationObserver will run two functions everytime the user clicks on that button and the functions will keep running when the DOM structure I'm observing change.
What I'm trying to do is to disconnnect the MutationObservers as soon as the user clicks the button again (Let's say click first time then sort elements, click again and stop sorting elements). I'm passing a boolean (goSortDom) everytime the user clicks the button (if true go do stuff and observe, if false stop observing). The thing is when I try to disconnect the observers when goSortDom=false they will never get disconnected and the functions will keep running.
I'm pretty new to mutationObservers so I don't know if my approach is a bad practice that's why I will really appreciate commnents on that too.
$(document).ready(function () {
// Function 1: Assign Priorities
function assignChatPriority(arrayParent) {
//Assign Priorities
//Observe if time change, if change re-assign priority to dom node
timeInQueueDomObserver.observe(
$(incomingChat).find(".time_cell")[0],
configtimeInQueue
}
// Function 2: Reorder DOM
function orderIncomingChats() {
//Reorder DOM save DOM elements to Array
//Replace original DOM with new sorted DOM
}
//Declaring DOM Observers for Time in Queue and DOM container dynamics
var incomingChatsDomObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.addedNodes.length) {
for (let i = 0; i < mutation.addedNodes.length; i++) {
if (
mutation.addedNodes[i].attributes["data-priority"] === undefined
) {
runExtensionFunctions();
}
}
}
});
});
var timeInQueueDomObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (
mutation.addedNodes.length === 1 &&
mutation.addedNodes[0].nodeType === Node.TEXT_NODE &&
mutation.removedNodes.length === 1 &&
mutation.removedNodes[0].nodeType === Node.TEXT_NODE
) {
runExtensionFunctions();
}
});
});
//Obervers Configuration
let configChatsContainer = {
childList: true,
};
let configtimeInQueue = {
childList: true,
};
if (goSortDom) {
//boolean is true go ahead run functions and observe
assignChatPriority(incomingChatsRows);
orderIncomingChats();
incomingChatsDomObserver.observe(
incomingChatsContainer[0],
configChatsContainer
);
} else {
//disconnect observers: WON'T WORK
incomingChatsDomObserver.disconnect();
timeInQueueDomObserver.disconnect();
}
}
You initialize and work on the MutationObserver's incomingChatsDomObserver
and timeInQueueDomObserver
within this function passed to .ready(). I don't see an outside reference. If that is the case, the if (goSortDom)
will only be evaluated once for the initialized MutationObserver's. After that, the function ends and the references are lost. Calling the function again creates new MutationObserver's and the disconnect() calls will reference those new MutationObserver's instead of the already observing old ones!
Could it be that what you want to achieve is to move the initialization and reference of the MutationObserver's outside of this function and use it there? Or maybe disconnect the MutationObservers within theirselfs?
Let me give this a try. Since this is no full code, I cannot test it myself:
// ANSWERER: Now the references are outside the ready function. If the ready function is done, this references still exist.
//Declaring DOM Observers for Time in Queue and DOM container dynamics
var incomingChatsDomObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.addedNodes.length) {
for (let i = 0; i < mutation.addedNodes.length; i++) {
if (
mutation.addedNodes[i].attributes["data-priority"] === undefined
) {
runExtensionFunctions();
}
}
}
});
});
var timeInQueueDomObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (
mutation.addedNodes.length === 1 &&
mutation.addedNodes[0].nodeType === Node.TEXT_NODE &&
mutation.removedNodes.length === 1 &&
mutation.removedNodes[0].nodeType === Node.TEXT_NODE
) {
runExtensionFunctions();
}
});
});
// ANSWERER: This is now possible
function disconnectObservers() {
incomingChatsDomObserver.disconnect();
timeInQueueDomObserver.disconnect();
}
$(document).ready(function () {
// Function 1: Assign Priorities
function assignChatPriority(arrayParent) {
//Assign Priorities
//Observe if time change, if change re-assign priority to dom node
timeInQueueDomObserver.observe(
$(incomingChat).find(".time_cell")[0],
configtimeInQueue
}
// Function 2: Reorder DOM
function orderIncomingChats() {
//Reorder DOM save DOM elements to Array
//Replace original DOM with new sorted DOM
}
//Obervers Configuration
let configChatsContainer = {
childList: true,
};
let configtimeInQueue = {
childList: true,
};
if (goSortDom) {
//boolean is true go ahead run functions and observe
assignChatPriority(incomingChatsRows);
orderIncomingChats();
incomingChatsDomObserver.observe(
incomingChatsContainer[0],
configChatsContainer
);
} else {
//disconnect observers: WON'T WORK
incomingChatsDomObserver.disconnect();
timeInQueueDomObserver.disconnect();
}
}
$(document).ready(function () {
// Function 1: Assign Priorities
function assignChatPriority(arrayParent) {
//Assign Priorities
//Observe if time change, if change re-assign priority to dom node
timeInQueueDomObserver.observe(
$(incomingChat).find(".time_cell")[0],
configtimeInQueue
}
// Function 2: Reorder DOM
function orderIncomingChats() {
//Reorder DOM save DOM elements to Array
//Replace original DOM with new sorted DOM
}
//Declaring DOM Observers for Time in Queue and DOM container dynamics
var incomingChatsDomObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.addedNodes.length) {
for (let i = 0; i < mutation.addedNodes.length; i++) {
if (
mutation.addedNodes[i].attributes["data-priority"] === undefined
) {
runExtensionFunctions();
}
}
}
});
// ANSWERER: Now the observer disconnects itself after the run. Remember: MutationObserver's disconnect itself from *everywhere*
incomingChatsDomObserver.disconnect();
});
var timeInQueueDomObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (
mutation.addedNodes.length === 1 &&
mutation.addedNodes[0].nodeType === Node.TEXT_NODE &&
mutation.removedNodes.length === 1 &&
mutation.removedNodes[0].nodeType === Node.TEXT_NODE
) {
runExtensionFunctions();
}
});
// ANSWERER: Now the observer disconnects itself after the run. Remember: MutationObserver's disconnect itself from *everywhere*
timeInQueueDomObserver.disconnect();
});
//Obervers Configuration
let configChatsContainer = {
childList: true,
};
let configtimeInQueue = {
childList: true,
};
if (goSortDom) {
//boolean is true go ahead run functions and observe
assignChatPriority(incomingChatsRows);
orderIncomingChats();
incomingChatsDomObserver.observe(
incomingChatsContainer[0],
configChatsContainer
);
} else {
//disconnect observers: WON'T WORK
incomingChatsDomObserver.disconnect();
timeInQueueDomObserver.disconnect();
}
}
Alternatively, look at following. The MutationObserver's are bound to the button object, so clicking the button always references the once initialized MutationObserver's. That way they can be disconnected and reconnected (Try changing div#changes in a browser):
<html>
<body>
<button id="somebutton">bla</button>
<div id="changes"></div>
<script>
document.querySelector("#somebutton").addEventListener("click", function () {
if (!this.incomingChatsDomObserver) {
this.incomingChatsDomObserver = new MutationObserver(function (mutations) {
console.log("incomingChatsDomObserver", mutations);
});
}
if (!this.timeInQueueDomObserver) {
this.timeInQueueDomObserver = new MutationObserver(function (mutations) {
console.log("timeInQueueDomObserver", mutations);
});
}
if (this.observing) {
this.observing = false;
this.incomingChatsDomObserver.disconnect();
this.timeInQueueDomObserver.disconnect();
this.innerText = "inactive";
} else {
this.observing = true;
const changingDiv = document.querySelector("#changes");
this.incomingChatsDomObserver.observe(changingDiv, { attributes: true });
this.timeInQueueDomObserver.observe(changingDiv, { attributes: true });
this.innerText = "active";
}
});
</script>
</body>
</html>