Completely lost on how to save extension popup window content
Similar to a web page, the popup's (or an options/settings page's) scope is created when it is shown and destroyed when it is no longer visible. This means that there is no state stored within the popup itself between the times that it is shown. Any information which you desire to persist after the popup is destroyed, you will need to store somewhere else. Thus, you will need to use JavaScript to store any state which you desire to have be the same the next time the popup is opened. Each time the popup is opened, you will need to retrieve that information and restore it to the DOM. The two most commonly used places are a StorageAreaMDN, or the background page.
Where you store the information will depend on how long you want the data you store to persist, and where you want the data to be seen.
The general locations where you could store data include (other possibilities exist, but the followin are the most common):
- The background page if you want the data to exist only until Chrome is closed. It will not exist once Chrome is restarted. You can send the data to the background page through a couple/few different methods, including message passingMDN, or directly changing values on the background pageMDN. Data stored in the StorageArea (the two options below) is also available to the background page, and content scripts.
chrome.storage.local
MDN if you want the data to persist on the local machine across Chrome being closed and restarted.chrome.storage.sync
MDN if you want the data shared with all instances of Chrome which use the current Chrome account/profile. The data will also persist until changed. It will be available through Chrome being closed and restarted. It will be available on other machines using the same profile.window.localStorage
: Prior to the existence ofchrome.storage
it was popular to store data for the extension inwindow.localStorage
. While this will still work, it is generally preferred to usechrome.storage
.
One of the advantages of using a chrome.storage
StorageAreaMDN is that the data is directly available to all portions of your extension without the need to pass the data as a message.1
Your current code
Currently your code is not storing the URLs that are entered anywhere other than in the DOM of the popup. You will need to establish a data structure (e.g. an array) in which you store the list of URLs. This data can then be stored into one of the storage locations mentioned above.
Google's example on the Options documentation page2, MDN shows storing chrome.storage.sync
and restoring values into the DOM when the options page is displayed. The code used in this example can for the options page can work exactly as-is for a popup by just defining its HTML page as the default_popup
for a browser_action
. There are many other examples available.
Unfortunately, without more specifics from you as to what you desire, it is difficult to give you specific code. However, couple of suggestions to head in the direction you need to go are:
- Refactor your code so you have a separate function that you call with a URL as a parameter which just adds this URL to the list you have in the DOM (e.g.
addUrlToDom(url)
). This function will be used when the user adds a URL and when the URLs are restored when the page loads. Store your list of URLs in an array (e.g.
urlList
). This array will be what you save into the storage location outside of your popup. You will read this array from that storage location in yourDOMContentLoaded
handler and use the refactoredaddUrlToDom()
function to add each value. Restoring it into the DOM could look something like:urlList.forEach(function(url){
addUrlToDom(url);
});
Storing your data in chrome.storage.local
Assuming you want to store the URLs on the local machine across Chrome shutdown/restart (i.e. use chrome.storage.local
), you code could look something like:
manifest.json changes to permissions
only:
"permissions": [
"tabs",
"storage"
]
popup.js:
// global variables
var urlList=[];
document.addEventListener('DOMContentLoaded', function() {
getUrlListAndRestoreInDom();
// event listener for the button inside popup window
document.getElementById('button').addEventListener('click', addLink);
});
// fetch the URL of the current tab, add inside the window
function addLink() {
chrome.tabs.query({currentWindow: true,active: true}, function(tabs) {
// tabs is an array so fetch the first (and only) object-element in tab
var url = tabs[0].url;
if(urlList.indexOf(url) === -1){
//Don't add duplicates
addUrlToListAndSave(url);
addUrlToDom(url);
}
});
}
function getUrlListAndRestoreInDom(){
chrome.storage.local.get({urlList:[]},function(data){
urlList = data.urlList;
urlList.forEach(function(url){
addUrlToDom(url);
});
});
}
function addUrlToDom(url){
// change the text message
document.getElementById("div").innerHTML = "<h2>Saved pages</h2>";
//Inserting HTML text here is a bad idea, as it has potential security holes when
// including content not sourced entirely from within your extension (e.g. url).
// Inserting HTML text is fine if it is _entirely_ sourced from within your
// extension.
/*
// format HTML
var html = '<li><a href=' + url + " target='_blank'>" + url + '</a></li>';
//Add URL to DOM
document.getElementById("list").insertAdjacentHTML('beforeend',html);
*/
//Build the new DOM elements programatically instead:
var newLine = document.createElement('li');
var newLink = document.createElement('a');
newLink.textContent = url;
newLink.setAttribute('href',url);
newLink.setAttribute('target','_blank');
newLine.appendChild(newLink);
document.getElementById("list").appendChild(newLine);
}
function addUrlToListAndSave(url){
if(urlList.indexOf(url) === -1){
//URL is not already in list
urlList.push(url);
saveUrlList();
}
}
function saveUrlList(callback){
chrome.storage.local.set({urlList},function(){
if(typeof callback === 'function'){
//If there was no callback provided, don't try to call it.
callback();
}
});
}
- The exception to this is scripts which you insert into the page context. The page context is something you will probably not be running scripts in. To do so you have to use a content script (where your StorageAreaMDN data is directly available) to insert a
<script>
tag into the DOM of a web page. This can be a bit complex, any you probably don't need to be concerned about it. It is mentioned here merely because there is a possible exception to the statement that the StorageAreaMDN data is available to all areas of your extension. - The example in the Chrome documenation works just fine on Firefox. Yes, Firefox supports both
chrome.*
, using callbacks, andbrowser.*
, using promises.
How to get chrome storage to save on chrome extension popup close
beforeunload
event is ignored for the popup shown bybrowser_action
orpage_action
.unload
won't wait for the asynchronouschrome.storage
to complete so the data won't be stored
Based on this several solutions are possible.
Autosave on any change.
This is the preferable and modern user-friendly solution. You can give the elements an
id
that's equal to their name inchrome.storage
like<input type="text" id="userName" class="storage">
.const STORAGE_SELECTOR = '.storage[id]';
let debounceTimer;
document.addEventListener('change', saveOnChange);
document.addEventListener('input', saveOnChange);
function saveOnChange(e) {
if (e.target.closest(STORAGE_SELECTOR)) {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(doSave, 100);
}
}
function collectData() {
const data = {};
for (const el of document.querySelectorAll(STORAGE_SELECTOR))
data[el.id] = el.type === 'checkbox' ? el.checked : el.value;
return data;
}As for
doSave()
function, either simply overwrite the current options data in storagefunction doSave() {
chrome.storage.sync.set(collectData());
}or save under a separate
autoSave
and check it the next time the popup is shown:function doSave() {
chrome.storage.sync.set({autoSave: collectData()});
}
function loadFromStorage() {
chrome.storage.sync.get(data => {
if (data.autoSave) data = data.autoSave;
for (const [id, value] of Object.entries(data)) {
const el = document.getElementById(id);
if (el) el[el.type === 'checkbox' ? 'checked' : 'value'] = value;
}
});
}
loadFromStorage();Save the data in
unload
event directly in the backround script's JavaScriptwindow
object e.g.chrome.extension.getBackgroundPage().popupData = collectData()
.It's bad because it requires a persistent background page (or a temporarily persistent page) and because Chrome moves away from
unload
events in general. The data may be easily lost on a crash of the extension process or of the browser itself, it might be lost if the browser was closed by the user.
Saving data from Chrome extension popup to a rate-limited backend
you don't need to use service worker
Do this:
- if you don't have a background script,you need to add one
- add a
chrome.runtime.onMessage.addListener
in the background script - do not fire
save
option in the popup. listen to thekeyup
event in the popup, and send an event to the background with everykeyup
event. - do your
wait 300ms and send data to firebase
stuff in the background
if you do not familiar with chrome.runtime.onMessage
and chrome.runtime.sendMessage
, you need to read the SDK documentation.
How to keep Google Chrome Extension popup open?
As a user, you currently cannot force the the popup to stay open. That is a UI decision the UI team made. If you want to want to force a setup, you can have other way to show this by changing the popup icon, open a new tab when it requests, or new popup view for registration.
As a developer, inspect the popup, and it will stay open.
How to maintain the state of button in Chrome extension pop up once it is clicked.(JavaScript)
If I am reading your code correctly, you are using 'count' like a boolean to indicate if the button is enabled or not. You should be able to achieve saved state by calling:
var obj = {};
obj['buttonState'] = count;
chrome.storage.sync.set(obj, function() {
// this called after the save
});
To retrieve, you simply do the reverse:
chrome.storage.sync.get('buttonState', function(data) {
// this is called after the retrieve.
count = data['buttonState'];
});
how not to lose data when closing and opening chrome extension popup
When a popup is closed, its HTML document is completely unloaded; you need to restore state when your popup loads every time it's opened. No way around that.
As you mention, it's possible to persist state information in the background page while the browser is running. But it's still temporary storage; you need to use persistent storage to save whatever state you need to save.
The most obvious (and recommended) choice is chrome.storage
API, specifically designed for this purpose. You can also use Web APIs such as localStorage
or IndexedDB
if you like.
Chrome Extensions - Changing the popup window
You should be looking at chrome.browserAction
API.
Specifically:
chrome.browserAction.setPopup(object details)
Sets the html document to be opened as a popup when the user clicks on the browser action's icon.
So, to set your popup, you would call it like this:
chrome.browserAction.setPopup({popup: "logged_in.html"});
You can do this when you understand that the user is logged in; however, you may want to restore this state when extension is restarted. To do so, you should save the fact that you are logged in (or out) in persistent storage and call this function on initialization. An event script is a good place to do so.
// wherever you can do this in your code
function login_success() {
/* ... */
chrome.storage.local.set({logged_in: true});
chrome.browserAction.setPopup({popup: "logged_in.html"});
}
function login_failure() {
/* ... */
chrome.storage.local.set({logged_in: false});
chrome.browserAction.setPopup({popup: "default.html"});
}
// This goes into eventPage.js and executes once on extension load
chrome.storage.local.get("logged_in", function(data) {
if(data.logged_in)
chrome.browserAction.setPopup({popup: "logged_in.html"});
});
Related Topics
Limited Parallelism with Async/Await in Typescript/Es7
Closure in JavaScript - Whats Wrong
How to Match Multiple Occurrences with a Regex in JavaScript Similar to PHP's Preg_Match_All()
JavaScript Validation for Empty Input Field
How to Get the Status Code from an Http Error in Axios
What the Difference of This.State and This.Setstate in Reactjs
How to Check If Page Exists Using JavaScript
How to Programmatically Force an Onchange Event on an Input
How to Check If the Array of Objects Have Duplicate Property Values
How to Read from Chrome's Console in JavaScript
Console.Log Showing Only the Updated Version of the Object Printed
Should an Async API Ever Throw Synchronously
How to Set Multipart in Axios with React
Intercepting Call to the Back Button in My Ajax Application
How to Make Recaptcha a Required Field