Assuming I am unable to see below code, I have no idea how long does the timeout set, and I am unable to change the original code
document.querySelector('button').addEventListener('click', function(){
setTimeout(function(){
document.querySelector('.old').classList = 'old new';
}, 100);
});
<div class="old">OLD</div>
<button>Click</button>
What I'd like to achieve is that once the new class is added then I want to change the TEXT line, the hack code as below
document.querySelector('button').addEventListener('click', function(){
setTimeout(function(){
document.querySelector('.old').classList = 'old new';
}, 100);
});
document.querySelector('button').addEventListener('click', function(){
if(document.querySelectorAll('.new').length !== 0) {
document.querySelector('.old').innerText = "123"
}
});
<div class="old">OLD</div>
<button>Click</button>
document.querySelector('button').addEventListener('click', function(){
if(document.querySelectorAll('.new').length !== 0) {
document.querySelector('.old').innerText = "123"
}
});
Since I am unable to know how long the timeout secs, so my first click won't work as it executes right away. So I have to add the timeout seconds bigger than the original. Is there an efficient way to detected if new class is added?
or timeout is the best solution for this use case? Thanks
You might use Mutation Observer for this purpose:
document.querySelector('button').addEventListener('click', function() {
setTimeout(function() {
document.querySelector('.old').classList = 'old new';
}, 500);
});
document.querySelector('button').addEventListener('click', function() {
var observer = new MutationObserver(function(mutationsList, observer) {
for (var mutation of mutationsList) {
if (
mutation.type === 'attributes' &&
mutation.attributeName === 'class' &&
mutation.target.classList.contains('new')
) {
mutation.target.innerText = "123";
observer.disconnect();
}
}
});
observer.observe(document.querySelector('.old'), {attributes: !0});
});
<div class="old">OLD</div>
<button>Click</button>
Use ClassList API to get this done. As new class will be add after some time. If new class is not added to dom then you can't get reference of this node to compare. The ClassList provides a handy method to solve this issue. use contains method to check if new class added or not. If added then change the text.
use below code
document.querySelector('button').addEventListener('click', function(){
if(document.querySelectorAll('.old')[0].classList.contains("new")) {
document.querySelector('.old').innerText = "123"
}
});
Solution
Related
I got this Code:
const odleglosc = parseFloat(document.getElementsByClassName("dystans")[0].innerText);
const daleko = "za daleko";
if (odleglosc > 200) {
alert(daleko);
}
<span data-pafe-form-builder-live-preview="lechnarlok" class="dystans" id="dystans">500</span>
It runs fine, because at starting point there is number higher than 200 in it.
But when i change it, alert don't trigger again..
How can i solve that? :(
Im not sure about how the span value will change, so this example works with an input. The same idea could also be applied to a span tho.
<input onchange="theFunction()" data-pafe-form-builder-live-preview="lechnarlok" class="dystans" id="dystans" value="500"></input>
<script>
function theFunction() {
var odleglosc = parseFloat(document.getElementsByClassName("dystans")[0].value);
var daleko = "za daleko";
if (odleglosc > 200)
{
alert(daleko);
}
}
</script>
Here, onChange calls the function whenever the value in the input field changes.
Do You want to show alert after each change of the value? If yes, use event listener for input (not for span).
Update:
Use MutationObserver for this case.
let span = document.getElementById('dystans');
function updateValue(value) {
var daleko = "za daleko";
if (parseFloat(value) > 200)
{
alert(daleko);
}
}
// create a new instance of 'MutationObserver' named 'observer',
// passing it a callback function
observer = new MutationObserver(function(mutationsList, observer) {
let value = mutationsList.filter(x => x.target.id =='dystans')[0].target.innerHTML;
updateValue(value);
});
// call 'observe' on that MutationObserver instance,
// passing it the element to observe, and the options object
observer.observe(span, {characterData: true, childList: true, attributes: true});
span.innerHTML = '3000';
<span data-pafe-form-builder-live-preview="lechnarlok" class="dystans" id="dystans">500</span>
Source:
Detect changes in the DOM
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
So I am currently using the following code to execute my jQuery. However, as you can see I have set some timers on executing the second part of the code. What I would like is to see if #objectPrice exists, and then run the timed code but only once. This way I can replace the timers.
var checkExist = setInterval(function() {
if (jQuery('#objectPrice').length) {
var content = jQuery('#prisen').html();
objectPrice.value = content.replace(/\D/g,'');
}
}, 200); // check every 200ms
setTimeout(function() { jQuery("#downPayment").focus(); }, 2200);
setTimeout(function() { jQuery("#downPayment").blur(); }, 2205);
The right way to do it
You can do this by observing the direct parent of the element you want to check, let's assume that your element will be added to the page in the following div:
<div id="parent-div">
<div>child 1</div>
<div>child 2</div>
</div>
You will need to observe any new child added to the #parent-div and trigger a function when this happens:
const callback = function(mutationsList, observer) {
for(let mutation of mutationsList) {
if( mutation.addedNodes.length > 0){
for(let node of mutation.addedNodes) {
let jqueryNode = jQuery(node);
if(jqueryNode.is('#objectPrice')){
var content = jQuery('#prisen').html();
objectPrice.value = content.replace(/\D/g,'');
}
}
}
}
};
const observer = new MutationObserver(callback);
observer.observe(jQuery('#parent-div')[0], {childList: true});
But if you don't want to change your current code, you make it recursive and call it the first time, like the following:
var checkingFunction = function () {
if(jQuery('#objectPrice').length){
var content = jQuery('#prisen').html();
objectPrice.value = content.replace(/\D/g,'');
}else{
setTimeout(function() { checkingFunction() }, 200);
}
}
checkingFunction();
Is there a way to detect when the parent of an element changes (namely when changing from null to !null -- i.e., when the element is initially added to the DOM) using a MutationObserver? I can't find any documentation that shows how this could be achieved.
I am programmatically creating elements with document.createElement(). I return the created element from a function, but want to create a listener from within the function to react when the element is eventually added to the DOM, without knowing where or which parent it will be added to.
I'm not quite sure how else to phrase this, honestly.
const elem = document.createElement('div');
let added = false;
elem.addEventListener('added-to-dom', () => { added = true; });
// ^ how do I achieve this?
assert(added == false);
document.body.addChild(elem);
assert(added == true);
I don't see what's so hard about understanding this or why it was closed.
An easy but inelegant way is to monkeypatch Node.prototype.appendChild (and, if necessary, Element.prototype.append, Element.prototype.insertAdjacentElement, and Node.prototype.insertBefore) to watch for when an element is added to the DOM:
const elementsToWatch = new Set();
const { appendChild } = Node.prototype;
Node.prototype.appendChild = function(childToAppend) {
if (elementsToWatch.has(childToAppend)) {
console.log('Watched child appended!');
elementsToWatch.delete(childToAppend);
}
return appendChild.call(this, childToAppend);
};
button.addEventListener('click', () => {
console.log('Element created...');
const div = document.createElement('div');
elementsToWatch.add(div);
setTimeout(() => {
console.log('About to append element...');
container.appendChild(div);
}, 1000);
});
<button id="button">Append something after 1000ms</button>
<div id="container"></div>
Mutating built-in prototypes generally isn't a good idea, though.
Another option would be to use a MutationObserver for the whole document, but this may well result in lots of activated callbacks for a large page with frequent mutations, which may not be desirable:
const elementsToWatch = [];
new MutationObserver(() => {
// instead of the below, another option is to iterate over elements
// observed by the MutationObserver
// which could be more efficient, depending on how often
// other elements are added to the page
const root = document.documentElement; // returns the <html> element
const indexOfElementThatWasJustAdded = elementsToWatch.findIndex(
elm => root.contains(elm)
);
// instead of the above, could also use `elm.isConnected()` on newer browsers
// if an appended node, if it has a parent,
// will always be in the DOM,
// instead of `root.contains(elm)`, can use `elm.parentElement`
if (indexOfElementThatWasJustAdded === -1) {
return;
}
elementsToWatch.splice(indexOfElementThatWasJustAdded, 1);
console.log('Observed an appended element!');
}).observe(document.body, { childList: true, subtree: true });
button.addEventListener('click', () => {
console.log('Element created...');
const div = document.createElement('div');
div.textContent = 'foo';
elementsToWatch.push(div);
setTimeout(() => {
console.log('About to append element...');
container.appendChild(div);
}, 1000);
});
<button id="button">Append something after 1000ms</button>
<div id="container"></div>
You could listen for the DOMNodeInserted-event and compare the elements id.
Notice: This event is marked as Depricated and will probably stop working in modern modern browsers at some point in the near
future.
let container = document.getElementById('container');
let button = document.getElementById('button');
document.body.addEventListener('DOMNodeInserted', function(event) {
if (event.originalTarget.id == button.id) {
console.log('Parent changed to: ' + event.originalTarget.parentElement.id);
}
});
button.addEventListener('click', function(event) {
container.appendChild(button);
});
#container {
width: 140px;
height: 24px;
margin: 10px;
border: 2px dashed #c0a;
}
<div id="container"></div>
<button id="button">append to container</button>
By using the GeckoWebBrowser in C# is there anyway to know when a page has completed updating its content using XMLHttpRequest ? I thought that the DocumentCompleted event would have done it but since the page it's not reloading it wont fire up...
You could use a mutation observer watching document.body's subtree, and assume that the page has finished being modified (say) 20ms after the last notification you get.
In JavaScript, that would look something like this:
(function() {
var observer;
// The click handler that appends content after a random delay
document.querySelector('input').addEventListener("click", function() {
if (!observer) {
hookupObserver();
}
setTimeout(function() {
var p = document.createElement('p');
p.innerHTML = "New content added at " + Date.now();
document.querySelector('div').appendChild(p);
}, 500 + Math.round(Math.random() * 500));
}, false);
// Watching for subtree mods to `document.body`:
function hookupObserver() {
var timer = 0;
observer = new MutationObserver(function() {
clearTimeout(timer);
timer = setTimeout(done, 40);
});
observer.observe(document.body, {childList: true, subtree: true});
}
function done() {
timer = 0;
alert("Modification complete");
}
})();
<input type="button" value="Click to simulate async modification">
<div>This is the page</div>
I want to execute some code if this element exists <div id="element">Some text</div> using jquery.
my code until now:
setInterval(function(){check()}, 100);
function check() {
var count = document.getElementById("count");
if(document.getElementById("element") && count.value != 1) {
//some code
count.value = 1;
}
}
It works, but I think this is a very bad way to reach my target.
I want an easier solution, but I didn't find.
Your way is the most reliable, because it cannot fail.
However, you may wish to try listening for change events on the count element, and reset the value if your element exists. This will mean your verification code only runs when a change is made to the value.
do you want to do this initially?
hjow about you do this?
$(document).ready(function(){
if($(#element)) { do something };
});
EDIT:
after 10 seconds of search:
$("#someDiv").bind("DOMSubtreeModified", function() {
alert("tree changed");
});
You can listen DOM events (when an element is inserted or modified) and check your condition only at this time, not every time interval.
If you need some information about DOM events you can take a look at : http://en.wikipedia.org/wiki/DOM_events#HTML_events (mutation events)
One solution I can think of is about using MutationObserver with a fallback mechanism like
jQuery(function() {
if (window.MutationObserver) {
var target = document.querySelector('#myparent');
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
[].forEach.call(mutation.addedNodes, function(el, i) {
if (el.id == 'element') {
check();
//if you don't want to listen any more remove the listener
//observer.disconnect();
}
})
});
});
// configuration of the observer:
var config = {
childList: true
};
// pass in the target node, as well as the observer options
observer.observe(target, config);
} else {
setInterval(function() {
if (document.getElementById("element")) {
check();
}
}, 100);
}
function check() {
var count = document.getElementById("count");
if (count.value != 1) {
//some code
count.value = 1;
}
}
});
$('button').click(function() {
$('#myparent').append('<div id="element">Some text</div>');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button>Add</button>
<input id="count" />
<div id="myparent"></div>
Note: The solution assumes you have a static parent element for the dynamic element(like the myparent element in the above example)