I’m learning how to make chrome extensions. I have a content script that will obtain some data and I want to pass them to the popup.html page to display them on the popup DOM. I’ve read about the message passing in the Chrome documentation but I’m unable to make it work. Can anyone help me?
My code:
content script file: main.js
(function($){ $(document).ready(function(){ console.log('Extension Started!'); var el = $(document).find('#stories_tray'); var child = el.find('._827c'); $.each(child, function(i){ var div = $(child[i]) .find('._7h4p') .attr('data-onkeypress'); var d = JSON.parse(div); if( typeof d[0].a != 'undefined' ){ console.log(d[0].a[0].preloadImageURIs[0]); var l = d[0].a[0].preloadImageURIs[0]; chrome.runtime.sendMessage({imageURIs: l}, function(response) { console.log(response.farewell); }); } }); }); }(jQuery));
popup javascript file: popup.js
// window.onload = function(){ // $('.spinner-grow').delay('300') // .css({'transition':'ease-out','display':'none'}); // } (function($){ $(document).ready(function(){ console.log('Extension Started!'); chrome.runtime.onMessage.addListner(function(request, sender, sendResponse){ console.log(sender.tab ? "from a content script:" + sender.tab.url : "from the extension"); console.log(request.imageURIs); sendResponse({farwell: "ok"}); }); }); }(jQuery));
Maybe I’m doing something wrong with the code.
I get this errors in the console:
// content script console error
Error handling response: TypeError: Cannot read property ‘farewell’ of undefined
//popup.js console error
jQuery.Deferred exception: chrome.runtime.onMessage.addListner is not a function TypeError: chrome.runtime.onMessage.addListner is not a function:
Uncaught TypeError: chrome.runtime.onMessage.addListner is not a function
UPDATE
I’ve managed how to pass the message from the content script to the popup.js but I need a way to hold the message until the user click on the extension icon. How can I achieve also this?
Advertisement
Answer
In general, it will not work to send a message from a content script to a popup unless you know the popup is open: the popup does not exist until you open it.
Given this, it will likely be most decoupled to have your content script send its message to a persistent background (which is the default btw) and serve as the repository for your messages until the popup requests them.
background.js
const messageQueue = []; chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { // Arbitrary string allowing the background to distinguish // message types. You might also be able to determine this // from the `sender`. if (message.type === 'from_content_script') { messageQueue.push(message); } else if (message.type === 'from_popup') { sendResponse(messageQueue); } });
Now from content script, send chrome.runtime.sendMessage({imageURIs: l, type: 'from_content_script'}...
and from the popup send
chrome.runtime.sendMessage({type: 'from_popup'}, (response) => { // do stuff with response (which will be the value of messageQueue // sent from background.js). });
Of course the strings ‘from_popup’ and ‘from_content_script’ mean nothing; they are just there for clarity.
If you need the popup to initiate the flow, you will need to:
- send a message from the popup
- to the background, to send a message to the content scripts
- which should respond to the background
- which should respond to the popup