How to save multiple objects to an array in a chrome extension? - javascript

I'm building my first chrome extension and I want it to track the TV series I watch and I'm currently trying to get it to save metadata on the series that I am following.
I have a content script that returns the title, the newest episode (and the URL of this episode) as well as the URL of the cover image of the series. I am currently trying to save it with some code on my background script (I have made sure to include "storage" under the permissions section of the manifest file).
So far my script looks like this (This was developed with help from Trying to save and fetch a Javascript object using chrome.storage API?):
var bkg = chrome.extension.getBackgroundPage();
response.aID = new Series(response.aTitle,response.aNewEp,response.aNewEpURL,response.aImage);
chrome.storage.sync.set(response.aID, function(){
chrome.storage.sync.get(function(val){
bkg.console.log("The saved title is: ", val.anTitle);
bkg.console.log("The saved newEp is: ", val.anNewEp);
bkg.console.log("The saved newEpURL is: ", val.anNewEpURL);
bkg.console.log("The saved imageURL is: ", val.anImage);
});
});
Problem is, the script only seems to store one response.aID at a time, so I can never store data for more than 1 TV series. Every time I try, the script seems to overwrite my previous entry. So I would like to ask whether there's any way to store more than 1 TV series at a time?
I have looked at storing an array and then pushing each new object into that array (Store an array with chrome.storage.local), but I don't quite understand the syntax involved so I'm not sure if this would work for me.

Unfortunately you didn't include the piece of code where you save your data, but i think you dont store your data with indices for the different TV series so the stored one gets overwritten everytime you store another one.
Anyway I would prefer storing your data in a JSON element (basically every javascript element can by converted to one but continue reading) because js provides several functions for this format which make it quite easy to use.
When opening your extension, load the data and call
var data = JSON.parse (yourloadedstring);
so the string (which should look like {"TVShows": [{"title": "How i met your mother", "url": ...}, {...}]} (look here for an explenation how JSON works) gets "translated" to an element from which you can read simply by calling
data.TVShows[0].title
or
data.TVShows[1].imageURL
You can edit this data JSON element when you add a new show for example by saying
data.TVShows[2].title = "The Big Bang Theory";
data.TVShows[2].URL= ...;
data.TVShows[2].imageURL= ...;
and save this element to chromes storage by calling
var dataToSave = JSON.stringify(data);
You have a string in your storage then, containing all information you need and you can simply parse it later like explained above :)
I hope everything is clearly to understand, if not pls ask me!
Cheers

Related

Attempting to use a global array inside of a JS file shared between 2 HTML files and failing

So I have one HTML page which consists of a bunch of form elements for the user to fill out. I push all the selections that the user makes into one global variable, allTheData[] inside my only Javascript file.
Then I have a 2nd HTML page which loads in after a user clicks a button. This HTML page is supposed to take some of the data inside the allTheData array and display it. I am calling the function to display allTheData by using:
window.onload = function () {
if (window.location.href.indexOf('Two') > -1) {
carousel();
}
}
function carousel() {
console.log("oh");
alert(allTheData.toString());
}
However, I am finding that nothing gets displayed in my 2nd HTML page and the allTheData array appears to be empty despite it getting it filled out previously in the 1st HTML page. I am pretty confident that I am correctly pushing data into the allTheData array because when I use alert(allTheData.toString()) while i'm still inside my 1st HTML page, all the data gets displayed.
I think there's something happening during my transition from the 1st to 2nd HTML page that causes the allTheData array to empty or something but I am not sure what it is. Please help a newbie out!
Web Storage: This sounds like a job for the window.sessionStorage object, which along with its cousin window.localStorage allows data-as-strings to be saved in the users browser for use across pages on the same domain.
However, keep in mind that they are both Cookie-like features and therefore their effectiveness depends on the user's Cookie preference for each domain.
A simple condition will determine if the web storage option is available, like so...
if (window.sessionStorage) {
// continue with app ...
} else {
// inform user about web storage
// and ask them to accept Cookies
// before reloading the page (or whatever)
}
Saving to and retrieving from web storage requires conversion to-and-from String data types, usually via JSON methods like so...
// save to...
var array = ['item0', 'item1', 2, 3, 'IV'];
sessionStorage.myApp = JSON.stringify(array);
// retrieve from...
var array = JSON.parse(sessionStorage.myApp);
There are more specific methods available than these. Further details and compatibility tables etc in Using the Web Storage API # MDN.
Hope that helps. :)

