Search code examples
javascripthtmlgoogle-chrome-extensionfrontendmessaging

How to solve Messaging Error occuring from Background Script to another script?


I am trying to send some selected text from the current page to an HTML page. Since, I can not do it directly, I am using message passing: content script to background script, then background script to the HTML page. But get error if the HTML is not open already, even then I get an error first time:

background.js:1 Uncaught (in promise) Error: Could not establish connection. Receiving end does not exist.

If I close the page, then run again, this error will keep happening.

What is the solution ?

My code is given below:

popup.js

chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
console.log("from popup = \n"+request.bg);
})  

background.js

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

chrome.tabs.create({url: 'popup.html'});
chrome.runtime.sendMessage({bg: request.exc})
                                                                              })

content.js

string=[];
function doc_keyUp(e) {
if (getSelectionText() != "")  {
if (e.key === '1') {
    string=getSelectionText();
    chrome.runtime.sendMessage({exc: string});
            
                   } 
                                }
                      } // doc_keyUp(e)
console.log('The program has started!!!');  
// register the handler 
document.addEventListener('keyup', doc_keyUp, false);                              

function getSelectionText() {
    var text = "";
     text = window.getSelection().toString();
    if (window.getSelection) {
        text = window.getSelection().toString();
    } 
    else if (document.selection && document.selection.type != "Control") {
        text = document.selection.createRange().text;
    }
    return text;    
}

popup.html

<html>
<script src="popup.js">
</script>
</html>

I am doing this to buid a chrome extension, so if required then:

manifest.json

{
  "name": "",
  "version": "1.0",
  "description":"",
  "manifest_version": 3,
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"]
    }
  ],
  "action": {
    "default_title": "T"
  },
  "background":{
    "service_worker": "background.js"
  },
  "permissions": ["tabs","storage"]
}

Post Script:

  1. Is there an alternative way to send data directly from content script to script of an HTML (e.g. here popup.js is such script) without going through background script?
  2. Is there a to get a variable from background script without message passing to any other script? I saw solutions using chrome.extension.getBackgroundPage() but it does not work anymore after manifest v3. Is there anything else?

Solution

  • You can use localStorage to send and get items. If your item not included in your localStorage you can initialize it.

    content.js

    localStorage.setItem("bg", "#000000"); // <- You can send json or whatever you want
    

    popup.js

    var bg = localStorage.getItem("bg");
    

    or you can use chrome.storage API

    content.js

    chrome.storage.local.set({bg: value}, function() {
      console.log('Value is set to ' + value);
    });
    

    popup.js

    chrome.storage.local.get(['bg'], function(result) {
      console.log('Key is ' + result.bg);
    });
    

    Add storage to permissions.

    And you need to add to your extension permissions (manifest file ) But you should be careful because

    confidential user information should not be stored! The storage area isn't encrypted.

    Working Code:

    content.js

    string=[];
    function doc_keyUp(e) {
        if (getSelectionText() != "")  {
            if (e.key === 'Enter') { 
                string=getSelectionText();
                chrome.storage.local.set({bg: string}, function() {
                    console.log('Bg is set to ' + value);
                });
                chrome.runtime.sendMessage({});
            } 
        }
    } // doc_keyUp(e)
    console.log('The program has started!!!');  
        // register the handler 
    document.addEventListener('keyup', doc_keyUp, false);                              
        
    function getSelectionText() {
        var text = "";
        text = window.getSelection().toString();
        if (window.getSelection) {
            text = window.getSelection().toString();
        } 
        else if (document.selection && document.selection.type != "Control") {
            text = document.selection.createRange().text;
        }
        return text;    
    }
    

    popup.js

    chrome.storage.local.get(['bg'], function(result) {
        alert('Bg is ' + result.bg);
    });
    

    background.js

    chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
        chrome.tabs.create({url: 'popup.html'});
    });
    

    I changed e.key === 'Enter' in content.js for better testing. And I deleted chrome.runtime.onMessage.addListener from popup.js because you will call popup after background.js receive message so you don't need to get message everytime in popup.js.You need to get value once when popup created.

    Selected Text Image:

    enter image description here

    And popup alert:

    enter image description here