Javascript storing/state of global data/object - javascript

Is there a way to store global data in the window object such that the data can survive page reloads/refresh. So lets say I assign my global data/object -
window.myObject = myProductObject
And the user refreshes/reloads the page or may be jumps to another page of my website. Is window.myObject still available after the page reload?
NOTE -: I cannot store the object in a cookie, since its a object, I mean it could be a reference to another custom object or it could refer to another "window" object which has opened via "window.open"

Use the window.top.name hack
var data = window.top.name ? JSON.parse(window.top.name) : {}
...
window.top.name = JSON.stringify(data)
window.top.name persists across page loads
I recommend you use an abstraction like lawnchair instead though

You CAN save objects in cookies. But localStorage is better. Is similar to a cookie but you get 5Mb to use.
You have to JSON encode/decode if you save objects instead of strings, but that is easy with a wrapper on localStorage or cookie.
Here is a really simple wrapper for localStorage (you have 5Mb to use):
var Storage = {
set: function(key, value) {
localStorage[key] = JSON.stringify(value);
},
get: function(key) {
return localStorage[key] ? JSON.parse(localStorage[key]) : null;
}
};
And you can use it like this:
$(function() {
var defaultValue = {param1: 'value',counter: 0 },
myObj = Storage.get('myObj') || defaultValue; // get the obj from storage or create it with default values
$('body').html('counter: ' + myObj.counter);
myObj.counter+=1; // increment counter
Storage.set('myObj', myObj); // save it to localStorage
});
​
You can try it on this jsFiddle: http://jsfiddle.net/guumaster/LytzA/3/

You could try storing a string representation of your object in a cookie, provided the object is made up of values only (no methods), eg
var foo = { a: "a", b: "b" };
document.cookie = "foo=" + JSON.stringify(foo);
There's a good cookie reader / writer example here - https://developer.mozilla.org/en/DOM/document.cookie

I'm not sure how this fairs cross-browser. I at least got it to work in chrome, firefox and IE9 and IE8/7 in compatibility mode, but you will get warned about popups. You can detect if popups are being blocked and refuse to load anything until they are enabled for your site. See Detect blocked popup in Chrome
I'm using jQuery to bind to the beforeunload event, you can use your preferred solution.
jQuery(function ($) {
$(window).bind('beforeunload', function () {
window.open("", "_savedata", "titlebar=0,width=100,height=100").saveData = window.saveData;
});
var store = window.open("", "_savedata");
window.saveData = store.saveData;
store.close();
});
Example: (refresh the page a few times)
http://jsfiddle.net/hZVss/1/
And as requested by #Raynos - persisting closure state - something you can't serialise (works in firefox and chrome at least, IE calls it a security issue, but might be something to do with how jsfiddle is using frames)
http://jsfiddle.net/ght9f/2/
Disclaimer: I wouldn't vouch for the elegance of this solution. I was merely curious about persisting object state using popups. Serialising your object to JSON and storing it in a client side store is much better (#Raynos would recommend lawnchair https://github.com/brianleroux/lawnchair/). You should avoid cookies if you can as this data gets posted back to the server, which might not be ideal.
If your main objective was to persist references to popup windows you can actually do this by giving the popup a name. This is exactly how I am persisting my reference to the popup that I create on refresh.

Related

How to save the last state of sliders after page reload

