HTML5 localStorage: Is my code following correct standards? - javascript

OK, so I have created an HTML5 canvas game that uses localStorage. I have localStorage working perfectly but I'm not sure that it follows the correct standards, or if it is completely fine the way that I have written it.
//check if storage is set already, if not set the variable
function checkLocalStorage(){
if (localStorage.timesPlayed){
timesPlayed = Number(localStorage.timesPlayed);
}
else{
timesPlayed = 0;
}
}
//code snippet to increase my variable
timesPlayed += 1;
//code snippet to set the localStorage
localStorage.timesPlayed = timesPlayed;
This works perfectly!? But from what I have read, i should be using localStorage.getItem and localStorage.setItem?
Should I change the way I write localStorage??
This is just the link to the website where I learned this way to access localStorage
http://hacks.mozilla.org/2009/06/localstorage/

It works, and it probably won't break, but I'd still try to cast things in the correct type when using localStorage. getItem and setItem are the preferred ways of doing things, but the thing that jumped out at me was that your methods of getting and setting the value won't work for any type but a number, which means you have to code cautiously if you're using a lot of localStorage.
You're sending a number to localStorage, where it's converted to a string. This can get you into a lot of trouble when dealing with booleans, for example:
var won = false;
localStorage.isWinner = won;
if (localStorage.isWinner) { // always true
alert("You won!");
}
Arrays and objects get ugly too:
localStorage.test = {foo: "bar", dog: "cat"};
// returns "[object Object]"
In other words, what you have works, but it's a good habit to do things correctly and consistently from the start, as it will simplify debugging later. The correct way -- which works with strings, numbers, arrays, objects -- is this:
localStorage.setItem("key", JSON.stringify(value));
JSON.parse(localStorage.getItem("key"));
// or as a de facto alternative
localStorage.key = JSON.stringify(value);
JSON.parse(localStorage.key);

I don't think the array access notation for localStorage is part of the standard, but most browsers that implement will probably allow for that possibility. If you want to be especially careful, then use getItem and setItem - but personally, I don't foresee this being a problem.
Mozilla says:
Although the values can be set and read via the standard JavaScript property access method usage of getItem and setItem methods is recommended.
http://dev.w3.org/html5/webstorage/#storage-0
Even the examples in that draft they use the property access notation, so I think you're OK.

For a small application, direct reading and writing to localStorage is probaby OK, however I think in a more complex application it would be a good idea to wrap localStorage and provide an API with get and set methods suitable for the particular application (e.g. get/setMySpecialObject and get/setMySpecialValue).
I don't think an application should care about where data is stored, it should just call an API to get or set it. The code behind the API works out how to store it and where to get it from. Genearlly it's most efficient to read and write data into an object and read/write to localStorage behind the scenes. Get data from localStorage the first time it is requested and cache it. If it's updated along the way, write back to localStorage as appropriate, it should not require commands from the application to do so.

Related

Detecting if there is a change in a localStorage variable

