I'm adding a new element dynamically via JQuery, with code like the below:
$('#example').after("<p class='xx'></p>")
Upon this code being called and a "xx" element being added, I'd like to run some other code. How can I 'listen' and pick up when this event happens?
Thanks
You can use Mutation Observer for this.
The demo below is a simple quick adaptation of the example in reference.
$(document).ready(function(){
var targetNode = document.getElementById('some-id');
var config = { attributes: true, childList: true, subtree: true };
var callback = function(mutationsList, observer) {
for(var mutation of mutationsList) {
if (mutation.type == 'childList') {
console.log('A child node has been added or removed.');
}
}
};
var observer = new MutationObserver(callback);
observer.observe(targetNode, config);
$('#example').after("<p class='xx'>I am a paragraph inserted by a script.</p>");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="some-id">
<p id="example">I'm a static paragraph.</p>
</div>
Related
I have two scripts. One asks my backend about new data in database and if there is something new, add this to div with id 'box'. In second script I want to monitorize this and if something is changed in this div, I want to call my function. How to do that?
$(document).ready(function(){
refreshTable();
});
function refreshTable(){ //loading data to div
$('#messbox').load('getData.php', function(){ setTimeout(refreshTable, 1000); });
}
function scroll(){ //function to call
$("#messbox").scrollTop($("#messbox")[0].scrollHeight);
}
You can use a MutationObserver to listen for changes in the element's childList:
const targetNode = document.getElementById('target');
const callback = function(mutationsList, observer) {
for(const mutation of mutationsList) {
if (mutation.type === 'childList') {
myFunction()
}
}
};
const observer = new MutationObserver(callback);
observer.observe(targetNode, {childList: true});
function myFunction(){
console.log("Change!")
}
<div id="target"></div>
<button onclick="target.innerHTML += '<p>Hello World!</p>'">Add something to #target</button>
I have a puppeteer project in which I'm waiting for some form of information on an Element. For example, in the header, I'm waiting for some new child Nodes.
<div id="outside">
</div>
and then after some time
<div id="outside">
<div id='inside'>
</div>
</div>
is there a way for me to add an event listener to check when the HTML has been changed?
something like
page.addListener('#outside', () => {
console.log('event fired');
}
You can try with MutationObserver
// Options for the observer (which mutations to observe)
const config = { attributes: true, childList: true, subtree: true };
// Callback function to execute when mutations are observed
const callback = function(mutationsList, observer) {
for(let mutation of mutationsList) {
if (mutation.type === 'childList') {
console.log('A child node has been added or removed.');
}
else if (mutation.type === 'attributes') {
console.log('The ' + mutation.attributeName + ' attribute was modified.');
}
}
};
// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);
const targetNode = document.querySelector('#outside');
// Start observing the target node for configured mutations
observer.observe(targetNode, config);
targetNode.insertAdjacentHTML('beforeend', "<div id='inside'>Child</div>"); // Add child
targetNode.classList.add('.child'); // Modify attribute
document.querySelector('#inside').style.marginLeft = '15px';
<div id="outside">Parent
</div>
I want to remove a div when the style changes. I have read that MutationObserver can do this. But the code that I tried is not working.
const observer = new MutationObserver(function
(mutations) {
mutations.forEach(function (mutation) {
if (mutation.attributes === 'style') {
removeDiv()
}
})
})
const elem = document.querySelector('.show-pl');
observer.observe(elem, {
attributes: true
})
function removeDiv() {
Object.assign(elem.style, {
display: 'none',
})
}
The addition of a new element has nothing to do with attributes, and you can't observe mutations on an element that isn't in the DOM yet.
Instead, you look for childList modifications on the parent element the div will be added within (or childList + subtree on an ancestor, if you can't watch the parent directly —if necessary, the ancestor can even be document.body).
Here's an example watching the parent directly:
// Set up the observer on the container
let observer = new MutationObserver(function() {
// Does the div exist now?
const div = document.querySelector(".show-pl");
if (div) {
// Yes, "remove" it (you're really just hiding it) and release this observer
console.log("The div has appeared, hiding and releasing observer");
div.style.display = "none";
observer.disconnect();
observer = null;
}
});
observer.observe(document.getElementById("the-parent"), {
childList: true
});
console.log("Watching for the element");
// On a delay, create the div
setTimeout(() => {
console.log("Creating the div");
const div = document.createElement("div");
div.textContent = "Hi there!";
div.className = "show-pl";
document.getElementById("the-parent").appendChild(div);
}, 800);
<div id="the-parent"></div>
To watch an ancestor instead you'd use the ancestor in the observe call and add subtree: true to the init options.
function removeDiv(canvas) {
var elem = document.querySelector('.show-pl');
elem.parentNode.removeChild(elem);
}
var observer = new MutationObserver(function (mutations, me) {
var canvas = document.querySelector(".show-pl");
if (canvas) {
removeDiv(canvas);
me.disconnect();
return;
}
});
observer.observe(document, {
childList: true,
subtree: true
});
This does what I want, but an error occurs "cannot read property 'addeventlistener' of null", because the div doesn't exists in the DOM yet.
Hi,
I need to execute a javascript function once as soon as an element with a given class appears on the code (the element will be generated by another script).
This is my function:
play(sound);
the element would appear inside this:
<div id="canvas">
The element would look like this:
<span class="sound">sound name</span>
where "sound name" will determine the argument for play();
how can this be done with javascript?
Thank you.
You can use a You could use a MutationObserver as shown below.
The second argument to .observe(), MutationObserverInit, is important:
In the options, use childList: true if the span will only be added as a direct child. subTree: true if it can be at any level down below #canvas.
From the docs:
childList: Set to true if additions and removals of the target node's child elements (including text nodes) are to be observed.
subtree: Set to true if mutations to target and target's descendants are to be observed.
$("#go").click(function () {
$("#canvas").append($('<span class="sound">sound name</span>'));
});
function play(n) { alert('playing '+ n); }
var obs = new MutationObserver(function(mutations, observer) {
$.each(mutations, function (i, mutation) {
var addedNodes = $(mutation.addedNodes);
var selector = "span.sound"
var spanSounds = addedNodes.find(selector).addBack(selector); // finds either added alone or as tree
spanSounds.each(function () { // handles any number of added spans
play($(this).text());
});
});
});
obs.observe($("#canvas")[0], {childList: true, subtree: true});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="canvas"></div>
<button id="go">Add span to canvas</button>
Using plain JavaScript
The code is a little less compact, but it is definitely doable:
document.getElementById("go").addEventListener('click', function () {
var s = document.createElement('span');
s.innerText = 'sound name';
s.classList.add('sound')
document.getElementById('canvas').appendChild(s);
});
function play(n) { alert('playing '+ n); }
var obs = new MutationObserver(function(mutations, observer) {
for(var i=0; i<mutations.length; ++i) {
for(var j=0; j<mutations[i].addedNodes.length; ++j) {
var addedNode = mutations[i].addedNodes[j];
//NOTE: if the element was added as child of another element, you would have to traverse
// the addedNode to find it. I recommend the jQuery solution above if that's the case
if(addedNode.tagName == "SPAN" && addedNode.classList.contains("sound")) {
play(addedNode.innerText);
}
}
}
});
obs.observe(document.getElementById('canvas'), {childList: true, subtree: true});
<div id="canvas"></div>
<button id="go">Add span to canvas</button>
You could probably try onload event
You need a listener to detect the DOM change, MutationObserver
// Select the node that will be observed for mutations
var targetNode = document.getElementById('some-id');
// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true };
// Callback function to execute when mutations are observed
var callback = function(mutationsList) {
for(var mutation of mutationsList) {
if (mutation.type == 'childList') {
console.log('A child node has been added or removed.');
}
else if (mutation.type == 'attributes') {
console.log('The ' + mutation.attributeName + ' attribute was modified.');
}
}
};
// Create an observer instance linked to the callback function
var observer = new MutationObserver(callback);
// Start observing the target node for configured mutations
observer.observe(targetNode, config);
// Later, you can stop observing
observer.disconnect();
I'm adding some element to DOM after drag event. I need to detect this element and the moment when this element was added. I use Mutation Observer but something is wrong, the code:
var targetNodes = $('.mvly');
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
var myObserver = new MutationObserver (mutationHandler);
var obsConfig = { childList: true, characterData: true, attributes: true, subtree: true };
targetNodes.each(function(){
myObserver.observe(this, obsConfig);
} );
function mutationHandler (mutationRecords) {
mutationRecords.forEach ( function (mutation) {
if (typeof mutation.addedNodes == "object") {
console.log('test');
}
});
}
Can anybody help, much thx.
Here's a simple example of how you can use a MutationObserver to listen for when an element is added to the DOM.
For brevity, I'm using jQuery syntax to build the node and insert it into the DOM.
var myElement = $("<div>hello world</div>")[0];
var observer = new MutationObserver(function(mutations) {
if (document.contains(myElement)) {
console.log("It's in the DOM!");
observer.disconnect();
}
});
observer.observe(document, {attributes: false, childList: true, characterData: false, subtree:true});
$("body").append(myElement); // console.log: It's in the DOM!
You don't need to iterate over each MutationRecord stored in mutations because you can perform the document.contains check directly upon myElement.