Reputation: 2601
I am trying to display a notification in my Chrome extension when an HTTP response is received. Every time I try, I get the following error.
Uncaught TypeError: Cannot read property 'create' of undefined
I have made sure that I have the notifications permission set in the manifest.json.
I thought I might be able to do the notification in a callback function, however anything I pass in for a callback (function, constant, variable, etc) is always undefined.
Here is my relevant code.
function push(info,tab) {
function modifyDOM(tab_info, callback) {
var endpoint = "https://blahblahblah";
var xmlhttp = new XMLHttpRequest();
alert(callback); //always undefined.
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200) {
alert(this.responseText);
var msg = 'Pushed ' + tab_info.tab.url + ' to endpoint';
var opt = {
iconUrl: "images/img48.png",
type: 'basic',
title: 'Handler',
message: msg
};
chrome.notifications.create(opt); //Error occurs here.
}
else {
alert(callback); //always undefined
}
}
};
xmlhttp.open("POST", endpoint);
xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xmlhttp.send(JSON.stringify({ "body": {"content": document.body.innerText }, "query": { "url": tab_info.tab.url, "title": tab_info.tab.title} }));
}
chrome.tabs.executeScript({
code: '(' + modifyDOM + ')(' + JSON.stringify({ "tab" : tab, "callback": 1}) +');' //callback parameter is always undefined in the modifyDOM() function above
}, (results) => {
console.log(results[0]);
});
}
manifest.json
{
"manifest_version": 2,
"version": "1.0",
"name": "Handler",
"description": "Push to endpoint",
"icons": {
"16": "images/img16.png",
"48": "images/img48.png",
"128": "images/img128.png"
},
"permissions": [
"tabs",
"contextMenus",
"*://*/*",
"notifications"
],
"background": {
"scripts": ["script.js"]
}
}
Upvotes: 0
Views: 627
Reputation: 73526
The function modifyDOM
doesn't run inside the background script. It's only declared there and you convert its code into a string and inject via chrome.tabs.executeScript, which runs the code as a content script in the active tab. Content scripts can't use most of chrome
API, they can use only the few basic ones like chrome.i18n, chrome.runtime, chrome.storage.
The solution is to call chrome.notifications in the background script context e.g. send a message from the injected code.
The parameters are passed as a single object { "tab" : tab, "callback": 1}
but the function is declared to take two.
The simplest solution is to declare the function to take a single object too and use destructuring.
function modifyDOM({tab, callback}) {
// ..............
xmlhttp.onload = function () {
if (this.status == 200) {
chrome.runtime.sendMessage('Pushed ' + tab_info.tab.url + ' to endpoint');
}
};
// ..............
}
background script global code:
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
var opt = {
iconUrl: 'images/img48.png',
type: 'basic',
title: 'Handler',
message,
};
chrome.notifications.create(opt);
});
Upvotes: 2