0

I'm doing a Chrome extension and I need the action button to show a badge text "ON" when it is active, and hide this badge when it is disabled. You toggle this state clicking on the action button. I've seen there are other posts trying to do the same in certain way, and there may be another solution, but I also would like to understand why my solution is not behaving in the way I want, specifically to understand how to handle chrome.action.getBadgeText, which is what I'm using to toggle the state of the button. I think it behaves as a promise and that this asynchronous behaviour is causing that the button toggle every two clicks, instead of with only one click. I mean, what I get is if you click twice the button it toggles, but I need to toggle with only one click. This is the code:

event.js relevant code:

let badgeStatus = "";

chrome.action.onClicked.addListener(() => {
    getBadgeStatus();
    toggleBadgeStatus();
});

function getBadgeStatus() {
    chrome.action.getBadgeText({}, (r) => {
        badgeStatus = r;
        console.log(badgeStatus);
    })
} 

function toggleBadgeStatus() {
    if (badgeStatus != "ON") {
        chrome.action.setBadgeText({text: "ON"}, () => {});
        setAlarm();
        stateDetect();
        console.log("Alarm set")
    } else {
        chrome.action.setBadgeText({text: ""}, () => {});
    }
}

Code updated with the suggestion to use chrome.storage.local:

event.js, running on the background:

var badgeStatus;

chrome.runtime.onInstalled.addListener(() => {
    var badgeStatus = false;
    chrome.storage.local.set({badgeKey: badgeStatus}, () => {});
})

chrome.action.onClicked.addListener(() => {
    badgeStatus = chrome.storage.local.get(['badgeKey'], (result) => {
        badgeStatus = result.badgeKey;
    })

    if (!badgeStatus) {
        chrome.action.setBadgeText({text: "ON"}, () => {});
        badgeStatus = true;
        chrome.storage.local.set({badgeKey: badgeStatus}, () => {});

        setAlarm();
        stateDetect();
        console.log("Alarm set")
    } else {
        chrome.action.setBadgeText({text: ""}, () => {});
        badgeStatus = false;
        chrome.storage.local.set({badgeKey: badgeStatus}, () => {});
        chrome.alarms.clear("video_alarm");
        console.log("Alarm clear")
    }
});
  • The script terminates after 30 seconds so you should use chrome.storage.local instead of `badgeStatus` variable. – wOxxOm Apr 03 '22 at 17:10
  • I will try that, but I'm also curious, when I console.log the status it write it in the console correctly, but if I try to assign it to a variable, it doesn't work, thank you anyway, I will try that solution. – Rodrigo Yanez Apr 03 '22 at 17:13
  • That's because `chrome` API is asynchronous, [more info](/q/23667086). – wOxxOm Apr 03 '22 at 17:24
  • Thank you very much for your help. It is working now – Rodrigo Yanez Apr 03 '22 at 20:40
  • Well, I thought it was working... seems that chrome.storage.local.get is also asynchronous, so I'm getting a similar problem, because this is running on the service worker, and when it goes inactive, I need to retrieve the storage, and I get a promise, which comes later than the click event – Rodrigo Yanez Apr 03 '22 at 22:09
  • The topic I've linked explains the problem and the solutions. In short, you need to move the code that uses the data inside the callback or switch to the await/async syntax. – wOxxOm Apr 04 '22 at 05:21
  • Thank you, I still don't understand well promises, and the different options to handle asynchronous functions, I'm working on it. Surely this post will help. – Rodrigo Yanez Apr 05 '22 at 01:09
  • Thank you very much wOxxOm for your help, this took me almost a week to resolve, but I think I have learned about promises and this is a very important topic. The following post also helped with the solution if anyone has a similar problem: https://stackoverflow.com/questions/37700051/chrome-extension-is-there-any-way-to-make-chrome-storage-local-get-return-so – Rodrigo Yanez Apr 06 '22 at 18:13

0 Answers0