Mirth channelMap in source JavaScript

In my source connector, I'm using javascript for my database work due to my requirements and parameters.
The end result is storing the data.
ifxResults = ifxConn.executeCachedQuery(ifxQuery); //var is declared
I need to use these results in the destination transformer.
I have tried channelMap.put("results", ifxResults);.
I get the following error ReferenceError: "channelMap" is not defined.
I have also tried to use return ifxResults but I'm not sure how to access this in the destination transformer.
Do you want to send each row as a separate message through your channel? If so, sounds like you want to use the Database Reader in JavaScript mode. Just return that ResultSet (it's really a CachedRowSet if you use executeCachedQuery like that) and the channel will handle the rest, dispatching an XML representation of each row as discrete messages.
If you want to send all rows in the result set aggregated into a single message, that will be possible with the Database Reader very soon: MIRTH-2337
Mirth Connect 3.5 will be released next week so you can take advantage of it then. But if you can't wait or don't want to upgrade then you can still do this with a JavaScript Reader:
var processor = new org.apache.commons.dbutils.BasicRowProcessor();
var results = new com.mirth.connect.donkey.util.DonkeyElement('<results/>');
while (ifxResults.next()) {
var result = results.addChildElement('result');
for (var entries = processor.toMap(ifxResults).entrySet().iterator(); entries.hasNext();) {
var entry = entries.next();
result.addChildElement(entry.getKey(), java.lang.String.valueOf(entry.getValue()));
}
}
return results.toXml();
I know this question is kind of old, but here's an answer just for the record.
For this answer, I'm assuming that you are using a Source connector type of JavaScript Reader, and that you're trying to use channelMap in the JavaScript Reader Settings editing pane.
The problem is that the channelMap variable isn't available in this part of the channel. It's only available in filters and transformers.
It's possible that what you want can be accomplished by using the globalChannelMap variable, e.g.
globalChannelMap.put("results", ifxResults);
I usually need to do this when I'm processing one record at a time and need to pass some setting to the destination channel. If you do it like I've done in the past, then you would first create a globalChannelMap key/value in the source channel's transformer:
globalchannelMap.put("ProcID","TestValue");
Then go to the Destinations tab and select your destination channel to make sure you're sending it to the destination (I've never tried this for channels with multiple destinations, so I'm not sure if anything different needs to be done).
Destination tab of source channel
Notice that ProcID is now listed in the Destination Mappings box. Click the New button next to the Map Variable box and you'll see Variable 1 appear. Double click on that and put in your mapping key, which in this case is ProcID.
Now go to your destination channel's source transformer. There you would enter the following code:
var SentValue = sourceMap.get("ProcID");
Now SentValue in your destination transformer has whatever was in ProcID when your source channel relinquished control.

Passing DOM elements to another page with JQuery

So, I understand this is an odd question. I have 2 pages, one that somebody fills out w/ a bunch of inputs. The next page would be a "print to pdf" type deal w/ Coldfusion. However, I want to send all the info to the next page and not lose what the person entering data has put in. Is there a way with jQuery (or some other option in CF that I haven't seen) to potentially grab the $('body') and pass it to sub in on the next page so it keeps the <input> values? I don't want to do a form submit, as there are a bunch of calculations that also take place based off those inputs that are shown, using javascript, and <cfdocument> has trouble with javascript after the fact.
I would serialize all the form input values using jQuery's serializeArray, and store it in the localStorage. In the next page, just read the localStorage and parse your data back to an object using JSON.parse.
Page 1 :
localStorage.formData = $("form").serializeArray()
Page 2 :
var formData = JSON.parse(localStorage.formData)
...aaaand you'll get all your data in an object on page 2.
Ok, so the element data to local storage worked, but the way I actually did it was writing the $('body').html() to a string, passing that using $.ajax() to a cfc file, where I wrote a text file to the CF temp directory using <cffile>, then re-rendered that text into HTML/CFML on the PDF page using <cfinclude>. Hope this helps someone if they need it!
You can cache the data for use on another page in CFML. I do this with Railo, but Adobe CF has a similar function. Any data I want to use on the next page goes in to an array of structs. I haven't tried cacheput('formdata', form), but it seems like it would work.
Page 1
// Empty cache storage
cacheClear();
// call the function to cache data
cachePut('cData', data);
Page 2
// get items from the cache
data = cacheGet('cData');

Parsing a large JSON array in Javascript

I'm supposed to parse a very large JSON array in Javascipt. It looks like:
mydata = [
{'a':5, 'b':7, ... },
{'a':2, 'b':3, ... },
.
.
.
]
Now the thing is, if I pass this entire object to my parsing function parseJSON(), then of course it works, but it blocks the tab's process for 30-40 seconds (in case of an array with 160000 objects).
During this entire process of requesting this JSON from a server and parsing it, I'm displaying a 'loading' gif to the user. Of course, after I call the parse function, the gif freezes too, leading to bad user experience. I guess there's no way to get around this time, is there a way to somehow (at least) keep the loading gif from freezing?
Something like calling parseJSON() on chunks of my JSON every few milliseconds? I'm unable to implement that though being a noob in javascript.
Thanks a lot, I'd really appreciate if you could help me out here.
You might want to check this link. It's about multithreading.
Basically :
var url = 'http://bigcontentprovider.com/hugejsonfile';
var f = '(function() {
send = function(e) {
postMessage(e);
self.close();
};
importScripts("' + url + '?format=json&callback=send");
})();';
var _blob = new Blob([f], { type: 'text/javascript' });
_worker = new Worker(window.URL.createObjectURL(_blob));
_worker.onmessage = function(e) {
//Do what you want with your JSON
}
_worker.postMessage();
Haven't tried it myself to be honest...
EDIT about portability: Sebastien D. posted a comment with a link to mdn. I just added a ref to the compatibility section id.
I have never encountered a complete page lock down of 30-40 seconds, I'm almost impressed! Restructuring your data to be much smaller or splitting it into many files on the server side is the real answer. Do you actually need every little byte of the data?
Alternatively if you can't change the file #Cyrill_DD's answer of a worker thread will be able to able parse data for you and send it to your primary JS. This is not a perfect fix as you would guess though. Passing data between the 2 threads requires the information to be serialised and reinterpreted, so you could find a significant slow down when the data is passed between the threads and be back to square one again if you try to pass all the data across at once. Building a query system into your worker thread for requesting chunks of the data when you need them and using the message callback will prevent slow down from parsing on the main thread and allow you complete access to the data without loading it all into your main context.
I should add that worker threads are relatively new, main browser support is good but mobile is terrible... just a heads up!

