Detect change in document title via Javascript [duplicate] - javascript

This question already has answers here:
How to listen for changes to the title element?
(6 answers)
Closed 3 years ago.
Is there any way to detect a change to document.title / head > title via Javascript? I want to detect this via a Google Chrome extension content script, so I can't really wire up code in the target page's JS where the actual title change is performed.
I've found WebKitMutationObserver which theoretically should be able to detect a change to head > title, but it doesn't work for all cases:
// set up an observer for the title element
var target = document.querySelector('title');
var observer = new WebKitMutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation);
});
});
var config = { attributes: true, childList: true, characterData: true };
observer.observe(target, config);
// this jQuery statement fires the observer as expected ...
$('head > title').text('foo');
// ... but this doesn't:
document.querySelector('title').innerText = 'cheezburger';
// ... and neither does this:
document.title = 'lorem ipsum';
Any ideas?

I have found a fully working solution which is only a small modification to the example I posted in the original post.
// set up an observer for the title element
var target = document.querySelector('head > title');
var observer = new window.WebKitMutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log('new title:', mutation.target.textContent);
});
});
observer.observe(target, { subtree: true, characterData: true, childList: true });
// all three of these methods correctly fire the mutation observer
setTimeout(function() { document.title = 'foo'; }, 1000); // the usual method
setTimeout(function() { document.querySelector('head > title').innerText = 'bar'; }, 2000); // DOM method
setTimeout(function() { $('head > title').text('cheezburger'); }, 3000); // jQuery-only method
The addition of subtree: true was all that was needed to get this working right.
The wrapping of the three title-changing methods in setTimeout calls at the end is just for demonstration purposes; without this the title value changes so quickly that the WebKitMutationObserver doesn't report each change individually, since MutationObserver is designed to accumulate changes over a short period before executing the observer callback.
If one does not need to detect title changes made via the last jQuery-only method, the childList: true property can be omitted from the observer.observe line; only characterData: true is needed to detect the first two title-changing methods.

You have both JQuery and Javascript in your code example. Not sure if your only restricted to JavaScript, but here's how you can do it with jQuery
If you want to trigger the change, take a look at: http://api.jquery.com/trigger/
jQuery
$(document).ready(function () {
$("title", "head").change(function () {
console.log("Title has changed");
});
//Trigger Change
$("title","head").text("New Title").trigger("change");
});

Related

Mutation isn't observing and logging to console

I have the following script that runs on page load. It's meant to observe every td element on the page and check if it changes.
I was just logging the mutation to console to see my next steps, as I want to see what values change in each td element (the div refreshes every 15 seconds that houses the table).
Here's what I've got so far:
jQuery(document).ready(function( $ ) {
/** Change URL */
setInterval(function() {
$.ajax({
url: 'http://localhost:8888/profitmanager/wp-content/plugins/football-stats/update.php'
}).done(function(){
$('.fbs_results').load(
location.href+" .fbs_results>*", function(){
var hidden = [];
$.each(JSON.parse(localStorage.getItem("table_state")), function(index, value) {
if(value == 'hidden'){
$('tr[data-index="'+index+'"]').hide();
}
});
// console.log(hidden);
$('tr').each(function(index){
});
}
);
});
}, 15000);
const config = {
characterData: true,
characterDataOldValue: true,
childList: true,
subtree: true
};
function tdChanges(mutations) {
mutations.forEach((mutation) => {
console.log(mutation);
// if (mutation.addedNodes.value) {
// console.log();
// }
});
}
const tds = document.querySelectorAll('td');
Array.from(tds).forEach(function(td) {
const observer = new MutationObserver(tdChanges);
observer.observe(td, config);
});
});
But it doesn't work, nothing logs. Weird.
Can anyone fix my code?
TIA
querySelector() returns only a single Element. To look at all of them you need to use querySelectorAll() then loop over the result:
const tds = document.querySelectorAll('td');
Array.from(tds).forEach(function(td) {
const observer = new MutationObserver(tdChanges);
observer.observe(td, config);
});
Here's a working example in a jsFiddle, as the SO snippet editor is sandboxed and has issues running MutationObservers.
One thing to note here is that MutationObservers are not fast, and if you have a lot of td elements in your page you may see a performance hit. You may be better served by placing a single MutationObserver on the parent table and letting the event bubble up, like this.

target specific element with mutationObserver

i am using mutationObserver to detect changes using bellow code
var target = document.querySelector('body');
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation.type);
});
});
var config = { attributes: true, childList: true, characterData: true };
observer.observe(target, config);
in this i am able to detect changes if changes happen inside the targeted element right now i am targeting body
what i exactly want is the mutationObserver event only fires when the element i had specified is added to the DOM
You can have a good example of Mutation Observer on this page:
http://www.htmlgoodies.com/beyond/javascript/respond-to-dom-changes-with-mutation-observers.html
The working example add the observer on the body, and if you add, remove, or change an attribute you can capture the change.
But to be sure that all things are well capture use this observerConfig.
var observerConfig = {
attributes: true,
childList: true,
characterData: true,
subtree : true
};

Run javascript function when a button is enabled

I want a (preferably pure javascript but jquery is acceptable too) way to run a function when the disabled="disabled" property is removed from a button.
You can get notified of DOM changes by implementing a MutationObserver.
var observer = new MutationObserver(function(mutations) {
if(mutations.some(function(m) { return m.attributeName == 'disabled' && !m.target.disabled; }))
{
alert('Button was enabled');
}
});
observer.observe(targetButton, { attributes: true, childList: false, characterData: false });
Demo
The MutationObserver API lets you monitor elements for changes on the element.
var btnElement = document.getElementById("buttonId");
var observer = new MutationObserver(observerChanges);
observer.observe(btnElement, {
attributes: true,
subtree: opt.watchChildren,
childList: opt.watchChildren,
characterData: true
});
/// when you're done observing
observer.disconnect();
function observerChanges(mutationRecord, mutationObserver) {
console.log(mutationRecord);
}
You can use Object.prototype.watch(). It's supported in Firefox only, but here's a polyfill:
HTML:
<button id="myButton" disabled="disabled">Click</button>
JavaScript:
var myButton = document.getElementById('myButton');
myButton.watch("disabled", function() {
console.log("myButton changed!");
});
myButton.disabled = false; // "myButton changed" will be logged
JSFiddle: https://jsfiddle.net/6ofvutwh/1/
More info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/watch
Can you give us the code on how you remove disabled? But here is an example from the top of my head.
<button class="class" id="btn1" disabled>
function remove_disable()
{
document.getElementById('btn1').disabled = false;
function2();
}
then function2
function function2()
{
//somecode
}
Here, when we call remove_disable we remove the disabled feature on the button then run another function.
Hope this helps in a way
If you have control over when this change is done, a simple callback function would be the easiest solution.
Otherwise, you can use Mutation Observers to watch for when disabled property on inputs are changed.

How to 'get' an element only generated for 3 seconds via javascript?

My problem basically is that i want to click on a <button> that appears inside a <div> that is available only for 3 seconds...
The <div> has display:none, so i can make it appear whenever i want, but the <button> is generated by an other js file that i don't have access to. I can not change the original js file (to give me more time, for example) because i'm only interacting with the page using a userscript! (not my own page)
I tried so far locating inside the js code the id or the class of the button generated, but the js is minified... so no luck...
I tried also using the temporary class that is generated during those 3 seconds for that button and click on it... by doing a screenshot typing the class manually and then running a little code in the console during those 3 seconds to click on it... and no luck...
By now i think the problem is my approach to the situation, so i didn't write any code here...
Please give me your thoughts about this...
You can add MutationObserver if you want to react to changes in DOM (in your case to parent element).
Without any code it's hard to provide better answer.
jsFiddle
(function () {
"use strict";
var target = document.getElementById("hiddenElement"),
observer = new MutationObserver(function(mutations) {
mutations.forEach(function(value, index, array) {
console.log(value.type);
console.dir(value.addedNodes); // return node list
console.dir(value.removedNodes);
// put here your logic
});
});
observer.observe(target, {
childList: true,
subtree: true,
characterData: true,
characterDataOldValue: true
});
}());
(function () {
"use strict";
var newEle = document.createElement("input"),
hiddenElement = document.getElementById("hiddenElement");
newEle.type = "button";
newEle.value = "click";
newEle.addEventListener("click", function(e) {
alert("Generated only for 3 second");
});
hiddenElement.appendChild(newEle);
hiddenElement.style.display = "block";
setTimeout(function() {
hiddenElement.style.display = "none";
hiddenElement.removeChild(newEle);
}, 3000);
}());
Throw your button detection code inside a setInterval that fires often enough that it will fire while the button is present:
// note: this is just pseudocode
var interval = setInterval(function() {
// look for button
if(buttonFound) {
clickButton();
clearInterval(interval);
}
}, 300);

ControlLoaded event

I know there is no such event, but is there something similar I can use?
I have ASP.NET usercontrols which are loaded dynamically into a container, which gives a very smooth effect.
The downside of doing this is that I want to run some client-side javascript when a control has finished loading, and I don't know how.
It took me a while to figure out why my jQuery scripts weren't running, then I realised they only ran on $(document).ready() and that only occurs when the entire page loads! (Duh!)
Can anyone think of a way of doing this?
Thanks :)
Getting more complicated now!
I'm trying to use a DOM Mutation Observer to watch the container so I can run a script when it changes.
But I'm getting an error: An attempt was made to reference a Node in a context where it does not exist.
The DOM element does exist, but I'm not sure I understand the error correctly.
Here is my observer code:
$(document).ready(function () {
// select the target node
var target = $('#contentPanel');
if (typeof (target) != 'undefined') {
// create an observer instance
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
console.log(mutation.type);
if (mutation.addedNodes) {
alert('New nodes');
}
//rememberMe();
})
});
// configuration of the observer:
var config = { attributes: false, childList: true, characterData: true }
// pass in the target node, as well as the observer options
observer.observe(target, config); // <== error occurs here
}
});
The final observer code:
$(document).ready(function () {
// select the target node
var target = $('#contentPanel');
if (typeof (target) != 'undefined') {
// create an observer instance
var observer = new MutationObserver(function (mutations) {
var doRememberMe = false;
mutations.forEach(function (mutation) {
if (mutation.addedNodes) {
doRememberMe = true;
}
})
if (doRememberMe) rememberMe();
});
// configuration of the observer:
var config = { attributes: false, childList: true, characterData: true }
// pass in the target node, as well as the observer options
//observer.observe(target, config);
observer.observe(document.body, config); // <== apply observer to whole document! (could be done nicer)
}
});
Got it, in that case try this at the end of your container (you can define CallLoadedEvent in a separate JS file):
<asp:Panel id="Container" runat="server">
<!-- controls dynamically load here -->
<script>
CallLoadedEvent();
</script>
</asp:Panel>
I was eventually able to get it working using the DOM Mutation code added above.
However the only way it would work was if I applied the listener to the whole document.
For some reason I wasn't able to apply it just to the element that was being modified; perhaps for some reason it was going out of scope, even though I was able to test it existed first! Oh well.

Categories

Resources