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.
Related
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
I want to use MutationObserver to track DOM changes in a window I create with window.open. I have the following code:
var newWin = window.open('/somepath');
var observerConfig = {
childList: true,
subtree: true,
attributes: false,
characterData: false
};
var obs = new newWin.MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (!mutation.addedNodes) return;
mutation.addedNodes.forEach(function(addedNode) {
console.log(addedNode);
});
})
});
obs.observe(newWin.document, observerConfig);
I would expect to see some newly added nodes logged in the console (as I got when I tracked the original window the same way, same observer), but I get nothing. Am I missing something?
This is the same problem you would face when using JavaScript (from a script in <head> for instance) to modify the DOM of the current document, before the DOM has been loaded: you would be trying to access elements that do not exist in memory at this time.
You would use the DOMContentLoaded event to trigger a callback when the DOM has been loaded and is ready to manipulate.
Similarly, when you are trying to access the DOM of the new window, that window may not have finished loading yet.
You should wrap your obs.observe call in a load event listener:
newWin.addEventListener('load', function() {
obs.observe(newWin.document.body, observerConfig);
}, true);
This way when you begin observing the body you are sure that it actually exists!
Is there a way to fire a function when element loses some custom attribute? For example, when custom_attribute is removed, then show me some alert. What's the way to do it? Plain JS is preferable, although jQuery is also okay.
<div class="someclass" custom_attribute>...</div>
You can use MutationObserver:
// select the target node
var target = document.querySelector('.someclass');
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
fire_function();
console.log(mutation.type);
});
});
// configuration of the observer:
var config = { attributes: true };
// pass in the target node, as well as the observer options
observer.observe(target, config);
// later, you can stop observing
observer.disconnect();
This fires the fire_function() every time an attribute is changed. So you can check, if the particular attribute is missing or changed.
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
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();