SamG SamG - 7 months ago 30
Javascript Question

Chrome Extension Storing Custom Object Type Strips Prototype Methods

I have created a custom object that I am using in my extension. When I save objects of the type Group (my object type) and then later pull those objects out of storage, it appears that the prototype methods are no longer present. Now I read in the documentation that objects serialize down to object literals

{}
and I can't seem to figure out how to keep the methods with the objects. I have provided the code of the group class below. When I try and use one of the methods from the file below on an object that was retrieved from storage, I get an error that the function does not exist. I used a for in loop to loop through all of the properties and the object has the name and urls property. Any help would be greatly appreciated!

Group.js:

// Create the Group class
var Group = function (name, urls) {
this.name = name;
this.urls = urls;
};

// Clears all urls from the group
Group.prototype.clearUrls = function () {
this.urls = [];
};

// Adds the specified url to the group
Group.prototype.addUrl = function (url) {
this.urls.append(url);
};

// Removes the specified url from the group
Group.prototype.removeUrl = function (url) {
this.urls = this.urls.filter(function(_url){
return url !== _url;
});
};

// Renames the group
Group.prototype.rename = function (name) {
this.name = name;
};

// Checks whether or not the group contains the specified url
// Returns either true or false
Group.prototype.containsUrl = function (url) {
var contains = false;
for (var i = 0; i < this.urls.length; i++) {
if (this.urls[i] === url) {
contains = true;
break;
}
}
return contains;
};


EDIT:

Here is the background.js script, it shows how the object is retrieved and then how it is called later in the script. It fails when it receives the addUrl message and attempts to call
containsUrl()
on currentGroup.

// Global Variables
var currentGroup;
var groups = [];
var options = [];

// Short hand function to save the current data to storage
var saveData = function () {
// Save default options, currrentGroup, and groups
chrome.storage.sync.set({'options': options, 'currentGroup': currentGroup, 'groups': groups}, function() {
if (chrome.runtime.lastError) {
console.error("Could not save because: " + chrome.runtime.lastError);
}
});
}

// On start query for saved data to make sure data is current
chrome.storage.sync.get(function(items) {
// Check if there are groups
if (items['groups']) { // Set the groups
groups = items['groups'];
} else { // Create default group and add to list of groups
currentGroup = new Group('default', []);
groups = [currentGroup];
}

// Check for current group, if none set to first available group
if (items['currentGroup']) {
currentGroup = items['currentGroup'];
console.log(Object.getOwnPropertyNames(currentGroup));
} else {
currentGroup = groups[0];
}

// Check for the options
if (items['options']) {
options = items['options'];
} else {
// No options, set the default options and save them
options['overrideHomepages'] = true;
}

saveData();

// After data has been fetched bring up the tabs
chrome.tabs.query({'currentWindow': true}, function(tabs) {
for (var i = 0; i < currentGroup.urls.length; i++) {
if (options['overrideHomepages']) {
if (tabs[i].url.length > 0) {
chrome.tabs.update(tabs[0].id, {'url': currentGroup.urls[i]});
} else {
chrome.tabs.create({'url': currentGroup.urls[i]});
}
} else { // Don't override homepages or open tabs
chrome.tabs.create({'url': currentGroup.urls[i]});
}
currentGroup.urls[i]
}
}); // End tabs.query

}); // End storage.sync.get

// Add message listener
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {

// If add url was sent
if (request.message === 'addUrl') {
console.log('Recieved message: ' + request.message);
// Check if the group contains the url already
if (currentGroup.containsUrl(sender.url) === false) {
currentGroup.addUrl(sender.url);
saveData();
sendResponse({'message': 'Saved ' + sender.url});
}
}

// If remove url was sent
if (request.message === 'removeUrl') {
// Check if the group contains the url
if (currentGroup.containsUrl(sender.url)) {
currentGroup.removeUrl(sender.url);
saveData();
sendResponse({'message': 'Removed ' + sender.url})
}
}
});

Answer

I believe currently chrome.storage is only used to save key-value items, not including prototype/functions. However, I didn't find any official docs about this.

One workaround would be using Group.prototype.containsUrl.call(currentGroup, sender.url), it allows you to invoke containsUrl with specifying the context for "this".