Reputation: 1036
How to access background script objects form a content script inside chrome extension?
In content script I have:
// this will store settings
var settings = {};
// load settings from background
chrome.extension.sendMessage({
name: "get-settings"
}, function(response) {
debugger;
settings = response.data.settings;
});
Inside the background script I have:
var Settings = function() {
var me = this;
// internal, default
var settingList = {
serverUrl : "http://automatyka-pl.p4",
isRecordingEnabled : true,
isScanEnabled : true
};
this.get = function( key ) {
return settingList[key];
};
this.set = function( key , value ) {
if (settingList[key] != value) {
var setting = {};
setting[key] = value;
chrome.storage.sync.set(setting, function() {
settingList[key] = value;
});
}
return true;
};
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
if (request.name == 'get-settings') {
sendResponse({
data : {
settings : settings
}
});
return true;
}
});
var settings = new Settings();
Messaging works, i mean response is send but returned object is empty. Do you know how to solve that?
EDIT Based on your comments and answer will try to add different light to my question.
The actual problem is: How to access background "model" from content script.
Lets assume that content script continuously responds to page DOM changes. Any time changes are detected some processing is made inside content script. But this processing is depended on extension setting. Those setting can be set via page action popup script which informs background model what those settings are.
So, any time page is processed with content script it should be aware of current settings stored inside background script.
As already described pulling settings from background is an asynchronous process, so i need a callback for further processing inside content script. Further processing must wait for settings (so this should be handled synchronously?).
It's hard for my to imagine what program flow should look like in this case.
Upvotes: 0
Views: 2359
Reputation: 77523
It would probably make more sense to have another instance of Settings
in your content script.
After all, chrome.storage
API is available in content scripts.
Of course, you need to watch for changes made in other parts of the extension - but you should be doing so anyway, since you're using chrome.storage.sync
and its value can change independently by Chrome Sync.
So, proposed solution:
chrome.storage.onChanged
and process changes to update your settingList
as needed.Storage
logic to a separate JS "library", e.g. storage.js
storage.js
in your content script and use it normally.You may also want to adjust your storage logic so that saved data is actually taken into account - right now it's always the default. You can do something like this:
var defaultSettingList = {
serverUrl : "http://automatyka-pl.p4",
isRecordingEnabled : true,
isScanEnabled : true
};
var settingList = Object.assign({}, defaultSettingList);
chrome.storage.sync.get(defaultSettingList, function(data) {
settingList = Object.assign(settingList, data);
// At this point you probably should call the "ready" callback - initial
// load has to be async, no way around it
});
Upvotes: 0
Reputation: 1632
sendMessage doesn't transfer the object itself, but only its JSON-ifiable representation,
effectively objReceived = JSON.parse(JSON.stringify(objSent))
, so since your object's settingList
is invisible outside function context it's lost during serialization.
You can make it public by exposing a stringifiable property
this.settingList = { foo: 'bar' };
that would be transferred to your content script successfully.
Since messaging is asynchronous, to use the response in the content script you should do it inside the response callback:
// this will store the settings
var settings = {};
// load settings from background
chrome.runtime.sendMessage({
name: "get-settings"
}, function(response) {
settings = response.data.settings;
onSettingsReady();
});
function onSettingsReady() {
// put your logic here, settings are set at this point
}
To know if settings changed outside your content-script, in settings setter in background.js send messages to your tab's content-script:
this.set = function( key , value ) {
...
// notify active tab if settings changed
chrome.tabs.query({"windowType":"normal"}, function(tabs){
for( id in tabs ){
if("id" in tabs[id]){
chrome.tabs.sendMessage(tabs[id].id,{"action":"update-settings","settings":settings});
}
}
});
return true;
};
And in content-script listen and process this message:
chrome.runtime.onMessage.addListener(function(msg){
if("action" in msg && msg.action == 'update-settings'){
// You are setting global settings variable, so on it will be visible in another functions too
settings = msg.settings;
}
});
More details: https://developer.chrome.com/extensions/runtime#method-sendMessage.
P.S. Use chrome.runtime.sendMessage
instead of chrome.extension.sendMessage
as the latter is deprecated in Chrome API and totally unsupported in WebExtensions API (Firefox/Edge).
Upvotes: 3