I have this network visualized using d3 and angular. Here is the link to the visualization.
I wanted to save the last state of the network so that even if I refresh the page it will show the last state. But don't know how to do that.
I read that it can be done using sessionStorage or localStorage but I can't seem to figure it out for my visualization.
I tried this by setting my JSON data to the sessionStorage and then getting it:
if (sessionStorage) {
sessionStorage.setItem("myKey", myJSON.toString());
}
if (sessionStorage) {
sessionStorage.getItem("myKey"); // {"myKey": "some value"}
}
and I also tried it like this:
localStorage.setItem("networkGraph", networkGraph);
var networkGraph = localStorage.getItem("networkGraph");
but it's not working. Is this the right way to do it?
Any help will be highly appreciated!
Are you sure that you need sessionStorage and not localStorage? In the case of sessionStorage saved data will be deleted when a browser tab with your app becomes closed.
You can write localStorage.setItem('inputLayerHeight', vm.inputLayerHeight); in your onChange handler to remember inputLayerHeight and Number.parseInt(localStorage.getItem('inputLayerHeight')) || 15 to restore the inputLayerHeight at value property of vm.inputLayerHeightSlider object. The same approach can be used for the other values to keep.
Your attempt is almost right. The only thing you need to change is the usage of localStorage. Simply add window or $window (more 'angulary' way to access window variable) variable like so:
$window.localStorage.setItem("networkGraph", JSON.stringify(networkGraph));
Also, I recommend using angular-storage if you're looking for an easy way to work with local storage. It makes things less painful :)
I think the problem might be related to the way you are storing data on your local storage. You are saving data as a string however I think that d3 doesn't recognize strings as valid data options. So instead you should do something like this:
if (sessionStorage) {
// Parse the data to a JavaScript Object
const data = JSON.parse(sessionStorage.getItem("myKey"));
} else {
// Fetch data...
// Set sessionStorage or localStorage
sessionStorage.setItem("myKey", myJSON.toString());
}
You can rearrange the logic as it might suit you but the idea is that in the end you should use JSON.parse() when getting the data from storage.

firefox add-on access variable everytime page is loaded

I am writing firefox add-on but I have no idea how to do this (how to store variables between page openings):
When I open page and if var page_count does not exist, I want to create it and set to 1. If I open another page it should count page_count++
I don't know how to set "global" variable in addon (and how to access it later) - it should keep alive between page openings. Any idea please?
Maybe you should try to use the Simple Storage to store this variables? It's pretty simple and (probably) fast.
https://developer.mozilla.org/en-US/Add-ons/SDK/High-Level_APIs/simple-storage
var simpleStorage = require("sdk/simple-storage");
var tabs = require("sdk/tabs");
simpleStorage.storage.pageCount = 1; //you need to initialize a variable
tabs.on('open', function onOpen(tab) {
simpleStorage.storage.pageCount++; //in method
});

IE 11 caching javascript overrides

I've come across some weird behavior in IE11 when it comes to overriding functions in javascript.
On a webpage i have the following code:
(function ()
{
var tempSetItem = window.localStorage.setItem;
window.localStorage.setItem = function (key, data)
{
var newdata = JSON.stringify(data);
newdata = JSON.parse(newdata);
newdata.CachedDate = new Date();
tempSetItem.call(window.localStorage, key, JSON.stringify(newdata));
};
})();
This should simply override the localStorage.setItem() function.
However, i ran into some trouble with the code and decided to comment it out.
When i refreshed the page (cleared cache ofcourse) the same problem was still there.
I soon realised that IE had somehow cached my override.
I searched through all my files to make sure i didn't override it anywhere else and i even tried to set it to null manually through the console (In other words, it should not be null after a refresh) and after a refresh, it was now null.
It seems to be cached per domain or per URL in some way and i don't know how to clear this cache or if it's even possible.
I even tried repairing IE but localStorage.setItem is still null on my webpage.
I still don't know why the overriding gets cached but i found a way to reset it.
Calling localStorage.clear() resets the entire localStorage-object, including the setItem-function.
To avoid the rest of the problem i simply made a normal wrapper-function instead of overriding the original and called that from all the places where i would otherwise call localStorage.setItem().

automating browser with phantom.js

