skip to Main Content

Hi it’s my first time using JavaScript and HTML so I might be doing something wrong:

I am trying to insert something new into a webpage using chrome extension, and my code sometimes work but sometimes not.
For example, when I try to insert a text into any YouTube page, my code can querySelect id="logo" but not id="secondary". I don’t have a good sense of JavaScript nor HTML, and I am completely stuck here.

Here is my manifest.json and my content.js:

{
    "manifest_version": 3,
    "name": "tutorial",
    "version": "1.0",
    "description": "Add text to YouTube page",
    "content_scripts": [
      {
        "js": ["content.js"],
        "matches": [
          "https://www.youtube.com/*"
        ]
      }
    ]
}
if(document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded',afterDOMLoaded);
} else {
  console.log('DOM fully loaded and parsed');
  
  const object = document.querySelector('#secondary');

  if (object) {
    const newElement = document.createElement('div');
    newElement.innerText = 'Hello from the YouTube Element Injector!';
    object.insertAdjacentElement('afterbegin', newElement);
  } else {
    console.log('object is null');
  }
}

and
my result with #logo

and
my result with #secondary

I would appreciate any advice! Thanks

2

Answers


  1. With the example you gave, I presume you are trying to explore the youtube.com DOM. The #secondary node seems to exist but not during the first render.

    Maybe you can try to wait for the readystate to change

    document.addEventListener("readystatechange", (event) => {
      if (document.readyState === "complete") {
        afterDOMLoaded(event);
      }
    });

    Here the MDN documentation: https://developer.mozilla.org/en-US/docs/Web/API/Document/readystatechange_event

    Login or Signup to reply.
  2. Iy may be that the YouTube page doesn’t have "#secondary" at the time your code is executed. This could happen if the element is added to the page dynamically, after your code has already run.

    You can get around this by using a MutationObserver to watch for changes to the DOM

    // Define a function to handle DOM mutations
    function handleMutations(mutationsList, observer) {
      for (const mutation of mutationsList) {
        if (mutation.type === 'childList') {
          const obj = document.querySelector('#secondary');
    
          if (obj) {
            const el = document.createElement('div');
            el.innerText = 'Hello from the YouTube Element Injector!';
            obj.insertAdjacentElement('afterbegin', el);
            // you should disconnect() after insertion for performance
            observer.disconnect();
          }
        }
      }
    }
    
    // Create a new observer and start watching for mutations
    const observer = new MutationObserver(handleMutations);
    observer.observe(document.body, { childList: true });
    
    

    This create a MutationObserver and starts watching for changes on document.body. When a child element has been added or removed (i.e. the "childList" mutation), handleMutations is called. In that function, you can try to select #secondary and insert the new div element.

    Note that you should call observer.disconnect() after you’ve inserted the new element to stop the observer from watching for further mutations. This is because you only need to insert the new element once, and you don’t want to keep inserting it every time the DOM changes.

    I hope this helps! Let me know if you have any questions.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search