Little change of my code and it's partially works :)
var db = {
hotels: JSON.parse(localStorage.getItem('table') || "[]"),
get objects() {return this.hotels},
set objects(obj) {
obj = this.hotels;
localStorage.setItem('table', JSON.stringify(obj))
}
}
jQuery(function(){
var count = localStorage.getItem('count');
if(!count) {
count = 0;
}
function Add(item){
var client = {
ID : jQuery(item).find("#txtID").val(),
Name : jQuery(item).find("#txtName").val(),
Photo : jQuery(item).find("#txtPhone").val(),
Link : jQuery(item).find("#txtEmail").val()
};
db.objects = db.objects.push(client);
count = count+1;
localStorage.setItem('count',count);
jQuery('.panel2 a span').text('('+ localStorage.getItem('count') +')');
jQuery(item).find('.add_rem').hide();
jQuery(item).find('.remove').show();
jQuery("#tblList .empty").hide();
jQuery("#tblList").find('li:gt(0)').remove();
jQuery.each(db.objects,function(i,element) {
jQuery("#tblList").append("<li class='added"+db.objects[i].ID+"'>"+
"<img src='../../images/general/delete.gif' alt='Delete"+i+"' class='delete'/>" +
"<a href='"+db.objects[i].Link+"' title='"+db.objects[i].Name+"'>"+
" <img src='"+db.objects[i].Photo+"' alt='"+db.objects[i].Name+"'>" +
" <span>"+db.objects[i].Name+"</span>" +
" </a>" +
"</li>");
})
return true;
}
function Delete(item){
jQuery(item).prev('.add_rem').show();
jQuery(item).find('.remove').hide();
jQuery(item).find('.remove').removeAttr('alt');
}
function List(){
if(count > 0) {
jQuery("#tblList .empty").hide();
jQuery('.panel2 a span').text('('+ localStorage.getItem('count') +')');
}
for(var i= 0; i<= count; i++) {
var cli = JSON.parse(db.hotels);
if(cli[i] != null){
jQuery("#"+cli[i].ID).find('.add_rem').hide();
jQuery("#"+cli[i].ID).find('.remove').show();
jQuery("#"+cli[i].ID).find('.remove').attr('alt','Delete'+i);
jQuery("#tblList").append("<li class='added"+cli[i].ID+"'>"+
"<img src='../../images/general/delete.gif' alt='Delete"+i+"' class='delete'/>" +
"<a href='"+cli[i].Link+"' title='"+cli[i].Name+"'>"+
" <img src='"+cli[i].Photo+"' alt='"+cli[i].Name+"'>" +
" <span>"+cli[i].Name+"</span>" +
" </a>" +
"</li>");
}
}
}
jQuery("#frmCadastre").bind('submit',function(e){
e.preventDefault()
return Add(this);
});
List();
jQuery(".remove, .delete").bind("click", function(e){
e.preventDefault();
Delete(this);
List();
});
})
now my question is how to push element to array after page refresh this is located in function Add()
array looks like this
"["{"ID":"1","Name":"test","photo":"/link/to/photo.jpg"}"]"
and if i add another element before page refresh it works great
"["{"ID":"0","Name":"test0","photo":"/link/to/photo0.jpg"}","{"ID":"1","Name":"test1","photo":"/link/to/photo1.jpg"}"]"
but if i Reload page and try to add an element Firebug is throwing:
`TypeError: db.objects.push is not a function
db.objects = db.objects.push(client);`
Little change of my code and it's partially works :)
var db = {
hotels: JSON.parse(localStorage.getItem('table') || "[]"),
get objects() {return this.hotels},
set objects(obj) {
obj = this.hotels;
localStorage.setItem('table', JSON.stringify(obj))
}
}
jQuery(function(){
var count = localStorage.getItem('count');
if(!count) {
count = 0;
}
function Add(item){
var client = {
ID : jQuery(item).find("#txtID").val(),
Name : jQuery(item).find("#txtName").val(),
Photo : jQuery(item).find("#txtPhone").val(),
Link : jQuery(item).find("#txtEmail").val()
};
db.objects = db.objects.push(client);
count = count+1;
localStorage.setItem('count',count);
jQuery('.panel2 a span').text('('+ localStorage.getItem('count') +')');
jQuery(item).find('.add_rem').hide();
jQuery(item).find('.remove').show();
jQuery("#tblList .empty").hide();
jQuery("#tblList").find('li:gt(0)').remove();
jQuery.each(db.objects,function(i,element) {
jQuery("#tblList").append("<li class='added"+db.objects[i].ID+"'>"+
"<img src='../../images/general/delete.gif' alt='Delete"+i+"' class='delete'/>" +
"<a href='"+db.objects[i].Link+"' title='"+db.objects[i].Name+"'>"+
" <img src='"+db.objects[i].Photo+"' alt='"+db.objects[i].Name+"'>" +
" <span>"+db.objects[i].Name+"</span>" +
" </a>" +
"</li>");
})
return true;
}
function Delete(item){
jQuery(item).prev('.add_rem').show();
jQuery(item).find('.remove').hide();
jQuery(item).find('.remove').removeAttr('alt');
}
function List(){
if(count > 0) {
jQuery("#tblList .empty").hide();
jQuery('.panel2 a span').text('('+ localStorage.getItem('count') +')');
}
for(var i= 0; i<= count; i++) {
var cli = JSON.parse(db.hotels);
if(cli[i] != null){
jQuery("#"+cli[i].ID).find('.add_rem').hide();
jQuery("#"+cli[i].ID).find('.remove').show();
jQuery("#"+cli[i].ID).find('.remove').attr('alt','Delete'+i);
jQuery("#tblList").append("<li class='added"+cli[i].ID+"'>"+
"<img src='../../images/general/delete.gif' alt='Delete"+i+"' class='delete'/>" +
"<a href='"+cli[i].Link+"' title='"+cli[i].Name+"'>"+
" <img src='"+cli[i].Photo+"' alt='"+cli[i].Name+"'>" +
" <span>"+cli[i].Name+"</span>" +
" </a>" +
"</li>");
}
}
}
jQuery("#frmCadastre").bind('submit',function(e){
e.preventDefault()
return Add(this);
});
List();
jQuery(".remove, .delete").bind("click", function(e){
e.preventDefault();
Delete(this);
List();
});
})
now my question is how to push element to array after page refresh this is located in function Add()
array looks like this
"["{"ID":"1","Name":"test","photo":"/link/to/photo.jpg"}"]"
and if i add another element before page refresh it works great
"["{"ID":"0","Name":"test0","photo":"/link/to/photo0.jpg"}","{"ID":"1","Name":"test1","photo":"/link/to/photo1.jpg"}"]"
but if i Reload page and try to add an element Firebug is throwing:
`TypeError: db.objects.push is not a function
db.objects = db.objects.push(client);`
Share
Improve this question
edited Dec 2, 2013 at 19:19
arclite
asked Nov 25, 2013 at 0:55
arclitearclite
5281 gold badge6 silver badges23 bronze badges
8
-
Looks like you have JSON inside JSON... which is horrible. You seem to add JSON to
tbClients
and then convert the whole array to JSON. Why are you doing this? Add the objects themselves to the object. – Felix Kling Commented Nov 25, 2013 at 0:59 -
1
"Add the objects themselves to the array". E.g.
tbClients[selected_index] = {....};
, nottbClients[selected_index] = JSON.stringify({....});
. The only time you should parse from and convert to JSON is when you read from or write tolocalStorage
. – Felix Kling Commented Nov 25, 2013 at 1:05 - You wrote in one of your ments "and can you tell me why on my site the local storage elements have so many backslashes ?". That's the case in both situations. Noticed that you are in a different tab in your second image? If you select the first tab like in the first image, you should see the same value. Your code behaves the same way, the tool you are using just presents it differently. – Felix Kling Commented Nov 25, 2013 at 1:36
-
"if i remove JSON.stringify it'll work only for one element" As I said, you only need to use
JSON.stringify
when you write tolocalStorage
andJSON.parse
when you read from it. When you are adding or reading objects from the array, you should not use it. If you do this consistently your code will work fine. If it only works for the first element, then you are doing something wrong. – Felix Kling Commented Nov 25, 2013 at 1:38 - I don't know what tool you are using, but the same code won't behave differently on different sites. The backslashes are only there because you have so many tested strings and the quotation marks have to escaped properly. If you fix your code to as I suggested it might be resolved. – Felix Kling Commented Nov 25, 2013 at 1:42
1 Answer
Reset to default 10 +50We will start to clear out what happens with HTML5 Local Storage. Local storage is a place in your disk defined by every browser that supports it. These places may be different for every browser. They hold tuples with keys and values, both strings. If you want to save a whole object to the disk, you must serialize it. That means you have to transform it into an array of data, in our case chars -> string. In javascript the most mon object serialize function is JSON.stringify
. Its input is a valid JSON object, which in our case is an array and it will make it into a string using the literals you use to initialize an object like {x:5}
. JSON.stringify([{x:5},{x:6},{x:7}])
will have the following output: "[{x:5},{x:6},{x:7}]"
. And to reconstruct your object from a string you use JSON.parse(x)
where x is a valid json string. You want now to have an array of objects, the first thing you'll think of is to serialize your array you have as a var in your program and add a special key you remember to store it into your disk. Each browser has seperate localStorage for every site that is hosted by a server.
An example that stores a value bound to a key in localstorage is this:
localStorage.setItem('x','5');
localStorage['x'] = 5;
localStorage.x = 5;
all of them do the same thing, and their speed is in descending order. Now you have at Chrome->resources->localstorage:
+-------------------+
| Key | Value |
+---------+---------+
| x | "5" |
+---------+---------+
When you make your first visit to the page, you have nothing in localStorage, so you must have some initial values. Trying to get a value by:
return localStorage.getItem('x');
return localStorage['x'];
return localStorage.x;
will give you undefined. There is a nice operator made in javascript and is the ||
.
null || 5 //returns 5
undefined || 3.14 //returns 3.14
'' || 6 //returns 6
[] || {} //returns []
If the left operand "exists", return it, else return the right one. This makes things faster with localStorage.getItem('x') || 5
so if a tuple with key x exists it will return the value of the item with the specified key, else it will return the 5, which is our initial value.
Let's get back to the localStorage again. Remember the tuples are saved into the disk, which is vastly slower to access than things in ram. If I want to read the value of an item in the localStorage let say in a loop, several times, should I read it directly from the disk, or should I read it once from the disk and save it into ram to access it faster? You surely know what makes more sense...So I must have a variable that is the clone of the one in the localStorage. Let's say I name it private_var. It must have an initial value which will be:
var private_array = JSON.parse(localStorage.getItem('array')) || [];
When you want to change your array in localstorage (e.g pushed an item) you use:
private_array.push(item)
localStorage.setItem('array', JSON.stringify(private_array))
Your localstorage will be like:
+---------+-----------------------------------------+
| Key | Value |
+---------+-----------------------------------------+
| array | [{"name":"george", "surname":"bush"}] |
+---------+-----------------------------------------+
To make things faster in terms of code production, not program speed you can define setters and getters.
var obj = {
temp: 5,
get x( ) { return this.temp },
set x(value) { this.temp = value }
}
we have an object named obj, a member temp and a setter and a getter function, just like in some java code. You can check obj.temp === 5
. These special operators allow us to write
obj.x = obj.x + 6;
and it will be executed as something like this:
obj.set_x(obj.get_x() + 6);
So let's say you have an interface named db (database, similar to what a locastorage is) and a "private member" which is clearly not. You can see an implementation at http://ejohn/blog/javascript-getters-and-setters/ with __define(G/S)etter__ which has real private member, but this one is surely faster to write and more readable.
var db = {
cl_arr: JSON.parse(localStorage.getItem('array')) || [],
get clients( ) { return this.cl_arr },
set clients(v) {
localStorage.setItem('array', JSON.stringify(this.cl_arr));
if(v.constructor === Array) { this.cl_arr = v }
}
}
so when I execute:
db.clients.filter(function(client) { return client.money > 1000 });
this will be executed
db.get_clients().filter...;
And when I try to change the array, I will write this
db.clients = db.clients.push(client);
Even if the push method can change the array, only the get function will be triggered so only the "private" cl_arr variable will change, to trigger the setter which updates our localStorage too I have to write the db.clients = ...