I am trying to automate the browser using phantomjs. I load a page, supply the login credentials and then want to click on the submit button. As the first step I loaded a page, modified the form values and piped the output to a .html file to see if that works. Here is my code:
var page = require('webpage').create();
var fs = require('fs');
page.onConsoleMessage = function(msg) {
fs.write("/home/phantom/output.html", msg, 'w');
};
page.settings.userAgent = 'SpecialAgent';
//page.open('http://google.com', function(status) {
page.open('https://somewebsitehavingaform.com', function(status) {
if (status !== 'success') {
console.log('Unable to access network');
} else {
var ua = page.evaluate(function() {
document.getElementsByName('id').value="id";
document.getElementsByName('name').value="name";
document.getElementsByName('password').value="password";
console.log(document.body.innerHTML);
});
}
phantom.exit();
});
When i open the output.html, it shows me the form but its empty. I expected id,name and password to be pre-filled. Where i am going wrong here?
First of all, getElementsByName will return an array. In order to set the value of the first input found with that name, you'd need to choose a specific element in it, i.e. the first:
getElementsByName('foo')[0].value = 'bar'
Then, if you change the assignment to use setAttribute it seems to work correctly:
var ua = page.evaluate(function() {
document.getElementsByName('id')[0].setAttribute("value", "id");
document.getElementsByName('name')[0].setAttribute("value", "name");
document.getElementsByName('password')[0].setAttribute("value", "password");
console.log(document.body.innerHTML);
});
According to the Mozilla docs,
Using setAttribute() to modify certain attributes, most notably value
in XUL, works inconsistently, as the attribute specifies the default
value. To access or modify the current values, you should use the
properties. For example, use elt.value instead of
elt.setAttribute('value', val).
Though since you're just writing out the resulting HTML to file, I don't think it should cause you a problem in this instance.
Not sure if Phantom JS is now using the QJSEngine internally, but notice this open ticket on their backlog that might be related to the issue you're getting with dot notation:
QJSEngine is a simple wrapper around V8, mainly for use with QtQml.
Using QJSEngine for the PhantomJS main context might prove to be more
malleable/customizable than the current implementation.
Problems:
…
Automatic property creation when using dot notation does not work with QObjects added to the QJSEngine
(This suggests that QJSEngine isn't the current implementation in use, but was raised 9 months ago, so not sure if it's been introduced since then, so thought it was worth flagging)

Global variables in JavaScript with multiple files

I have a file called index.php. With script tags, it references index.js.
I also have a file called payment.php. With script tags, it references payment.js.
I need to set a variable called seatSelected in index.js and then use it in payment.js. However, I do not want to reference index.js in payment.php.
I have tried to make a file called globals.js, reference it in index.php before index.js containing the following:
var selectedSeat;
function setSelectedSeat(seat){
selectedSeat = seat;
}
function getSelectedSeat(){
return selectedSeat;
}
And setting the value in index.js with:
setSelectedSeat("test");
Receiving it in payment.js with (referencing globals.ks in payment.php above payment.js):
alert(getSelectedSeat());
But it alerts 'undefined'. Am I doing something wrong? How can I reference this variable without referencing the file it is changed in?
You cannot access variables created from another page.
You could use localStorage with cookies as fallback.
function setSelectedSeat(seat){
if(localStorage) {
localStorage['selectedSeat'] = JSON.stringify(seat);
}
else {
//add code to store seat in cookie
}
}
function getSelectedSeat(){
if(localStorage) {
return JSON.parse(localStorage['selectedSeat']);
}
else {
//add code to retrive seat in cookie
}
}
You are trying to persist the state of variables while transitioning from one page to another and your application seems to have data that would require session expiry, I suggest you use sessionstorage. With help of polyfills you can give sessionstorage support till IE6 browser.
Benefit of using SessionStorage over LocalStorage
Session Storage persists the data only for a particular tab/window and the data is lost when the tab/window is closed.
As the data gets expired automatically you don't need to worry about session expiring.
You can expire your session at your will as well.
The data persists on page refreshes.
But Remember with sessionstorage you can only store strings key-value pattern. And you need to use JSON.stringify and JSON.parse method to store your complex objects in browser memory.
Here you can find a list of polyfills that you can use to provide the support of sessionstorage in non supporting browsers : https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills#web-storage-localstorage-and-sessionstorage
Also you can read the following article to understand sessionstorage and localstorage in a better way: http://diveintohtml5.info/storage.html

Categories