Search code examples
javascripthtmlgoogle-chrome-extension

"Uncaught ReferenceError: element is not defined" on click event in chrome extension


It's a simple code to develop a chrome extension, but I ran into a problem.

[ popup.js ]

function handleClick(btn) {
    chrome.tabs.query({active: true}, function(tabs) {
        chrome.scripting.executeScript({
            target: {tabId: tabs[0].id},
            function: () => {
                console.log(btn); // error occured here
            }
        });
    })
}

function start(){
    const btn = document.querySelector('#request-btn');
    btn.addEventListener('click', function() {
        handleClick(btn);
    });

}
window.onload = start;

[ popup.html ]

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <style>
            BODY {width : 250px; min-height:250px;}
        </style>
    </head>
    <body>
        <input type="button" value="create answer" id="request-btn">
        <div id="email-writer"></div>
        <script src="popup.js"></script>
    </body>
</html>

[ manifest.json ]

{
  "manifest_version": 3,

  "name": "projectname_chromeExtension",
  "description": "projectname_cs_chromeExtension",
  "version": "1.0.0",

  "action": {
    "default_icon": "logo.png",
    "default_popup": "popup.html"
  },

  "permissions": [
    "tabs",
    "activeTab",
    "scripting"
  ],

  "host_permissions": [
    "..." // I omit it due to project regulations, but I don't think this is a problem!
  ]
}

I want to load and use the button element in popup.html , but it gives an error that it is not defined. The exact content of the error is "Uncaught ReferrenceError: btn is not defined.".

I tried many methods, such as passing btn as an argument or using document.querySelector() in handleClick() to get the button element again, but it didn't work. Is there something I'm missing? Any help would be appreciated.

enter image description here


Solution

  • As the documentation says,

    This function will be serialized, and then deserialized for injection. This means that any bound parameters and execution context will be lost.

    In your case, the button is inside popup whereas the function will execute in target page's context.

    Rather, if you wanted to read some attributes of the button inside the function, you may pass using args parameter.

    chrome.scripting.executeScript({
      target: {tabId: tabs[0].id},
      func: (attr) => {
        console.log(attr);
      },
      args: [btn.getAttribute('data-name')]
    });