834

If I didn't need localStorage, my code would look like this:

var names=new Array(); 
names[0]=prompt("New member name?");

This works. However, I need to store this variable in localStorage and it's proving quite stubborn. I've tried:

var localStorage[names] = new Array();
localStorage.names[0] = prompt("New member name?");

Where am I going wrong?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
David
  • 13,619
  • 15
  • 45
  • 51
  • I have posted up a complete solution for maintaining arrays in localStorage or sessionStorage at the thread this was closed as a duplicate of, because nether thread really answers the question originally posed by Dave: http://stackoverflow.com/a/23516713/2208713. Hope it helps some people. – Andy Lorenz May 07 '14 at 11:37
  • Easy way to handle that kind of condition you can use opendb library very use full to deal with array, object. You can follow this link https://github.com/pankajbisht/openDB – Pankaj Bisht Jan 24 '18 at 10:58

6 Answers6

1572

localStorage only supports strings. Use JSON.stringify() and JSON.parse().

var names = [];
names[0] = prompt("New member name?");
localStorage.setItem("names", JSON.stringify(names));

//...
var storedNames = JSON.parse(localStorage.getItem("names"));

You can also use direct access to set/get item:

localStorage.names = JSON.stringify(names);
var storedNames = JSON.parse(localStorage.names);
Douwe de Haan
  • 6,247
  • 1
  • 30
  • 45
Dagg Nabbit
  • 75,346
  • 19
  • 113
  • 141
  • 6
    JSON is not supported in IE7 and earlier. – Saif Bechan Nov 22 '11 at 08:44
  • 526
    @SaifBechan Don't worry about IE 6/7, we are talking about `localStorage` – tungd Jan 10 '12 at 04:40
  • 1
    I would test whether localStorage['names'] returns a value before parsing it or an error will be thrown. – Jonathan Tonge Mar 15 '13 at 19:21
  • 7
    @JonathanTonge, you could do something like `JSON.parse(localStorage["names"] || null)` if you wanted. – Dagg Nabbit Apr 12 '13 at 00:17
  • 1
    If you compress the resulting string, up to 4x times as much data can be stored. See https://jsfiddle.net/davidwihl/n12rogcx/ (uses the LZ JavaScript library: http://pieroxy.net/blog/pages/lz-string/index.html) – David Wihl Mar 07 '16 at 14:56
  • 3
    @SaifBechan `if(typeof JSON == "undefined") { alert("Upgrade your browser."); }` – Michaël van de Weerd Mar 16 '16 at 08:53
  • You could also do `JSON.parse(localStorage.getItem("names") || '[]')` (typescript doesn't complain then) – ali_wetrill Apr 08 '21 at 23:09
  • 1
    ali_wetrill has a good pointer, if you use `var storedNames = JSON.parse(localStorage.names || '[]');` or `var storedNames = JSON.parse(localStorage.names || null)` it'll default to either the empty string or null, as desired, in the case where the localStorage item has not been defined yet. – albertrw Sep 09 '21 at 16:52
  • @DaggNabbit: sir i received Converting circular structure to JSON --> starting at object with constructor 'TView this error after store array in the localstorage.can you tell me me why i get this error? – Kapil Soni Jun 20 '22 at 05:07
144

The localStorage and sessionStorage can only handle strings. You can extend the default storage-objects to handle arrays and objects. Just include this script and use the new methods:

Storage.prototype.setObj = function(key, obj) {
    return this.setItem(key, JSON.stringify(obj))
}
Storage.prototype.getObj = function(key) {
    return JSON.parse(this.getItem(key))
}

Use localStorage.setObj(key, value) to save an array or object and localStorage.getObj(key) to retrieve it. The same methods work with the sessionStorage object.

If you just use the new methods to access the storage, every value will be converted to a JSON-string before saving and parsed before it is returned by the getter.

Sebastian
  • 1,651
  • 1
  • 11
  • 12
  • 1
    if you needed all of them how would you retrieve them? – Dvid Silva Nov 16 '13 at 23:29
  • 1
    The storage objects provide the property "length" to determine the count of saved objects and the method "key(int index)" to get the current key. So you can try: `for (var i = 0; i < localStorage.length; i++) console.log( localStorage.key(i) +" has value " + localStorage[localStorage.key(i)] )` – Sebastian Dec 05 '13 at 11:55
  • 1
    @Sebastian using **localStorage.length** could be wrong in some cases if the website is also **localStorage** to store something. – PG1 Jun 11 '14 at 09:06
  • You may prefix your module specific values and delete everything with that prefix while iterating all elements of localStorage. – Sebastian Oct 06 '14 at 21:15
  • 1
    I used the same approch in my solution, which provides a minimalistic interface to how localStorage should work :) https://github.com/zevero/simpleWebstorage – zevero Sep 28 '16 at 10:26
