Search code examples
javascripthtmlgoogle-chrome-extension

querySelector not working in Chrome extension code


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


Solution

  • 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.