Passing message from background.js to popup.js
Asked Answered
S

5

38

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!

Spanos answered 4/9, 2012 at 14:15 Comment(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.Kepner
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 ?Komatik
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).Kepner
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 :(Komatik
Obviously... The popup's view is only active when the popup is visible. If functionality has to survive the lifetime of the popup, you should move it to the background page.Kepner
chrome.extension is deprecated since Chrome v58, use chrome.runtimeMujik
"Obviously" is also deprecated and should be avoided.Tavy
The popup up does not have a persistent state. One solution would be to store the popup state in localStorage, so it can be easily preloaded, and then use storage event to keep track of changes to the state while popup is open (which is the equivalent of sending a message to the popup). I have posted an answer below.Pincer
L
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.

Latoya answered 19/4, 2017 at 3:25 Comment(3)
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 @LatoyaMacrobiotics
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. #13547278Latoya
I did exactly the same by using tabid before see this.Thanks @Latoya for another wayMacrobiotics
C
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.

Cordierite answered 22/8, 2016 at 8:44 Comment(2)
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 methodsDamron
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 fileFrater
P
9

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

Photo answered 7/11, 2020 at 21:0 Comment(0)
P
1

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);
  } 
});
Pincer answered 22/6, 2021 at 7:53 Comment(0)
S
-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

Spinks answered 26/1, 2017 at 15:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.