MutationObserver is not triggered when innerText changes - javascript

I am running a Javascript file on this url. I am interested in changes in the red outlined elements:
I wrote the following script
const $xpath = xp => {
const snapshot = document.evaluate(
xp, document, null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null
);
return [...Array(snapshot.snapshotLength)]
.map((_, i) => snapshot.snapshotItem(i));
};
const xpathOdds = './/div[#col-id="bestOdds"]/descendant::div[#class="d-flex justify-content-between align-items-center"]';
var odds = $xpath(xpathOdds);
var config = {characterData: true,
attributes: true,
childList: true,
subtree: true
};
odds.forEach(function(target, idx) {
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation);
});
});
observer.observe(target, config);
})
I am not sure why the MutationObserver is not triggered.
It is triggered if I edit an element using rightmouse click - "Inspect".
However, it is not triggered if the website itself makes changes to the elements in question.
When an element changes it becomes yellow, so I know there should have been mutations
What am I doing wrong?

I checked the link you posted, and I think the problem is you are attaching the observers to the wrong objects. The thing is, when there is an update and the color of the cell becomes yellow, the whole table get replaced and not just the cells. So the cells you were observing are no longer there to be observed. You should attach the observer to a higher element in the hierarchy that does not get replaced, like that one with the class ag-center-cols-viewport or the document itself.

It probably has to do with the config for mutation observer.
var config = {
attributes: true,
childList: true,
subtree: true, // Because you're watching for changes made to one of the children element.
characterData: true // The changes you're looking for are in the content and not at element level.
});

The changes you expect triggering the observer are related to the element's style. You have to set the the observer to monitor changes to the element's attributes, including all its style attributes.
attributeFilter: ['style']
var config = {
attributes: true,
attributeFilter: ['style'],
childList: true,
subtree: true
};

Maybe its caused because site rendered using Next.js and Virtulal DOM. And mutationObserver doesnt react with changes on virtual dom.
And to check changes that make the site itself you can use some other way. For example with setInterval.
Something like this problem I viewed recently here https://copyprogramming.com/howto/why-isn-t-the-mutationobserver-working

Related

How to detect whether an dom element has loaded on the page

I have a single page application where a div with a class "abc" is getting loaded dynamically. I want to run a script only after that particular element and all its children have been loaded in the DOM. I don't want to use a timer which calls the function again and again. How do I go about this. This is probably related to mutation observer but I am not understanding how to use that.
Example with mutation observer
var target = document.querySelector('.class');
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation.type);
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true }
// pass in the target node, as well as the observer options
observer.observe(target, config);
So for each mutation of the target element
this code console.log(mutation.type);
will be execute
$(document).on('DOMNodeInserted', '.abc', function() {
});
This will wait until the DOM element is ready and then run your code.

Using client javascript to monitor new elements added to document

i was using Object.observe() a few months ago to monitor any recursive changes from window.document. Now O.o() is withdrawn from em6+, i need to customize this behavior. I need access to new elements created anywhere in the document.
I've tried These Projects (works, but without child recursion):
https://github.com/MaxArt2501/object-observe
https://github.com/jdarling/Object.observe
https://github.com/jdarling/Object.observe
I read from the Mozilla MDN to use proxy https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy I'm not sure which trap to use, or how to make this recursive.
Here is the exact code i've been using with O.o() :
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
console.log("Observed Mutation:");
//mutation.target
//mutation.type
//mutation.oldValue
//mutation.attributeName
//mutation.attributeNamespace
//mutation.removedNodes
//mutation.addedNodes
});
});
//mutation observer configuration
var config = {
childList: true,
attributes: true,
characterData: true,
subtree: true,
attributeOldValue: true,
characterDataOldValue: true
attributeFilter: false
};
// pass in the target node and options to mutation observer
observer.observe(document, config);
What is the minimal amount of code that will give me access to newly created objects with or without using a polyfill?
Found the answer through irc.freenode.net ##javascript from: jaawerth
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

detect div change in javascript