I have a case where I need to pass a variable from a modal back to the main screen. I have decided the cleanest way to do so is to store that value in localStorage so that I can pass it back to the main file and then display it on the main page.
Is there a way to listen to the localStorage item being changed? I've been searching, but only have found information getting and setting the variable.
My item looks like this.
var length = $('.table').find('tbody').find('tr').length;
localStorage.setItem('length', length);
There's a storage event on window object for local storage changes.
MDN local storage api
So you can watch the changes. But, if I am correct, that would work only for the same domain frames. So if they are, this is your choice.
you can use a global scope like define it out of function and it will be one global scope.
var globalVariable={
x: 'globalval'
};
or use...
window.globalvar1='test' //it will set to global.
that way it will be bind to window scope.
when you set the item, always first do a get and compare with that value,
if value is changed notify, otherwise set.
var length = $('.table').find('tbody').find('tr').length;
if(localStorage.getItem(length)){
localStorage.getItem(length)!=length?notifyChange():
}
Note: This is an expensive and overly complicated approach but meets your needs for pure localStorage.
If you must use localStorage the only way I can think of that you can watch/listen for a variable in localStorage is like so
setInterval(function(){
var modalValue = localStorage.getItem( 'length' );
if( modalValue ){
// use the value
// remove the value when you are done so that this code doesn't run every time
localStorage.setItem( 'length', null );
}
}, 100 );
This will check for the variable every 1/10 of a second and run the code when it's set.
You mentioned in a comment that it is complicated and that their are iframes involved. Perhaps you can leverage the messaging api to better meet your needs?
Don't use localstorage for critical functionality. localstorage is blocked completely when using private browsing on certain browsers.
Only use localstorage for non-critical enhancements.
There is no callback for localstorage, so you wont be able to monitor changes as they happen. You could however pull the value on page load, store the value in your execution context and watch for that value to change.
Otherwise, to do what you want will require using a database.
Don't do this, find a mechanism of dependency injection that will let you pass the the variable in a sane manner. Do that either with something akin to Angular.js' service/factory pattern, or a React store.
Leveraging a mechanism like that will also allow you to listen for changes to whatever you're storing. In fact, that's the whole point of things like RxJS Observables which are at the core of Angular2+'s framework.
Additionally, something like couchdb would let you persist this data asynchronously and still not have the drawbacks of coordinating globals through raw localstorage.
Allowing for uncontrolled access to some global variable is just asking for a defect.

How can I clone a <browser> element in Firefox using XUL?

I am developing a firefox extension where I need to save the state of an arbitrary web page in order to be able to restore that webpage later. The quirk is that I need to restore the entire state of the page, including the state of all javascript variables. The "saving" can be done in memory, it doesn't need to be serializable.
So, is there a way to exactly clone a browser element, so that it starts running from the same point of execution that the original is currently at?
If not, how much effort would it require to add this to firefox (using C++), and which files and documentation would I start looking at?
No, there isn't a way to do exactly what you want. Even the built-in session restore will only restore form fields (and some other selected things), but not the full JS and native object state.
Implementing something like this yourself not feasible (and would be also a massive task):
You could uneval() most js objects, but that will loose type information and you'll only get the source, but not any internal state (think "hidden" state via closures). Native objects like window or document need some special treatment, and getting the internal state isn't exactly always possible here without some C++-level "reflection".
You could potentially get a lot of the actual state using the debugger API in new ways, however I don't see any way to actually restore it later. And "a lot" is still not the same as "all".
About the closed-over "hidden" state:
There is no way I know of to reliably get the internal state of counter in the following example, let alone restore it later, without getting as low-level as a platform-dependent full memory dump.
var count = (function() {
var counter = 0;
return function() { return ++counter; };
})();
count();
count();
I guess that you could walk the properties of all objects and save them somewhere but preserving context of e.g. bound functions would be difficult. Maybe you could make some use of the session store?
See:
Session_store_API and nsISessionStore

localStorage - use getItem/setItem functions or access object directly?

