I am making an autofill chrome extension. Namely, once pressing a button, an input form in the content web page will be populated by the text from the popup.html. I am getting this "cannot read properties of null" error starting from where I added an event listener to my button. [Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')][1]
Here is my html file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Autofill</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<p id="testText">Text to put</p>
<button id="fillForm">Fill!</button>
<script src="app.js" ></script>
</body>
</html>
Here is my app.js
console.log('background running!!!')
let testtext = document.getElementById('testText')
let button = document.getElementById('fillForm')
button.addEventListener('click', buttonClick);
function buttonClick(){
params = {
active: true,
currentWindow: true
}
chrome.tabs.query(params, gotTabs);
function gotTabs(tabs){
let text = testtext.innerHTML
let content = {
username: text
}
chrome.tabs.sendMessage(tabs[0].id, content);
}
}
Here is my content.js
console.log("Receiving message...")
chrome.runtime.onMessage.addListener(gotMessage);
function gotMessage(message, sender, sendReponse){
document.getElementById('email').value = content.username
}
Lastly, my manifest.json
{
"name": "Resume Autofiller",
"description": "Build an Extension!",
"version": "1.0",
"manifest_version": 2,
"browser_action":{
"default_popup": "index.html"
},
"permissions": [
"activeTab",
"<all_urls>"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": [ "content.js" ]
}
],
"background": {
"scripts": ["app.js"]
}
}
I have read online that I should put my script tag at the bottom of the body tag, but I still get this error. I feel like I am overseeing something obvious, therefore any help is greatly appreciated. Thanks!! Attached is the error I am getting. [1]: https://i.stack.imgur.com/GyNXO.png
CodePudding user response:
As said, removing background from manifest will fix this, but there appears to be a conceptual mix-up in the code sample, which is why I would like to explain why this solution works.
The script called app.js seems to be intended to be the popup script, but being used as a background script in the example. Popup is different from background. It will help to understand the difference between these two extension parts and their use cases. For continuity, the following explanation will refer to MV3 version and terms.
Background: "A background service worker is loaded when it is needed, and unloaded when it goes idle [...] Structure background scripts around events the extension depends on. Defining functionally relevant events allows background scripts to lie dormant until those events are fired and prevents the extension from missing important triggers." (Manage events with service workers) Additional note: background is literally in the background; there is no visible user interface. User would not be interacting with buttons in the background (though it is possible to send events to background for further handling through message passing). Consider background as a singleton.
Popup: This is one of the possible places to provide a UI for the extension user. The popup is activated by user clicking the extension icon, and destroyed when the popup loses focus (also when tab is closed), and reloaded again when user clicks the icon the next time. "Like the background script, this file must be declared in the manifest in order for Chrome to present it in the extension's popup. To do this, add an action object to the manifest and set popup.html as the action's default_popup." (Introduce a user interface). In the popup you can add buttons and other elements for user to click. Popup is specific to each tab. Opening multiple browser windows and clicking the icon, multiple popups can be open at the same time.
In short: the error is coming from looking for button element in the background, when there are no such buttons; removing the manifest key will prevent this.
Minimal working example
manifest.json: background
key removed
{
"name": "Resume Autofiller",
"description": "Build an Extension!",
"version": "1.0",
"manifest_version": 2,
"browser_action":{
"default_popup": "index.html"
},
"permissions": [
"activeTab",
"<all_urls>"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": [ "content.js" ]
}
]
}
index.html: no change
(style.css will raise not found error, but not a concern regarding this question)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Autofill</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<p id="testText">Text to put</p>
<button id="fillForm">Fill!</button>
<script src="app.js" ></script>
</body>
</html>
app.js: changed log text, no significant change
console.log('popup running!!!')
let testtext = document.getElementById('testText')
let button = document.getElementById('fillForm')
button.addEventListener('click', buttonClick);
function buttonClick(){
params = {
active: true,
currentWindow: true
}
chrome.tabs.query(params, gotTabs);
function gotTabs(tabs){
let text = testtext.innerHTML
let content = {
username: text
}
chrome.tabs.sendMessage(tabs[0].id, content);
}
}
content.js: change log outputs a bit, commented out assignment
chrome.runtime.onMessage.addListener(gotMessage);
function gotMessage(message, sender, sendResponse){
console.log("Receiving message...")
console.log('message', JSON.stringify(message));
// next line has undefined references, commenting out
// document.getElementById('email').value = content.username
}