Skip to content
Advertisement

Creating and accessing global variable in google chrome extension

All of the information I can find on this is pretty old. Like the title says I am trying to make a global variable in one script and access it from another. The purpose of the extension is to search for a class named “page-title” and then return the innerHTML of that HTML element. Once I get the code working I will specify the URL I want the extension to run on so it’s not constantly running.

After a couple iterations trying to accomplish this in different ways I followed the method explained in this answer but my needs have different requirements and I am receiving the error “Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.” tied to the popup.html. I tried the Unchecked runtime error solution found here but it’s been awhile (~ 7 years) since I’ve dived into any coding and I’m not sure I implemented it correctly. I’ve also tried to pass the value between JS documents is the HTML injection method, but without overriding security defaults in the manifest that doesn’t really work. It also seemed super bootstrappy and I wanted to pass the information in a more conventional way. I tried creating a global variable by simply declaring the variable outside of a function/class/if statement and loading that .js file first, but that was unsuccessful as well.

Manifest

    "name": "P.P. to Sharepoint",
    "version": "1.0.0",
    "description": "Open P.P. client folder in sharepoint",
    "manifest_version": 3,
    "author": "Zach Morris",
    "action":{
        "default_popup": "popup.html",
        "default_title": "Open Sharepoint Folder"
    },
    "background": {
        "service_worker": "background.js"
    },
    "permissions": [
        "activeTab",
        "tabs",
        "scripting",
        "notifications"
    ],
    "content_scripts": [{
    "js": ["contentScript.js"],
    "matches": ["<all_urls>"]
    }]
}

popup.html My popup.html is super simple and really just has a button to press. I included all the .js files in the order I thought necessary

<script src="globalVariable.js"></script>
<script src="contentScript.js"></script>
<script src="popup.js"></script>
<script src="script.js"></script>
<script src="background.js"></script>

globalVariable.js This one is straight forward. I need to pull the client’s name out of the HTML of the page then use it in an API call when I click the button in popup.js This initializes the variable and uses it as place holder.

var clientInfo = {
    name: 'test name'
};

ContentScript.js I only want to run this if importScripts is not undefined. So I threw it in the if statement. Then I make sure I pulled a client name from the page. If not I throw an error message saying no client was found.

if( 'function' === typeof importScripts) {
  importScripts('globalVariable.js');

   addEventListener('message', onMessage);

   function onMessage(e) { 
    
        if(b[0]) {
            clientInfo.name = b[0].innerHTML;
            alert(clientInfo.name + ' was assigned!');
        } else {
            alert('There is no client on this screen ' + 'b[0] is ' + b[0] + " clientInfo = " + clientInfo.name);
        };
    }; 
} else {
    console.log("Your stupid code didn't work. ");
}

popup.js This one pulls up the globalVariable.js to use the clientInfo. and makes a call to the button in background.js

if( 'function' === typeof importScripts) {
   importScripts('globalVariable.js');
   addEventListener('message', onMessage);

   function onMessage(e) { 
      const text = clientInfo.name;
      const notify = document.getElementById( 'myButton' );

      notify.addEventListener( 'click', () => {
        chrome.runtime.sendMessage( '', {
          type: 'notification',
          message: text });
        
      } );
   }    
}

background.js Same thing here. I import the globalVariable script to use the global variable. The notification will eventually be replaced with the API call when the rest of the code is working properly. I probably don’t need to import the script here to access the variable because I can mass it with the event listener in popup.js, but I put it in here out of desperation.

if( 'function' === typeof importScripts) {
   importScripts('globalVariable.js');
   addEventListener('message', onMessage);

   function onMessage(e) { 
     // do some work here 
     chrome.runtime.onMessage.addListener( data => {
  if ( data.type === 'notification' ) {
          chrome.notifications.create(
              '',
              {
                  type: 'basic',
                  title: 'Notify!',
                  message: data.message || 'Notify!',
                  iconUrl: 'notify.png',
              }
          );
          console.log("sent notification");
  };

});
   }    
}

Advertisement

Answer

You can have the popup.js listen for a button click and content.js handle all the logic of finding the correct element.

popup.js

document.querySelector('#btn').addEventListener('click', () => {
  chrome.tabs.query({ active: true, currentWindow: true }, (tabs) =>
    chrome.tabs.sendMessage(tabs[0].id, { command: 'getClientName' })
  );
});

content.js

chrome.runtime.onMessage.addListener((msg, sender, response) => {
  if (msg.command === 'getClientName')
    findClientName(document.querySelectorAll('h3.page-title'));
});

Example of findClientName function:

const findClientName = async (element) => {
  let clientName;
  if (element.length > 0) {
    element.length === 1
      ? (clientName = setClientName(element[0]))
      : handleMultipleElements(element);
  } else {
    handleNoClientNameFound();
  }
  clientName ? await makeAPIRequest(clientName) : null;
};
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement