I am trying to send a message from a content script to my background script. When the background receives the message it sends data back to the content script in the callback.
My popup also has a listener for messages from the content script, but does not respond to a message meant for the background script.
Then content is receiving an undefined back from the callback, which I think is caused by the popup receiving the message but not responding.
The reference says:
Note: If multiple pages are listening for onMessage events, only the
first to call sendResponse() for a particular event will succeed in
sending the response. All other responses to that event will be
ignored.
So surely I should only get the response from my background script.
My content script does this:
function notifyReady() {
chrome.runtime.sendMessage({
type: 'ACTIVITY_HISTORY_READY'
},
function (response) {
console.log(">>>>Response: ", response);
if (response.type == 'HISTORY_DATA') {
processLog(response);
}
});
}
My background script listens like this:
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
console.log("received " + msg.type);
if (msg.type = 'ACTIVITY_HISTORY_READY' && historyData) {
if (historyData) {
sendResponse({
type: "HISTORY_DATA",
position: historyData.position,
company: historyData.company
});
historyData = '';
} else {
sendResponse({
type: "NO_DATA"
});
}
}
});
And the listener in my popup is:
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
if (msg.type == 'JOB_DETAILS') {
sendResponse("OK!");
document.getElementById('position').value = msg.position;
document.getElementById('company').value = msg.company;
document.getElementById('url').value = sender.tab.url;
}
});
if (msg.type = 'ACTIVITY_HISTORY_READY' && historyData) {
note that if historyData is falsey you are not sending any response. The else branch of the second if can never be taken.
You should remove historyData from the first if. The popup code has nothing to do with this.
Related
In my Chrome extension, I'm trying to exchange data between an internal web page of the extension chrome-extension://myExtensionId/path/to/web/page.html and content scripts.
So, in order to make this data persistent among different content scripts, I'm trying to save it as global variables in the extension's background! I do so using message passing.
My problem is:
When I try to send a response back from the background I get this error:
Error in event handler for (unknown): TypeError: sendResponse is not a
function
I followed the documentation's examples and this is my attempt:
In the scriptOfTheInternalPage.js :
var message = {
'order': 'setData',
'varName': 'myArray',
'data': myArray
};
extPort.postMessage(message, function (response) {
console.log('response:\n', JSON.stringify(response));
});
In background.js :
var globals = {
'myArray': [],
...
};
chrome.runtime.onConnect.addListener(function (port) {
port.onMessage.addListener(
function (message, sender, sendResponse) {
console.log(
'the port received this message:\n', JSON.stringify(message), '\n',
(sender.tab) ? ' from tab #' + sender.tab.id : ' from the extension!'
);
if (message.order === 'setData') {
globals[message.varName] = message.data;
sendResponse({'response': 'data saved!'}); //<=====
}
return true; //<=== tried to return true here as well;
});
});
Does this error means I should create a brand new function outside of the onMessage event listener?
I'm confused! What am I missing?
Port's onMessage event listeners do not have the same signature as runtime.onMessage. You don't get sender and sendResponse parameters, only the message. Returning true has no effect either.
To reply to a message, you need to use the port itself. This is covered by examples:
port.onMessage.addListener(function(msg) {
if (msg.joke == "Knock knock")
port.postMessage({question: "Who's there?"});
}
So you do need an onMessage listener on both sides, and some way to track requests (unique ID?) if several can be made.
I am getting a trouble about passing message inside background page of chrome extension.
In content page
I send a message and wait for a response from background page:
chrome.runtime.sendMessage({"name": "Calling"}, function (response) {
console.log(response);
});
In background page
I have an event listener to listen message from content page:
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
if (request.name == "Calling") {
doTask().then(function (message) {
sendResponse(message);
});
return true; // Make respond asynchronously
}
}
);
Inside "Calling" event Listener, i call the function doTask() which return a promise:
var doTask = function(){
return new Promise(function (resolve) {
chrome.runtime.sendMessage({"name": "DoTask"}, function (response) {
resolve(response);
});
});
};
Inside doTask() i send another message "DoTask", and wait for response.
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
if (request.name == "DoTask") {
var message = "Task has done!";
sendResponse(message);
return true; // Make respond asynchronously
}
}
);
I expect "Task has done!" will be printed in content page, but nothing appears! When debugging i realize "DoTask" event listener cannot receive any message.
What wrong here? Thank you.
P/S: I make sure that all scripts are injected in manifest.json
I'm trying to build a chrome extension that involve sending request for data from popup script to Content script (through background script) analyze the request on the content script side and send back a response (again through the background script).
The popup script code:
chrome.runtime.sendMessage({action:"getLanguages",data:"hi hi",}, function(response) {
document.write(response.msg);
});
The background script:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
var returnedLangs;
if (request.action == "getLanguages"){
returnedLangs = getLangs();
alert("got langs " + returnedLangs);
//sendResponse({msg: "goodbye"});
}
});
function getLangs() {
var langs;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {action: "getLanguages"}, function(response) {
langs = response.langs;
alert(langs);
return langs;
});
});
}
The content script code:
chrome.extension.onMessage.addListener( function(request, sender, sendResponse)
{
getLanguages(sendResponse,sendBackLangs);
});
function getLanguages(sendResponse,callback) {
var acceptLangs = [];
chrome.i18n.getAcceptLanguages(function(langs) {
langs.forEach( function(lang) {
acceptLangs.push(lang);
});
callback(sendResponse,acceptLangs);
});
}
function sendBackLangs(sendResponse, acceptedLangs) {
sendResponse({langs: "acceptedLangs"});
}
With the current content script code no response is sent back to the background but if i do sendResponse directly from the chrome.extension.onMessage... function the response is arriving back to the background.
Can anyone help me understand what causes ths behavior and how can i fix it ?
chrome.tabs.sendMessage(tabs[0].id, {action: "getLanguages"}, function(response) {
langs = response.langs;
alert(langs);
return langs; // <---- Return where?
});
See the above snippet. You can't return a value from an asyncronous callback. In fact, this code block just finishes before the inner function executes and getLangs() returns undefined.
What you want to do, however, is doable. You can pass the sendResponse function into the callback to be called later; you just need to indicate to Chrome that you will call it later.
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.action == "getLanguages"){
getLangs(sendResponse); // Pass the callback
return true; // Indicates to Chrome to keep the message channel open
}
});
function getLangs(callback) {
var langs;
chrome.tabs.query(
{active: true, currentWindow: true},
function(tabs) {
chrome.tabs.sendMessage(
tabs[0].id,
{action: "getLanguages"},
function(response) {
// Here it sends it to the content script
callback(response.langs);
}
);
}
);
}
That said, there's absolutely no reason to route the request through background. Just do the tabs.query directly in the popup.
I send a message from a ContextMenu within content.js to background.js. When I send a message, I expect to see an alert of just two variables which are sent with the request. When I send multiple request(few times in a row) I receive alerts including previously sent messages. It seems that all messages are stored somewhere. How do you disable this? I would like to see alerts of only the most recent message.
contents.js:
$(document).mousedown(function(event) {
var url = window.location.href;
var contents = window.getSelection().toString();
switch (event.which) {
case 3:
chrome.runtime.sendMessage({contents: contents, url: url}, function(response) {
//console.log(response.farewell);
});
break;
}
});
background.js
chrome.extension.onMessage.addListener(function (message, sender, sendResponse) {
if (message.url) {
chrome.contextMenus.onClicked.addListener(function testFunc2(info, tab){
alert(message.url);
alert(typeof message.contents);
}
)
}
});
manifest.json
"background": {
"scripts": ["jquery-1.11.1.min.js", "background.js"],
//"page": "background.html",
"persistent": true
},
It's because of this code
chrome.extension.onMessage.addListener(function (message, sender, sendResponse) {
if (message.url) {
chrome.contextMenus.onClicked.addListener(function testFunc2(info, tab){
alert(message.url);
alert(typeof message.contents);
}
)
}
});
What you are saying is that every onMessage event add a listener for onClicked events. So if you send three messages you end up with three testFunc2 methods acting on onClicked events.
Since you are trying to use information from two different asynchronous events. You will have to store one of them temporarily. Something like this would probably work.
var lastMessage;
chrome.extension.onMessage.addListener(function(message, sender, sendResponse) {
if (message.url) {
lastMessage = message;
} else {
lastMessage = undefined;
}
});
chrome.contextMenus.onClicked.addListener(function(info, tab) {
if(lastMessage !== undefined) {
testFunc2(message, info, tab);
}
});
function testFunc2(info, tab){
alert(message.url);
alert(typeof message.contents);
// cleanup
lastMessage = undefined;
});
I'm so close to finishing my Chrome extension. I have one or two things to do. One of them is sending a message from the content script to the background script. I wrote the following, but it doesn't quite what I want.
content.js
var a=document.getElementsByTagName('a');
for (i=0,len=a.length;i<len;i++) {
a[i].addEventListener('contextmenu', function() {
var linkTitle = this.getAttribute('title').trim();
var linkUrl = this.getAttribute('href');
if ((linkTitle != null) && (linkTitle.length > 0)) {
chrome.extension.sendMessage({action:'bookmarkLink', 'title':linkTitle, 'url': linkUrl}, function(msg) {
alert('Messages sent: '+action+' and '+linkTitle+' also '+linkUrl);
});
}
});
};
background.js
chrome.contextMenus.create({'title': 'Add to mySU bookmarks', 'contexts': ['link'], 'onclick': mySUBookmarkLink});
function mySUBookmarkLink(info, tab) {
chrome.extension.onMessage.addListener(function(msg, sender, sendResponse) {
if (msg.action == 'bookmarkLink') {
chrome.storage.sync.set({'title': msg.linkTitle, 'url': msg.linkUrl}, function(msg) {
alert('Saved '+msg.linkTitle+' to bookmarks');
});
}
});
};
My problems are:
In the first code block, it alerts Saved undefined to bookmarks as soon as I right click on the link, while as I understand it should only send a message on right click and the second code block should alert Saved to bookmarks when I click on the context menu. What am I missing or doing wrong?
I may not have used parameters correctly (I am fairly new to extension development and Javascript in general). Do the above look okay?
Thank you in advance,
K.
It's chrome.runtime.sendMessage and chrome.runtime.onMessage rather than chrome.extension.
There used to be chrome.extension.sendRequest and chrome.extension.onRequest which have been deprecated in favor of the chrome.runtime API methods mentioned above.
See Chrome Extensions - Message Passing
it's JSON-serializable messaging, where first pair is for recognition, and then followed by pairs of
key: value.
You pull the value from received message by calling it's key.
is should be:
alert('Saved '+msg.title+' to bookmarks');
or even better:
function mySUBookmarkLink(info, tab) {
chrome.extension.onMessage.addListener(function(msg, sender, sendResponse) {
if (msg.action == 'bookmarkLink') {
var receivedValue = msg.title; //pull it out first, for better overview
chrome.storage.sync.set({'title': msg.title, 'url': msg.url}, function(msg) {
alert('Saved '+receivedValue+' to bookmarks');
});
}
});
};