39

I'm trying to implement my own chrome extension on which, on a certain event, create a browser notification and fills the popup with data calculated in background.js

Here is my manifest.json file:

{
    "name": "Dummy name",
    "description": "Description",
    "manifest_version": 2,
    "version": "1.1.3",
    "icons": {
        "16": "icon_16.png",
        "48": "icon_48.png",
        "128": "icon_128.png",
        "256": "icon_256.png"
    },
    "browser_action": {
        "default_icon": "icon_48.png",
        "default_title": "Test",
        "default_popup": "popup.html"
    },
    "permissions": ["background","webRequest","webRequestBlocking","webNavigation","tabs","notifications"],
    "background": {
        "scripts":["jquery-1.8.1.min.js","classy.js","background.js"]
    }
}

My call to sendMessage in background.js

show : function(result) {
    var that = this;
    chrome.extension.sendMessage({greeting: "hello"}, function(response) {
        console.log(response);
    });

    if(window.webkitNotifications) {
        var notification = webkitNotifications.createHTMLNotification('notification.html');
        notification.show();
        setTimeout(function(){
            notification.cancel();
            }, '7000');
        }
    }

My message listener in popup.js (from chrome extension samples)

chrome.extension.onMessage.addListener(
  function(request, sender, sendResponse) {
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.greeting == "hello")
      sendResponse({farewell: "goodbye"});
  });

The only error I get is a

Port error: Could not establish connection. Receiving end does not exist.

Thank you for your help!

8
  • The background page is loaded a long time before the browser action popup is displayed. Obviously, the popup script didn't have a change to bind the event listener via chrome.extension.onMessage. Commented Sep 4, 2012 at 19:19
  • As said before, this is triggered on an event basis. As the event occurs à few seconds after page loading, is it still right to believe that it is not listened bu the popup ? Commented Sep 5, 2012 at 3:30
  • 6
    Make sure that what you say is true. You could put in an alert('') dialog to see whether the methods occur in the expected order. Side note, you can directly communicate between popup/background via chrome.extension.getBackgroundPage() (gets access to background's global window object from the popup) and chrome.extension.getViews({type:'popup'})[0] (to get the global window object of a popup, if existent, from the background page). Commented Sep 5, 2012 at 8:04
  • I just tested that out and actually, any action in the popup can only be triggered when it's open. Any idea how to simulate the message sending ? Unfortunately, it's the same with the getBackgroundPage() and getViews() ... only work when the popup is open :( Commented Sep 5, 2012 at 9:20
  • 1
    "Obviously" is also deprecated and should be avoided. Commented Jan 22, 2019 at 4:12

5 Answers 5

45

Popup doesn't have tab id so you will get the error.

You can use chrome.runtime.sendMessage and chrome.runtime.onMessage.addListener in that case.

So in background.js

chrome.runtime.sendMessage({
    msg: "something_completed", 
    data: {
        subject: "Loading",
        content: "Just completed!"
    }
});

And in popup.js

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
        if (request.msg === "something_completed") {
            //  To do something
            console.log(request.data.subject)
            console.log(request.data.content)
        }
    }
);

I hope it would be helpful to you.

Sign up to request clarification or add additional context in comments.

3 Comments

what if i have opened multiple tabs and sending message to popup.js. which popup.js will receive it ? how to send message to where i want send message @Perfect
You should send message from popup to backend script. At this point, you can get tab_id in backend script to identify which tab's popup sent to background. There is no way to send message from backend script to popup, but you can send backend script to a specific tab's content script. Or you can create a connection between the backend and popup. Look at this link. stackoverflow.com/questions/13546778/…
I did exactly the same by using tabid before see this.Thanks @Perfect for another way
14

To solve this you need to first send a handshake message to background.js and then send the actual data from background.js to popup.js For Example: In my case what i did was

popup.js

