In my Chrome extension, I am trying to send a message from popup.js to content.js. This needs to happen based on an event in the popup, so it can't be triggered on a message from content or background.
I am using the following code just to test whether the message is being passed.
In popup.js:
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
alert(response.farewell);
});
});
In content.js:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
alert(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting == "hello")
sendResponse({farewell: "goodbye"});
});
;
The problem is that the message is only being delivered (alerted) when I open a new tab, not when I am in an active tab.
The idea is that the user is able to choose a setting in the popup which then causes the content.js to send through different data. So I should be able to send the message whenever the uses click a specific button.
Could someone please help because in every other question about this I just see the link to the Google page about Message Passing. This code is straight from there.
Related
Here's the code to the popup.jsx file and the background index.js file. For starters, I'm just working with a simple alert. the way I've gone with the working is that the background makes note of any new tabs using chrome.tabs.onCreated() and sends a message to the popup once so,
the issue I feel I'm facing is that the popup isnt receiving the message sent by the background file. please help out if you can, this is the link to the Github repo.https://github.com/Brihadeeshrk/extension
popup.jsx
chrome.runtime.onMessage.addListener((req) => {
console.log("message: "+req.message)
if(req.type === 'newTabCreated') {
alert("new tab")
}
return true
})
background.js
chrome.tabs.onCreated.addListener(function() {
console.log('new tab created')
chrome.runtime.sendMessage({
type: "newTabCreated",
message: "new tab created121"
}, function() {
console.log("message sent")
})
})
I am injecting an iframe in a tab. Now inside the the iframe, based on user's actions, I need to show some error/warning/success notifications. However I want to display these notifications in the tab not in iframe. So I need to communicate between iframe and content script. Now these notifications are dynamic based on user's actions so I thought of message passing between iframe and content script via background page.
So what i have done is send messages from iframe to background. Now both background page and content script listens to these messages but only background page is able to receive them. On receiving messages it reflects them back to sender tab. Now content script can receive these messages as they are sent from background page.
Now I tried the same using custom events but it didn't work.
But i would like to know any other method which is more efficient than what i am doing??
EDIT : Here's the relevant code
iframe.js:
$scope.hideFrame = function(){
sendMessageToBackground("hideFrame");
};
$scope.checkIfFormValid = function(){
if(!($scope.taskName === "" || $scope.group.selectedGroup === null )){
$scope.addTask();
}
else{
sendMessageToBackground("invalidForm");
}
};
function sendMessageToBackground(msg){
chrome.runtime.sendMessage({type: msg});
}
background.js:
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
switch (request.type){
case "hideFrame":
chrome.tabs.sendMessage(sender.tab.id,{type:"hideFrame"});
break;
case "invalidForm":
chrome.tabs.sendMessage(sender.tab.id,{type:"invalidForm"});
break;
}
});
content.js:
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
switch (request.type){
case "invalidForm":
var n = noty({
text : ' Please fill all details',
type : 'error',
layout : 'topRight',
timeout : 10000,
theme : 'defaultTheme'
});
break;
case "hideFrame":
$("#isolatedFrame").hide();
break;
}
});
Using window.parent.postMessage(not working):
iframe.js:
function sendMessageToContent(msg){
// chrome.runtime.sendMessage({type: msg});
window.parent.postMessage({ type: "fromFrame", message: msg }, "*");
}
content.js:
window.addEventListener("message", function(event) {
if (event.source != window)
return;
if (event.data.type && (event.data.type == "fromFrame")) {
console.log("Content script received: " + event.data.message);
}
}, false);
Also, when i add a breakpoint at window.parent.postMessage({ type: "fromFrame", message: msg }, "*"); and try to see window.parent object , inspected target is disconnected. I don't why this is happening??
Yes, there's a more effective way to achieve it - using tabs.sendMessage.
extensions cannot send messages to content scripts using this method. To send messages to content scripts, use tabs.sendMessage. (see runtime.sendMessage document )
Here's the code.
iframe.js:
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
console.log(response.farewell);
});
content.js:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
console.log('greeting:", request.greeting);
sendResponse({farewell: "goodbye"});
You can also refer to https://developer.chrome.com/extensions/messaging#simple for more detail.
EDIT
Since iframe.js is a content script, you should send the message with chrome.runtime.sendMessage and without using chrome.tabs API. Otherwise, chrome.tabs will be undefined.
I am developing a Google Chrome Extension. I want to get the contents(text only) of the active tab. I am sure that Content scripts will help me find what I am looking for.
But I am stuck in the below scenario:
If I run my chrome.tabs.onUpdated.addListener(function(){ in my background.js, I am able to achieve other tasks, say ajax post etc. But if I include document.body.innerHTML in that chrome.tabs.onUpdated.addListener(function(){, to get the contents of the opened tab, it is alerting the contents of my background.html and NOT the contents of the tab which is opened in the browser.
If I paste the chrome.tabs.onUpdated.addListener(function(){ in my content scripts, I am not able to trap the tab update.
Can I know where I am going wrong?
Try like this:
// In background.js
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (changeInfo.status === 'complete') {
chrome.tabs.sendMessage(tabId, {type: 'getDoc'}, function (doc) {
console.log(doc);
});
}
});
// In content_scripts.js
chrome.extension.onMessage.addListener(function(request, sender, response) {
if (request.type === 'getDoc') {
response(document.body.innerHTML);
}
return true;
});
In my extension, I am passing a message from background.js to contentScript.js.
The issue is that when I use
"run_at" : "document_start"
in my manifest.json, the message from background.js to contentScript.js is called twice and sometimes even more than that.
Message passing more than once is a bit expensive in my case as I'm sending a call to server and the processing the same values at the server multiple times is expensive.
background.js
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
chrome.tabs.sendMessage(tab.id, {type: "get-url", url: tab.url});
});
contentScript.js
chrome.runtime.onMessage.addListener(
function(message, sender, sendResponse) {
switch(message.type) {
case "get-url" : someFunction(message.url);
break;
// other cases
}
});
Is there a way to solve this?
chrome.tabs.onUpdated is called multiple times in the tab-update cycle (e.g. when the tab starts loading the new page, when the tab completes loading the new page, when the favicon is fetched etc).
The best option is to checj for when the tab has completed loading:
chrome.tabs.onUpdated.addListener(function (tabId, info, tab) {
if (info.status === 'complete') {
/* Now it is safe to send the message */
chrome.tabs.sendMessage(tabId, {
type: 'get-url',
url: tab.url
});
}
});
BTW, when injecting programmatically (not in manifest.json), the property's name is runAt, not run_at (docs).
I'm trying to pass data that is saved in sessionStorage from background.html to popup.html
background.html:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
data = sessionStorage.getItem(request.tabId);
alert(data);
sendResponse({ data: data });
});
and in popup.html:
chrome.tabs.getSelected(null, function(tab) {
chrome.extension.sendRequest({ tabId: tab.id }, function(response) {
alert(response.data);
});
});
The popup is opened by a pageAction button, when I click the button I get an alert box with "null" on the popup and then an alert box with the data that I stored in sessionStorage on the background!
Any ideas how to fix this?
You don't need to use message/request APIs. I think this response may help you.
You also don't need sessionStorage, just store your data in a global variable of the background page. It will persist until the browser is closed or until the extension is restarted.
So, here is how I would rewrite your code:
background.html:
var data = {}; // Object storing data indexed by tab id
and in popup.html:
chrome.tabs.getSelected(null, function(tab) {
alert(chrome.extension.getBackgroundPage().data[tab.id]);
});
Note that chrome.tabs.getSelected is deprecated since Chrome 16, so popup code should be:
chrome.windows.getCurrent(function(win) {
chrome.tabs.query({'windowId': win.id, 'active': true}, function(tabArray) {
alert(chrome.extension.getBackgroundPage().data[tabArray[0].id]);
});
});
Well, I've done something dumb.
I inspected the background page by opening chrome-extension://[extension-id]/background.html in a tab instead of clicking on "inspect active views: background.html" in the extensions management page. This caused the tab to catch the request and call sendResponse, but the popup expected the REAL background page to call sendResponse (and if I understand Google's documentation regarding message passing, the fact that sendResponse was called twice is root of the problem, because the first call clears the request object)