19

Use JSON.stringify() and JSON.parse() as suggested by no! This prevents the maybe rare but possible problem of a member name which includes the delimiter (e.g. member name three|||bars).

Matt
  • 74,352
  • 26
  • 153
  • 180
jayeff
  • 1,689
  • 14
  • 14
  • Can you show us a better alternative? – Phil Jun 19 '13 at 14:35
  • 13
    This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. – ChiefTwoPencils Jul 12 '14 at 09:20
  • @ChiefTwoPencils have you read comments before flagging? – J0HN Jul 12 '14 at 10:37
  • 2
    @J0HN: yes I did. Since when is a members reputation good reason to break the rules? In fact, doesn't the auto-messaging on recommended deletions specifically mention *not* posting commentary as answers and suggests the poster wait until they have enough reputation to comment and up-vote until then? Poster says it's not an answer; what more evidence needs to exist? – ChiefTwoPencils Jul 12 '14 at 15:18
  • 2
    @ChiefTwoPencils: Some historical context: When I posted this comment the accepted answer proposed doing a join and split with "|||" by Ian (Note: this answer no longer exists). Because I considered this answer actually harmful I posted my answer. Today my non-answer is no longer necessary (the correct answer is accepted and has a healthy dose of upvotes). I'm not too familiar with the guidelines: Is it ok/recommended to delete my "answer"? – jayeff Jul 13 '14 at 11:13
9

Just created this:

https://gist.github.com/3854049

//Setter
Storage.setObj('users.albums.sexPistols',"blah");
Storage.setObj('users.albums.sexPistols',{ sid : "My Way", nancy : "Bitch" });
Storage.setObj('users.albums.sexPistols.sid',"Other songs");

//Getters
Storage.getObj('users');
Storage.getObj('users.albums');
Storage.getObj('users.albums.sexPistols');
Storage.getObj('users.albums.sexPistols.sid');
Storage.getObj('users.albums.sexPistols.nancy');
jonsca
  • 10,218
  • 26
  • 54
  • 62
Klederson Bueno
  • 330
  • 3
  • 6
  • 3
    This is the sort of thing I was looking for, except it would walk the keys of the provided object and save the (single) linked value in each. Much obliged for the inspire. – twobob Feb 24 '16 at 23:50
4

The JSON approach works, on ie 7 you need json2.js, with it it works perfectly and despite the one comment saying otherwise there is localStorage on it. it really seems like the best solution with the least hassle. Of course one could write scripts to do essentially the same thing as json2 does but there is little point in that.

at least with the following version string there is localStorage, but as said you need to include json2.js because that isn't included by the browser itself: 4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; BRI/2; NP06; .NET4.0C; .NET4.0E; Zune 4.7) (I would have made this a comment on the reply, but can't).

Lassi Kinnunen
  • 448
  • 4
  • 10
2

Another solution would be to write a wrapper that store the array like this:

localStorage.setItem('names_length', names.length);
localStorage.setItem('names_0', names[0]);
localStorage.setItem('names_1', names[1]);
localStorage.setItem('names_' + n, names[n]);

Removes the overhead of converting to JSON, but would be annoying if you need to remove elements, as you would have to re-index the array :)

Markus Hedlund
  • 23,374
  • 22
  • 80
  • 109
  • 1
    Kills the performance gain of not JSONifying. – Camilo Martin Feb 23 '12 at 15:05
  • 1
    Instead of `names_length` use `names_keys` and you don't need to re-index! This would also allow you to use string keys. Of course this makes only sense if the array elements are kind of hugh. – PiTheNumber Aug 26 '13 at 18:26
  • @PiTheNumber If `names_keys` contains an array of indices, isn't that a chicken/egg situation? – Markus Hedlund Aug 26 '13 at 19:20
  • @Znarkus As I said, this makes only sense for hugh array elements. If you have for example 100KB per element it would be better to use a small entry with `keys`. – PiTheNumber Aug 27 '13 at 07:11
  • @PiTheNumber What is *hugh*? – Alix Axel Apr 16 '14 at 15:59
  • @AlixAxel I don't have an exact number for you but if things are slowing down because of reindexing or you just don't like to rebuild the index you might want to consider storing the keys instead. Or the other way around: If you store 10'000 integer values your index in names_keys would be larger than you actually data. – PiTheNumber Apr 22 '14 at 16:03