0

From content-script:

chrome.runtime.sendMessage({ type: "getFormatOption" }, function (response) {
    return response === 'csv';
});

I have inspected in console: the value, which is used in SendResponse() from background.js method is OK. The problem is that response is always UNDEFINED. What am I doing wrong?

background.js:

chrome.runtime.onMessage.addListener(
    function (message, sender, sendResponse) {
        switch (message.type) {
            case 'getFormatOption':
                var response = $('input[name=csvOrEnter_radio]:checked', '#csvOrEnter_form').val();
                console.log('formatOption: ' + response);
                sendResponse(response);
                break;
            case 'getFilteringStrategy':
                var response = $('input[name=filteringStrategy_radio]:checked', '#filteringStrategy_form').val();
                console.log('filteringStrategy: ' + response);
                sendResponse(response);
                break;
            default:
                console.error('Unrecognised message: ', message);
        }
    }
);

The idea that I take some values from radiobuttons from my plugin popup.html.

Manifest:

   {
  // default for the latest version of Chrome extensions
  "manifest_version": 2,

  // extension related general info
  "name": "FB Interest Search Tool",
  "short_name": "FB Interest Search Tool",
  "description": "FB Interest Search Tool",
  "version": "1.0.0",

  "default_locale": "en",

  // sets path to popup files
  "browser_action": {
    "default_icon": "img/128.png",
    "default_popup": "popups/popup.html",
    "default_title": "FB Interest Search Tool"
  },

  // sets path to content scripts and when they are injected onto the page
  "content_scripts": [
    {
      "matches": [ "http://*/*", "https://*/*" ],
      "css": [ "styles/styles.css" ],
      "js": [
        "bower_components/jquery.min.js",
        "bower_components/jquery.cookie.js"
      ]
    }
  ],

  // sets path to background scripts
  "background": {
    "scripts": [
      "bower_components/jquery.min.js",
      "bower_components/jquery.cookie.js",
      "bg/background.js",
      "content-scripts/rewriteStorage.js"
    ]
  },

  "permissions": [
    "activeTab",
    "http://*/",
    "https://*/",
    "file:///*/*",
    "<all_urls>",
    "tabs",
    "storage",
    "unlimitedStorage",
    "storage",
    "cookies"
  ],

  "web_accessible_resources": [ "styles/commentblocker_on.css" ]
}
52hertz
  • 342
  • 4
  • 16
  • And what does `background.js` have to do with your `popup.html`? – Xan Sep 30 '16 at 14:19
  • @Xan ('input[name=filteringStrategy_radio]:checked', '#filteringStrategy_form').val(); - it perfectly reads value from my radio buttons. It works nice. I've tested. – 52hertz Sep 30 '16 at 14:20
  • 3
    You're meaning to say that `background.js` is included in your `popup.html`? **\*gasp\*** That's so.. semantically dirty. – Xan Sep 30 '16 at 14:21
  • @Xan Look, that's first time I am dealing with JS and chrome extensions. My problem is to fix some bugs here. code was written by another guy. – 52hertz Sep 30 '16 at 14:23
  • 1
    My point being, if it's not used (exclusively) as a background script, it should be called anything BUT `background.js`. – Xan Sep 30 '16 at 14:24
  • @Xan i agree. But at the present moment I need to fix my 'undefined' problem as fast as possible and forget about debugging someone else's code. – 52hertz Sep 30 '16 at 14:25
  • 1
    Does the error occur when the popup is not shown? A popup can listen to messages only when it's shown. When it's closed its contents and listeners are destroyed. – wOxxOm Sep 30 '16 at 14:25
  • Does `console.log('formatOption: ' + response);` in background.js log a value? – punkrockbuddyholly Sep 30 '16 at 14:25
  • @MrMisterMan yes. It does. – 52hertz Sep 30 '16 at 14:27
  • @wOxxOm Both: when shown and when not are failed. – 52hertz Sep 30 '16 at 14:28
  • @wOxxOm Just open F12 mode for your popup.html. And u gonna see console. Isn't that all right? – 52hertz Sep 30 '16 at 14:34
  • This is wrong. Your background page has no *direct* access to popup's DOM (you'll have to use [chrome.extension.getViews](https://developer.chrome.com/extensions/extension#method-getViews)). Check the background page debugger: [Where to read console messages from background.js in a Chrome extension?](//stackoverflow.com/a/10258029). See the [extension architecture](https://developer.chrome.com/extensions/overview#arch). – wOxxOm Sep 30 '16 at 14:36

1 Answers1

2

Problem 1: it's called background.js.

I'm not even remotely joking. Well maybe a little.

Since it's included BOTH in the popup and as a background script, there are 2 message listeners registered. And only one can answer:

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.

Guess which gets to answer first? My bets are on the background, since it registered the listener first.

While you still see the listener execute in the popup if you try to debug, its sendResponse is ignored because the background already answered.

This one's easy to fix: make a copy, call it popup.js, and keep only relevant logic in both. Don't include the same file in both places unless you're 100% certain code needs to run in both.

Problem 2: Popup is mortal.

When the popup is closed — it's dead, Jim. It simply does not exist: neither the listener, nor the radiobuttons. Therefore, it cannot answer the message.

Fixing this requires reworking the architecture. The only 2 places that can provide storage you can query at any time are:

  • Background page. It needs to hold the state in a way other than selected element, and the popup needs to inform about the change of state.
  • chrome.storage API. Both the popup and the content script can read/write to it.

For options, the second one is preferable.

Xan
  • 74,770
  • 16
  • 179
  • 206
  • All right. Give me an advice please. I got only 2 radio buttons and I need to read their values at certain moment (after user clicks a button on my popup.html!). What is THE SIMPLEST way to achieve this? – 52hertz Sep 30 '16 at 14:38
  • Save their value to `chrome.storage.local` in the popup and read it in the content script. [This example](https://developer.chrome.com/extensions/optionsV2#step-2) and [documentation](https://developer.chrome.com/extensions/storage) might help. – Xan Sep 30 '16 at 14:40
  • [This](https://stackoverflow.com/questions/31111721/pass-a-variable-from-content-script-to-popup/) may also be of big help, even though it's a long read and slightly different problem. – Xan Sep 30 '16 at 14:44
  • @OK. All the logic is done in my popup.js. That's content-script, accessing the current page DOM. I take some values from the page, sort them, filter, etc. At certain moment I need toose filtering strategy and second parameter. How can I noify my background.js, which can access to the popup.html `'s`, to read necessary values and save them to the chrome.storage.local? – 52hertz Sep 30 '16 at 14:47
  • _"which can access to the popup.html ``'s"_ No, it cannot access them. You should pre-emptively save the values as soon as they change in the popup. Seems like there is a lot of work attaching actual logic of save/restore to the popup radiobuttons. – Xan Sep 30 '16 at 14:49
  • How can I save values as soon as the get changed? Who must be responsible for that? What kind of script? Who can access my popup.html directly? – 52hertz Sep 30 '16 at 14:51
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/124654/discussion-between-xan-and-52hertz). – Xan Sep 30 '16 at 14:51