chrome.runtime.sendMessage({data:"Handshake"},function(response){
	
			});
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
	str = JSON.stringify(message.data);
});

background.js

chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
//alert(message.data);
	chrome.runtime.sendMessage({data:datax},function(response){
			});
			});

What iam trying to do is that as soon as we click on icon the handshake message is sent to the background.js and when it recieves it we can then send the variable or any data whick we wanted to send on popup.js to render it on popup.html.

2 Comments

I like the handshake idea, it ensures the popup is alive (not destroyed) and able to listen for incoming data. Also this seems like a one-off event for every page load, which follows the API's Simple one-time request methods
But this means that call is initiated by the Popup. I believed the OP wanted a conversation initiation from background to popup. If popup wanted to pull data from background it could as well do the standard approach of: let bg= chrome.runtime.getBackgroundPage() and then get msg by console.log(bg.message); Here 'message' is an object in background.js file
10

These are the two simplest ways I've found to send data from background.js to popup.js:

1) Using storage

Save values into storage and once popup gets opened, it gets the values from storage and displays them in the popup.

background.js

chrome.storage.sync.set({ 'dataValue1': 'Some data 1.' });
chrome.storage.sync.set({ 'dataValue2': 'Some data 2.' });

popup.js

function updatePopup() {
    chrome.storage.sync.get(['dataValue1', 'dataValue2'], function (data) {
        document.getElementById("popupElement1").innerText = data.dataValue1;
        document.getElementById("popupElement2").innerText = data.dataValue2;
    });
}    
document.addEventListener('DOMContentLoaded', updatePopup);

popup.html

<html>    
<head>
    <script src="popup.js"></script>
</head>    
<body>
    <p id="popupElement1"></p>
    <p id="popupElement2"></p>
</body>    
</html>

manifest.json

{
    "name": "Background2popup",
    "version": "1.0",
    "manifest_version": 2,
    "description": "This is a demo",
    "browser_action": {
        "default_popup": "popup.html"
    },
    "background": {
        "scripts": [
            "background.js"
        ]
    },
    "permissions": [
        "<all_urls>",
        "storage",
        "tabs"
    ]
}

2) Using chrome.runtime.sendMessage()

Once popup opens, you send a message from popup to background to establish the connection/handshake (otherwise, you would get a 'Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.' if you try to send a message from background to popup and popup isn't open). Once with the connection established, you use sendResponse from background to send the data you wanted to send to popup in the first place.

background.js

chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
    if (request.method == "getStatus") {
        console.log(request.data)
        sendResponse({ method: "peepee", data: "poopoo" })
    }
});

popup.js

chrome.runtime.sendMessage({ method: "getStatus", data: "xxx" }, function (res) {
    document.getElementById("popupElement1").innerText = res.method;
    document.getElementById("popupElement2").innerText = res.data;
return true;
});

popup.html & manifest.json are the same as in the first example

Comments

0

localStorage solution

Because the popup does not have a persistent state, you may want to use localStorage to store the popup state and preload it when popup opens and the storage event to keep track of changes to the state while the popup is open.

Background:

localStorage.setItem('popupData', JSON.stringify({ tabReady: true }));

Popup:

// Load the state from localStorage when popup opens
let popupData = JSON.parse(localStorage.getItem('popupData'));

// Keep track of changes to the popup state while the popup is open
window.addEventListener('storage', (e) => {
  if (e.key === 'popupData') {
    popupData = JSON.parse(e.newValue);
    console.log(popupData.tabReady);
  } 
});

Comments

-1

Use runtime.sendMessage to send messages to background script, and tabs.sendMessage from background to content script.

Please note that you need to specify tab id:

chrome.tabs.query({ active: true }, (tabs) => {
    chrome.tabs.sendMessage(tabs[0].id, { greeting: 'hello' }, (response) => {
        console.log(response);
    });
});

You can find full example and documentation here: https://developer.chrome.com/extensions/messaging#simple

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.