1

I am making a simple Chrome Extension that contains a simple on/off switch, see below:

enter image description here

Whenever I enable this switch, I want it the new on/off state to reflect in all other active tabs/new tabs/chrome instances.

This is not currently happening, if I enable it in one tab, it is still disabled in another.

My approach was as follows:

  1. Add an event listener to the switch

  2. Toggle the value, and store the new value in chrome.storage

  3. Send a chrome.runtime message to the background script, and update all chrome instances.

The problem: Whenever I toggle the switch, I receive the following error:

enter image description here

Also, for some reason my background.js never initializes, perhaps related to the error above.

Here is my

background.js (listen for message to be sent, so that I can update other tabs)

console.log('?! loading background js !?') // this never fires :(

// Whenever a message has been passed, such as toggling the enable/disable switch, communicate that with other Chrome tabs/instances.
chrome.runtime.onMessage.addListener(
    function (request, sender, sendResponse) {
        // todo: update all chrome tabs with new switch state
        console.log('reached Background message handler!')
    }
);

popup.js (listens for click events, executes the script that toggles the chrome.storage toggle value)

// when the toggle is updated, run our script
document.getElementById('enable-site-blocking').onclick = executeBlocking;

function executeBlocking() {
    chrome.tabs.executeScript({
        code: "setToggleState()"
    });
}

content-script.js (executes when the toggle button is clicked, setting storage state, and sending runtime message)

setToggleState();

function setToggleState() {
    chrome.storage.sync.get(['isExtensionActive'], function (storage) {
        const invertedState = !storage.isExtensionActive;
        chrome.storage.sync.set({
            isExtensionActive: invertedState
        });

        console.log('sending message')

        // send an update to all other Chrome processes
        chrome.runtime.sendMessage({
            greeting: "hello"
        }, function (response) {
            console.log("done sending message");
        });
    });
}

So, my questions are as follows:

  1. Is my approach the correct one, for maintaining the state of the toggle switch across tabs? If not, what should I change?
  2. What might be the cause of the error shown above?
  3. Why does my background.js never execute?

Sorry if it is something simple, I am new to Chrome Extensions!

For additional context, here are the content_scripts/background in my manifest.json enter image description here

Thank you for any help

Edon
  • 1,116
  • 2
  • 22
  • 47
  • thanks @elegant-user , it leads to a new error: Could not establish connection. Receiving end does not exist. I'm definitely sending a message with chrome.extension.onMessage. I just found out how to debug the background.js, and there are no errors, and the "loading background js!" is firing – Edon Mar 07 '20 at 05:10
  • I think I'm onto the answer after finding the debug for background, your response incidentally is leading me to an answer! Thanks – Edon Mar 07 '20 at 05:17
  • as a revised question @elegant-user , if you feel like answering. Do you think I should toggle the button in the Background.js? Or should I do it in my content-script.js. Feel free to post an answer as a response so I can accept – Edon Mar 07 '20 at 05:19
  • or rather, should I toggle the button in my popout.js, or my content-script. Not sure what is best practice here – Edon Mar 07 '20 at 05:36
  • chrome.extension.onMessage has been deprecated 5 years ago, please don't spread the outdated info. – wOxxOm Mar 07 '20 at 06:00

1 Answers1

5

There's no need for background.js or messaging, simply set the value in popup.js and use chrome.storage.onChanged listener in the content script.

popup.js:

function setToggleState() {
  chrome.storage.sync.get('isExtensionActive', storage => {
    chrome.storage.sync.set({
      isExtensionActive: !storage.isExtensionActive,
    });
  });
}

background.js: not necessary

content.js:

chrome.storage.sync.get('isExtensionActive', storage => {
  toggleSomething(storage.isExtensionActive);
});

chrome.storage.onChanged.addListener(changes => {
  if (changes.isExtensionActive) {
    toggleSomething(changes.isExtensionActive.newValue);
  }
});

function toggleSomething(state) {
  console.log('new state:', state);
  // ........... do something
}

Notes:

  • The background script runs in a separate hidden background page which has its own devtools.

  • The popup is also a separate page in a separate window so it has separate devtools: right-click inside the popup, then click "inspect".

wOxxOm
  • 65,848
  • 11
  • 132
  • 136
  • this is an incredibly concise answer, and it cleared up many misconceptions I had. I'm still investigating myself, but I edited the topic with the result of your suggestions. Running into an issue where the state resets anytime I click outside of the extension, and other tabs are still not updating. Thank you again for the help. – Edon Mar 07 '20 at 06:30
  • Well, you need to read the current state at the start of popup.js and set the DOM element accordingly. The popup's execution environment is recreated each time it's shown and destroyed when hidden. – wOxxOm Mar 07 '20 at 07:49