I am aware that the main cause of this issue is when the script runs before the DOM is fully loaded. So I have tried several solutions which I've found suggested to previous similar problems on here and elsewhere, including interval before loading, interval polling, mutation observer, event listener for DOM load, and other. Nothing worked, which is why this post will be a little long (sorry).
I get the error Uncaught TypeError: Cannot read properties of undefined (reading 'appendChild') at contentScript.js:3:15 which comes from the line of code which attempts to use the element that was unable to be found. Interestingly, I also get "undefined" when I run the same document.getElementByClassName() function manually in the chrome console with the same argument. However, once I Ctrl+F to find the element manually and run the same commands again, it somehow does find the elements and executes the code as intended. This way I was able to check that my code does actually do exactly what I want it to do, as long as it is able to find the actual element.
Now, this is the first extension I've ever actually tried making myself so I apologize for being out of my depth. However, I have managed to achieve certain other functionalities on the same exact webpage, so I know for sure that I am doing at least some things right. Unlike the main problem, these working functionalities are also achievable through the chrome console.
The code which works is the following:
var notificationsNumber = document.getElementById("notificationsNumber");
if (notificationsNumber) {
notificationsNumber.parentNode.removeChild(notificationsNumber);
}
Simple enough, all it does is get rid of the annoying red number indicating the unread notifications.
So onto what I'm trying to do. Basically there is a chess website which offers chess opening courses and this page which lets you explore recommended moves from the courses on that website (requires an account, or can log in with google acc if you'd like to explore). All I want is to make a simple extension to add functionality to this webpage mostly for personal use. My very first step was to add a button to an existing array of buttons with the following code:
var buttondiv = document.getElementsByClassName("board-btns")[0];
buttondiv.appendChild(buttondiv.firstElementChild.cloneNode(true));
But maybe we need to wrap it such that it only runs once the DOM fully loads, like suggested here:
window.addEventListener("DOMContentLoaded", function(){
var buttondiv = document.getElementsByClassName("board-btns")[0];
if (buttondiv) {
console.log("Button div found");
buttondiv.appendChild(buttondiv.firstElementChild.cloneNode(true));
} else {
console.log("Button div not found");
}
})
Again, does not work. Interestingly, neither of the console messages pop up either. So I tried the same wrap with the notification script (the part of the extension that did work) and it is suddenly broken. Conclusion being that the event listener never triggers. The website does load, by the way, I can interact with everything including the buttons, and with the aforementioned Ctrl+F business I can run the exact same code in the console and manually make everything do what I want it to do.
Next try is to implement a mutation observer. I am not super familiar with JS so I asked copilot and it gave me this code:
// Function to execute when mutations are observed
var callback = function(mutationsList, observer) {
// Look through all mutations that just occured
for(let mutation of mutationsList) {
// If the addedNodes property has one or more nodes
if(mutation.addedNodes.length) {
var buttondiv = document.getElementsByClassName("board-btns")[0];
if(buttondiv) {
buttondiv.appendChild(buttondiv.firstElementChild.cloneNode(true));
observer.disconnect(); // Stop observing
return;
}
}
}
};
// Create an observer instance linked to the callback function
var observer = new MutationObserver(callback);
// Start observing the document with the configured parameters
observer.observe(document, { childList: true, subtree: true });
Again, doesn't work. Only other recommended solution I could find was to introduce an interval:
function checkForElement() {
var buttondiv = document.getElementsByClassName("board-btns")[0];
if(buttondiv) {
buttondiv.appendChild(buttondiv.firstElementChild.cloneNode(true));
return true;
}
return false;
}
var intervalId = setInterval(function() {
console.log("Checking for element");
if(checkForElement()) {
clearInterval(intervalId);
}
}, 500);
All this does is print the console message every 500ms, but nothing actually works. I tried again to find the element manually with Ctrl+F in inspect element, I ran the code in the console, it made everything work, but the "checking for element" message kept coming up.
I feel like I have tried everything in my power, and even copilot gave up on me and ran out of further recommendations. If you have any suggestions, I am on my knees.