I'm working on a small chrome extension for fun, and one thing I need it to be able to do, is to detect when the text inside a div is changed by the webpage itself.The code I'm using is:
var status = document.getElementById("status").innerHTML;
status.onchange = function() {
console.log("CHANGE DETECTED")
And this doesn't seem to work, so what should I use instead?
NOTE: I'd prefer not to use jquery, as I am not even very proficient with javascript at the moment, but if it would be that much simpler/easier, that would be fine.
use this trick
source:https://hacks.mozilla.org/2012/05/dom-mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/
// select the target node
var target = document.querySelector('#some-id');
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation.type);
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true }
// pass in the target node, as well as the observer options
observer.observe(target, config);
// later, you can stop observing
observer.disconnect();
You can't do what you want using change event. On newer browsers, you can use Mutation Observers. On older browsers... well, you ask people to upgrade to newer browsers. :P

Detect with Javascript when a elelment has recieved content

When is clicked, div with id button makes a AJAX request and adds new content inside div with id newContent.
I am trying to launch a function, after the the div button get's clicks and the div with id newContent receives the content.
<div id="button"> </div>
<div id="newContent"></div>
Unfortunatelly I can't make changes to the .js file, that contains the AJAX function.
I didn't succed with:
var contentdiv = document.getElementById('newContent');
window.onload = function() {
contentdiv.onreadystatechange = function () {
if (contentdiv.readyState == "interactive") {
myFunction();
}
}
}
What could I do, to launch my function after the content has successfully added to the newContent div?
For modern browsers I would recommend mutation observers:
var observer = new MutationObserver( myFunction );
// configuration of the observer:
var config = { attributes: false, childList: true, characterData: true, subtree: true };
// pass in the target node, as well as the observer options
observer.observe(contentDiv, config);
This adds a mutation observer to your element. You can configure the options to which the observer needs to listen. Jquery doesn't support this natively (yet). This will fire when there is content added to the contentDiv. Or changes to the child elements in the contentDiv.
childList Set to true if additions and removals of the target node's child elements (including text nodes) are to be observed.
attributes Set to true if mutations to target's attributes are to be observed.
characterData Set to true if mutations to target's data are to be observed.
subtree Set to true if mutations to not just target, but also target's descendants are to be observed.
attributeOldValue Set to true if attributes is set to true and target's attribute value before the mutation needs to be recorded.
characterDataOldValue Set to true if characterData is set to true and target's data before the mutation needs to be recorded.
attributeFilter Set to an array of attribute local names (without namespace) if not all attribute mutations need to be observed.
Source: MDN
Which browsers support this: CanIuse
Read more here: MDN
MutationObserver is a powerful tool. It also provides information about the changes in the element. I suggest to read up with the possibilities. For now it will do the thing you want.
As a fall back for IE9 and 10 you can use:
contentDiv.addEventListener ('DOMNodeInserted', myFunction, false);
This, however, will not host the same functionality as the mutation observer and its use is discouraged by MDN.
Another way, you can use the setInterval function and checked every X millisecond your content div.
var oldString = document.getElementById("DivId").innerHTML;
var checkContentDiv = setInterval(function() {
if(document.getElementById("DivId").innerHTML != oldString) {
//your div is updated.
clearInterval(checkContentDiv);
}
}, 500);

Timeago plugin to always be on()

How would I change the following code (which makes the timeago plugin work) to use the on() function (or others) so that it can be used live? I can't quite seem to figure it out (I'm fairly new to JQuery).
jQuery(document).ready(function() {
jQuery("a.timeago").timeago();
});
How would this be done?
You can use MutationObserver to check when the DOM was modified: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
You pick a node to observe. For your project you should observe the container the a.timeago elements will be created into. <body> is fine but will incur more work for the browser. Then, whenever the dom changes, a callback will be fired. Catch the elements you care about.
Modified from the documentation:
// select the target node
var target = document.querySelector('#your-container');
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
mutation.addedNodes.forEach(function(addedNode) {
// if the addedNode matches $('a.timeago')
// $(addedNode).timeago();
});
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };
// pass in the target node, as well as the observer options
observer.observe(target, config);
// later, you can stop observing
observer.disconnect();

Categories