Are there some benefits of using the methods defined on the localStorage object versus accessing the object properties directly? For example, instead of:
var x = localStorage.getItem(key);
localStorage.setItem(key, data);
I have been doing this:
var x = localStorage[key];
localStorage[key] = data;
Is there anything wrong with this?
Not really, they are, basically, exactly the same. One uses encapsulation (getter/setter) to better protect the data and for simple usage. You're supposed to use this style (for security).
The other allows for better usage when names(keys) are unknown and for arrays and loops. Use .key() and .length to iterate through your storage items without knowing their actual key names.
I found this to be a great resource : http://diveintohtml5.info/storage.html
This question might provide more insight as well to some: HTML5 localStorage key order
Addendum:
Clearly there has been some confusion about encapsulation. Check out this quick Wikipedia. But seriously, I would hope users of this site know how to google.
Moving on, encapsulation is the idea that you are making little in and out portals for communication with another system. Say you are making an API package for others to use. Say you have an array of information in that API system that gets updated by user input. You could make users of your API directly put that information in the array... using the array[key] method. OR you could use encapsulation. Take the code that adds it to the array and wrap it in a function (say, a setArray() or setWhateverMakesSense() function) that the user of your API calls to add this type of information. Then, in this set function you can check the data for issues, you can add it to the array in the correct way, in case you need it pushed or shifted onto the array in a certain way...etc. you control how the input from the user gets into the actual program. So, by itself it does not add security, but allows for security to be written by you, the author of the API. This also allows for better versioning/updating as users of your API will not have to rewrite code if you decide to make internal changes. But this is inherent to good OOP anyhow. Basically, in Javascript, any function you write is a part of your API. People are often the author of an API and it's sole user. In this case, the question of whether or not to use the encapsulation functions is moot. Just do what you like best. Because only you will be using it.
(Therefore, in response to Natix's comment below...)
In the case here of JavaScript and the localStorage object, they have already written this API, they are the author, and we are its users. If the JavaScript authors decide to change how localStorage works, then it will be much less likely for you to have to rewrite your code if you used the encapsulation methods. But we all know its highly unlikely that this level of change will ever happen, at least not any time soon. And since the authors didn't have any inherent different safety checks to make here, then, currently, both these ways of using localStorage are essentially the same. Except when you try to get data that doesn't exist. The encapsulated getItem function will return null (instead of undefined). That is one reason that encapsulation is suggested to be used; for more predictable/uniform/safer/easier code. And using null also matches other languages. They don't like us using undefined, in general. Not that it actually matters anyhow, assuming your code is good it's all essentially the same. People tend to ignore many of the "suggestions" in JavaScript, lol! Anyhow, encapsulation (in JavaScript) is basically just a shim. However, if we want to do our own custom security/safety checks then we can easily either: write a second encapsulation around the localStorage encapsulate, or just overwrite/replace the existing encapsulation (shim) itself around localStorage. Because JavaScript is just that awesome.
PT
I think they are exactly the same, the only thing the documenation states is:
Note: Although the values can be set and read using the standard
JavaScript property access method, using the getItem and setItem
methods is recommended.
If using the full shim, however, it states that:
The use of methods localStorage.yourKey = yourValue; and delete
localStorage.yourKey; to set or delete a key is not a secure way with
this code.
and the limited shim:
The use of method localStorage.yourKey in order to get, set or delete
a key is not permitted with this code.
One of the biggest benefits I see is that I don't have to check if a value is undefined or not before I JSON.parse() it, since getItem() returns NULL as opposed to undefined.
As long as you don't use the "dot notation" like window.localStorage.key you are probably OK, as it is not available in Windows Phone 7. I haven't tested with brackets (your second example). Personally I always use the set and get functions (your first example).
Well, there is actually a difference, when there is no local storage available for an item:
localStorage.item returns undefined
localStorage.getItem('item') returns null
One popular use case may be when using JSON.parse() of the return value: the parsing fails for undefined, while it works for null

How to pass javascript object from one page to other

I want to pass javascript object from one page to other page so anyone can tell me how to do it?
Is that possible to do so using jQuery?
Few ways
Server side postback
Have a POST form on your page and save your serialized object inside a hidden input then post it to the other page. You will be able to process that data on the server and most likely put it back somehow into the page. Either as javascript object or anything else.
Client side URL examination
Make a GET request to your other page by attaching your serialized object to URL as:
http://www.app.com/otherpage.xyz?MyObject=SerializedData
That other page can then easily parse its URL and deserialize data using Javascript.
What's in a window.name = local cross-page session
This is a special technique that's also used in a special javascript library that exposes window.name as a dictionary, so you can save many different objects into it and use it as local cross-page-session. It has some size limitations that may affect you, but check the linked page for that and test your browsers.
HTML5 local storage
HTML5 has the ability of local storage that you can use exactly for these purposes. But using it heavily depends on your browser requirements. Modern browsers support it though and data can be restored even after restarting browsers or computers...
Cookies
You can always use cookies but you may run into their limitations. These days cookies are not the best choice even though they have the ability to preserve data even longer than current window session.
Javascript object serialization
You will of course have to use some sort of a (de)serializer on your client side in some of the upper cases. Deserializers are rather easy to find (jQuery already includes a great function $.getJSON()) and are most likely part of your current javascript library already (not to even mention eval()).
But for object to JSON string serialization I'd recommend json2.js library that's also recommended by John Resig. This library uses in-browser implemented JSON (de)serialization features if they exist or uses it's own implementation when they don't. Hence recommendation.
That is only possible if the pages exist at the same time, and one page is opened from the other so that you have a reference to the other pages windows object.
If you navigate from one page to another, they don't exist at the same time, so you can't communicate like that. You would have to serialise the object into a string that you can send along in the request, for example sending JSON in the query string.
There are different ways of persisting data, like in the query string, post data, cookies, window name or HTML5 local storage, but all those methods can only persist string values, not Javascript objects.
This is possible to do, and you have a couple of options.
Local Storage
Can be added/eddited/removed at any stage and accessed across a domain. (doesn't work natively in ie6 and ie7 however there are work arounds for that)
The Window Object
I would put a massive cavet around this not being the best solution, it's not at all secure, so only use it for things that don't need to be kept private. window.name = { "json" : "object"} which is then available in the following page in the window.name property.
I believe that the only way to pass a javascript object from one page to another is to serialize it into string and pass it in url. For example if you have object
var temp = { id: 1, value: 'test' }
you may want to use JSON-js to serialize it and pass it in for example http://mysite.com/?data=serialization. Then after you load the page you need to deserialize it via for example $.parseJSON().
If your application uses sessions, you could serialize it (as per other answers) then POST it to the server where it is stored in a session variable. In the next page, you retrieve it from the session variable.
In Javascript, normally all variables only exist in a scope that is unique to that page load. They don't persist between different pages if there is a new page load.
The exceptions to this are
Cookies.
Local storage.
Cookies are truly cross-browser but are extremely limited in terms of size. You shouldn't expect to be able to store more than 4kB of cookies for a page reliably; in fact you probably shouldn't be using any more than 1kB. Cookie data slows down the loading of every page and other request, so it should be used sparingly.
There are various types of local storage available to Javascript, but the only practical cross-browser implementation of this is HTML5 webstorage which is implemented in all modern browsers (IE8+, FF, Chrome, Safari, etc), but is notably not implemented in IE6 or IE7, if that matters.
Both these approaches store a value in the user's browser which can be made to be persistent so that it can be written to and read from by pages from the same site, even between page views (and even, often, between browser sessions or computer reboots).
I wrote a library some time ago, that can store most js objects to localstorage. For example instances of your prototype classes, with references to other objects, self references included. Bare in mind that IE support is lackluster.

Javascript global namespace and dynamic property question

Say I want to have a global object which can be visible and accessible across pages(??)
// core.js
var MyLib = {}; // global Object cointainer
MyLib.value = 1;
If I define this way, then I can have access to MyLib.value in other places as long as I load the core.js.
However, if I want to add new property to object MyLib in somewhere else, say:
//extra.js
MyLib.otherVal = 2;
Then I try to access MyLib.otherVal from a different place, it is not available. I probably have some fundamental misunderstanding on how this suppose to work. I hope someone can enlighten me.
After reading the comments, I realized the scope I want is indeed across pages. Is that even possible?
thanks
Oliver
If you want to carry data across pages, there are really three major methods:
LocalStorage. See this page for a fairly thorough explanation of the concept, how to use it, and so forth. Here is a library dealing with JavaScript storage.
Cookies. Cookies can store 4KiB of data, but some users disable them.
window.name. You can store up to 2MiB of data in window.name. Here is a library that focuses on storing data in window.name; it seems fairly well-written.
You could potentially write an app to take advantage of all three of these techniques, starting with LocalStorage and falling back to window.name if all else fails.

Categories

Resources