Reputation: 36
I’m working on a simple time tracker extension. When I started out I had all the js code in one popup.js file, but I found that when the extension pop-up was closed the timer stopped running. I came across the use of a background script to use in junction with the already created popup.js script of mine. What I’ve now done is that I have the evenListener logic from the HTML page in the popup.js, I then use the browser.runtime.sendMessage to send the data to the background.js script to handle the timer. Is this a correct setup or should I do it differently?
I can’t figure out how to pass the click event from the post to the background script, and then use the eventListener in the background script to start the timer.
Here is my public GitHub repo for the timetracker extension. https://github.com/krullmizter/timetracker
Upvotes: 1
Views: 616
Reputation: 13
Firstly, you should avoid using innerHTML because the add-on might get rejected if you try to upload it to the Firefox AMO website. Instead, use textContent.
As for your question, the background script can’t directly update the DOM of your popup. You could do this by sending messages from the background script to the popup script.
That said, one of the big benefits of using the Alarms API instead of Javascript timeouts/intervals is that your popup should be able to access the alarms that you created, even if they were made by the background script. So for your popup page to see what alarms you have running, it doesn’t need to ask the background script for anything.
For example, if you wanted to show the live timer of your script, you could load the list of alarms when your popup loads and then just use Javascript intervals on the popup page to keep the timer ticking in the UI and then register a listener on the popup page for when an alarm is fired, so that the popup can remove it from the UI.
Updating the popup UI using the background script is doable using messages, but in my experience it can get pretty complex.
As a side note, if you are sending a lot of messages between the popup and background script, sometimes it’s a good idea to use port-based messaging instead of just the regular runtime messaging APIs.
I’m not sure Alarms can fire every second, at least in Chrome when you release the addon, it’s capped at 1 per minute. That’s why alarms has minute-granularity: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/alarms/create
Also, why does it need to run every second? Sounds like a bad design. Unless it’s for an UI element showing “seconds” :slight_smile:.
Also - alarms are global:
And lastly - background script is running all the time, so put there things that should run all the time. Popup runs when it’s opened, so all UI related things should be in the popup code. See also: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Anatomy_of_a_WebExtension
Upvotes: 1
Reputation: 356
In your notifyBackgroundPage() function in the popup.js file, you don’t need to send the HTML button to the background script. Instead, you’d probably want something like this:
const sending = browser.runtime.sendMessage({
action: startBtn.id
});
sending.then(handleRes, handleErr);
That will send the background script an object that has a message object with “start” as the action. Then, in your background script, you can use a switch statement (or if/else statements if you really want to) to call the appropriate function.
The click event listeners need to all be in the popup.js file and each onclick should send a message to the background to perform the desired action.
So your background script would be become something like this:
function popupMsgReceived(msg, sender, sendRes) {
console.log("Msg received", msg);
switch (msg.action) {
case "start":
handleStart();
break;
case "stop":
handleStop();
break;
case "reset":
handleReset();
break;
}
sendRes({response: "Response from background script"});
}
browser.runtime.onMessage.addListener(popupMsgReceived);
// Set the initial clock values
let hr = 0;
let min = 0;
let sec = 0;
let interval;
/*
* Three even listeners for the three buttons
* The startBtn event will set an interval to run each 1000ms (1sec) and run the startTimer function
* timerStartedAt function will also run och the btn event
*/
function handleStart() {
timerStartedAt();
clearInterval(interval);
interval = setInterval(startTimer, 1000);
}
function handleStop() {
clearInterval(interval);
}
function handleReset() {
clearInterval(interval);
hr = 0;
min = 0;
sec = 0;
timer.innerHTML = '00:00:00';
displayDate.innerHTML = ''
}
As far as for setting the timer, I’d recommend using the Alarms API instead of using Javascript timeouts or intervals. Alarms are a lot more stable for browser add-ons. Another be positive to that is that you could create and edit alarms from the popup.js without the need to send messages and the alarm will stay alive even after the popup page is closed.
Another thing to think of future-wise is that manifest version 3 will eventually be the standard in Firefox. That version of the API does not have persistent background pages. Therefore, Javascript timeouts and intervals won’t work in background scripts at that point and you will need to change your code later.
Upvotes: 6