Using AngularJS to process custom localStorage data

I wrote a bookmarklet that retrieves information from a page and stores it in JSON format in local storage (converting it to a string first, of course).
I would like a web app I am writing to be able to process this data, on the fly, preferably as it gets saved to the localStorage.
Right now i can change the item in LS via the console and refresh the page and the new data appears but I would like it to be live and seamless.
Any advice on how to go about this? I found several localStorage modules for angularJS and I tried them but they don't seem to allow me to retrieve from LS if the data is already there in LS.
In response to answer:
$scope.$watch(
function(){
return $window.localStorage.getItem('TestData');
},
function(newValueInStorage){
$scope.testingLS = newValueInStorage;
}
)
I tried this and I still get the data displayed by just doing a {{ testingLS }} in the view template but when I go and change the TestData key in local storage via the console it doesn't update instantly. (for now, I am just testing it without the bookmarklet with just a simple string inside TestData
There is few ways to do it
One of will be to populate correct model on scope when saving to localStorage
The other that I can think of at this moment is to setup watcher
$watch(
function(){
return localstorage object
},
function(newValueInStorage){
$scope.modelFromLS = JSON.parse(newValueInsStorage)
}
)
---edit---
as per James comment you need something that will handle the fact that data has changed in different tab and $digest process need to run for watch to be recalculated
http://plnkr.co/edit/zlS3wL65meBeA8KkV5KH?p=preview
window.addEventListener('focus', function(){
console.log('focus')
$scope.$digest()
})

Categories

Resources