2

I want to send data from content.js to popup.js, The content.js is just grabbing the document title and then passing it to the popup.js.

So then popup.js will change the popup.html DOM.

manifest.json:

    {
      "browser_action": {
        "default_icon": {
          "64": "icons/icon64.png"
        },
        "default_popup": "popup.html"
      },
      "content_scripts": [
        {
          "matches": [
            "<all_urls>"
          ],
          "js": [
            "content.js"
          ],
          "run_at": "document_end"
        }
      ],
      "permissions": [
        "tabs",
        "activeTab",
        "*://*/*"
      ]
    }

popup.html:

    <html>
    <body>
      <span class="info">TAB TITLE</span>
      <script src="popup.js"></script>
    </body>
    </html>

content.js:

    console.log('CONTENT IS RUNNING')

    var getTitle = function() {
      return document.title
    }

    chrome.runtime.sendMessage(getTitle());

popup.js:

    console.log('POPUP IS RUNNING')

    chrome.runtime.onMessage.addListener(
      function(response, sender, sendResponse) {

        var title  = response;
        return title;
      }
    );

    document.querySelector('.info').innerHTML = title; // error: title is not defind

In popup.js the response parameter is not giving the document title.

0xsh
  • 1,395
  • 3
  • 10
  • 18

1 Answers1

3

The popup runs (and exists) only when it's shown.
The declared content script runs whenever the web page is loaded.
These two events may happen at any time so there's no guarantee they coincide.

  • Solution 1: don't declare the content script, instead run it manually

    popup.js:

    chrome.tabs.executeScript({code: 'document.title'}, ([title]) => {
      document.querySelector('.info').textContent = title;
    });
    

    Note how we use textContent here which is safe, unlike innerHTML which can lead to XSS (it'll be blocked by default but not if you've relaxed the default CSP).

  • Solution 2: read the tab title directly via chrome.tabs API

    popup.js:

    chrome.tabs.query({active: true, currentWindow: true}, ([tab]) => {
      document.querySelector('.info').textContent = tab.title;
    });
    

manifest.js for both solutions:

{
  "browser_action": {
    "default_icon": {
      "64": "icons/icon64.png"
    },
    "default_popup": "popup.html"
  },
  "permissions": ["activeTab"]
}

Note we only need "activeTab" permission so no permissions warning is displayed at installation.

wOxxOm
  • 65,848
  • 11
  • 132
  • 136
  • Thanks for your answer, so now I just attached a event listener(DOMTitleChanged) to the tab, I want listen for the changes and then display a new title each time it's going to change, but now I can not access the html DOM. tab.addEventListener('DOMTitleChanged', () => { ... } – 0xsh Nov 17 '18 at 11:49
  • As you can see in the documentation, the [`tab` object](https://developer.chrome.com/extensions/tabs#type-Tab) doesn't have that method. Use chrome.tabs.onUpdated.addListener instead, but make sure to check the documentation first, and usage examples. In case of problems, ask a new question because it's a separate issue. – wOxxOm Nov 17 '18 at 11:54