Parsing strings from local storage with vanilla JavaScript [duplicate] - javascript

This is my code. I am trying since a couple of days to create an Array of Objects, which I will then store in Local Storage. Here is the problem, I need to first Get the existing value from Local Storage.
I then need to add the new data object to the existing array. I then convert it into JSON so that I can store it back in the local storage.
onRegisterSubmit(){
const user = {
a: this.a,
b: this.b,
c: this.c,
id: Date.now()
}
var abc = [];
var get = JSON.parse(localStorage.getItem('user'));
abc = [get];
abc.push(user);
localStorage.setItem('user', JSON.stringify(abc));
console.log(JSON.stringify(abc));
console.log(get);
}
I want the JSON to be an array of objects like this,
[{"hour":1,"minute":21,"ampm":"PM","repeatDays":[],"message":"","todayOrTomorrow":"Tomorrow","isRepeatMode":false,"isEnabled":false,"id":"1493797882440"},{"hour":1,"minute":24,"ampm":"PM","repeatDays":[],"message":"","todayOrTomorrow":"Tomorrow","isRepeatMode":false,"isEnabled":false,"id":"1493797896257"},{"hour":6,"minute":14,"ampm":"PM","repeatDays":[],"message":"","todayOrTomorrow":"Tomorrow","isRepeatMode":false,"isEnabled":false,"id":"1493815470408"}]
This is my JSON.
[[[[[[[{"id":1493820594019},{"id":1493820606448}],{"id":1493820609111}],{"id":1493820610150}],{"id":1493820610553}],{"id":1493820610827}],{"id":1493820611015}],{"id":1493820612018}]
I've been trying for several days and any help will be greatly appreciated.

The issues with that code are:
You're wrapping the result you get in an array, but in theory, you want to already have an array.
You're storing user, not get or abc. (You removed that with an edit.)
To store the array, do what you're doing:
localStorage.setItem("users", JSON.stringify(users));
To get the array:
users = JSON.parse(localStorage.getItem("users") || "[]");
Note how that provides a default (empty array) if getItem returns null because we've never stored our users there.
To add a user to the array:
users.push({id: 1, foo: "bar"});
Example (live on jsFiddle [Stack Snippets don't allow local storage]):
(function() { // Scoping function to avoid creating globals
// Loading
var users = JSON.parse(localStorage.getItem("users") || "[]");
console.log("# of users: " + users.length);
users.forEach(function(user, index) {
console.log("[" + index + "]: " + user.id);
});
// Modifying
var user = {
id: Math.floor(Math.random() * 1000000)
};
users.push(user);
console.log("Added user #" + user.id);
// Saving
localStorage.setItem("users", JSON.stringify(users));
})();
That shows you the list of current users in the console, adding one each time you refresh the page.

Try something like this:-
link https://jsfiddle.net/sureshraina/nLexkyfw/1/
var mydatas = new Array();
mydatas[0] = "data";
mydatas[1] = "data1";
mydatas[2] = "data2";
localStorage["mydatas"] = JSON.stringify(mydatas);
var datas = JSON.parse(localStorage["mydatas"]);

See this post.
You can't store Objects, you have to store a String. So the workaround is to stringify your Object before you store it (for example, you could use change it to a JSON object, store it, and read it again when needed).

Related

How do i append an array to an already existing state array?

Trying to implement pagination using react but cannot seem to figure out a way to append the new response to an already existing state variable.
I'm trying to implement a load more functionality wherein the data is appended to the list itself.
const handleLoadMoreClick = () => {
let tempObj = postparem;
tempObj.pagenumber = tempObj.pagenumber + 1;
setPostparem(tempObj);
getProductChildMenu(APIProductList, postparem);
setCopyMenu(...copyMenu, productChildMenu);
};
Currently the map function is running iterating over productChildMenu so it replaces the data but i want to append the data in productChildMenu to copyMenu.
I tried iterating over productChildMenu and pushing each element to copyMenu but it is coming out undefined or if i push it completely at once, it creates a 2d array which does not iterate in map correctly.
You must do the following to merge 2 objects into your state.
const handleLoadMoreClick = () => {
...
...
setCopyMenu({...copyMenu, ...productChildMenu});
};
You cannot do what you are doing with tempObject here:
let tempObj = postparem;
// this is wrong.
tempObj.pagenumber = tempObj.pagenumber + 1;
setPostparem(tempObj);
Even though you call the variable tempObj a "temporary object", it is not a new object. It is just a reference to the object stored in the variable postparem.
So your code is identical to the (equally wrong) postparem.pagenumber = postparem.pagenumber + 1.
Instead, you really have to create a new object:
let tempObj = {
...postparem,
};
and then you can either modify that, or already introduce your change on object creation.
That would look like
let tempObj = {
...postparem,
pagenumber: postparem.pagenumber + 1,
};
setPostparem(tempObj);
Or even a bit shorter:
setPostparem({
...postparem,
pagenumber: postparem.pagenumber + 1,
});

How do you update an array in localStorage without overwriting same-key values?

I am trying to retrieve an arrray from local storage, append a new array with the same keys, then stick it back into storage. I can't seem to get it to work however, I've tried turning my arrays into object, and objects into arrays (I'm new to programming so I'm not sure what the best way is.) I've also tried using the spread operator, object.entries(), object.assign() and a few other nonsensical options.
EDIT:
Saved to storage are the user input values:
"[[["name","bob ross"],["about","Painter"]]]"
I want the user to be able to add "Bilbo Baggins" for name, and "Hobbit" for about, then the storage should look like:
"[[["name","bob ross"],["about","Painter"]]], [[["name","Bilbo Baggins"],["about","Hobbit"]]]"
Any help would be greatly appreciated! Here's my code:
//============= Allows writing to LocalStorage without overwrite ==========================
submitbtn.addEventListener('click', function () {
const oldInfo = JSON.parse(localStorage.getItem('data')); // Retrieves info from storage to make it writeable
console.log('old Info: ', oldInfo); // Shows user what's currently saved in oldInfo
const newInfo = {};
newInfo.name = name.value; // Name and about are user input values
newInfo.about = about.value;
let array = Object.entries(newInfo); // Turns newInfo into an array
console.log('new info: ', newInfo);
oldInfo.push(array); // Appends newInfo to oldInfo without overwriting oldInfo data
console.log(oldInfo);
localStorage.setItem('data', JSON.stringify(oldInfo)); // Saves newly updated array to localStorage
});
I advise you to keep an object format, as you seems to only need to update properties, and not store.
That way, you can simply update your store by using your oldInfo object and using spread operator to create a new object from it (and get rid of conversion):
Let's say you put this in your localStorage (stringified):
const initialInfo = {
name: '',
about: ''
};
Then you can simply do
const oldInfo = JSON.parse(localStorage.getItem('data'));
localStorage.setItem(
'data',
JSON.stringify({ ...oldInfo, name: name.value, about: about.value })
);
This ... are syntaxic sugar for Object.assign, and to my mind, helps a lot to read instruction.
Here it means that you are 'cloning' the oldInfo object, and assigning new values to listed properties placed behind it.
EDIT:
After question editing; if you want to store multiple objects within an array, you should go with array spread operator. Like so:
const oldInfo = JSON.parse(localStorage.getItem('data'));
// oldInfo = [{ name: 'example', about: 'test' }];
const yourNewObject = {
value: name.value,
about: about.value
};
localStorage.setItem(
'data',
JSON.stringify([ ...oldInfo, yourNewObject ])
);
This way you will add an object to your array
I've cleaned up the code a little.
Your code should work, except that is was missing some error handling for the first load.
// Mock data
const name = { value: 'Foo name' };
const about = { value: 'Bar about' };
const submitbtn = document.getElementById('submit');
// Fake localStorage to make it work in the snippet
mockLocalStorage = {
getItem: (key) => this[key],
setItem: (key, value) => this[key] = value
};
submitbtn.addEventListener('click', function() {
// Make sure we get -something- back in case this is the first time we're accessing the storage.
const oldInfo = JSON.parse(mockLocalStorage.getItem('data') || '[]');
console.log('Before', oldInfo);
// The creation of the new object can be done in 1 step.
const array = Object.entries({
name: name.value,
about: about.value
});
oldInfo.push(array); // Appends newInfo to oldInfo without overwriting oldInfo data
console.log('After', oldInfo);
mockLocalStorage.setItem('data', JSON.stringify(oldInfo));
});
<button id="submit" type="button">Submit!</button>

Firebase: Can I combine a push with a multi-location update?

I need to create a new object with a generated key and update some other locations, and it should be atomic. Is there some way to do a push with a multi-location update, or do I have to use the old transaction method? This applies for any client platform, but here's an example in JavaScript.
var newData = {};
newData['/users/' + uid + '/last_update'] = Firebase.ServerValue.TIMESTAMP;
newData['/notes/' + /* NEW KEY ??? */] = {
user: uid,
...
};
ref.update(newData);
There are two ways to invoke push in Firebase's JavaScript SDK.
using push(newObject). This will generate a new push id and write the data at the location with that id.
using push(). This will generate a new push id and return a reference to the location with that id. This is a pure client-side operation.
Knowing #2, you can easily get a new push id client-side with:
var newKey = ref.push().key(); // on newer versions ref.push().key;
You can then use this key in your multi-location update.
I'm posting this to save some of future readers' time.
Frank van Puffelen 's answer (many many thanks to this guy!) uses key(), but it should be key.
key() throws TypeError: ref.push(...).key is not a function.
Also note that key gives the last part of a path, so the actual ref that you get it from is irrelevant.
Here is a generic example:
var ref = firebase.database().ref('this/is/irrelevant')
var key1 = ref.push().key // L33TP4THabcabcabcabc
var key2 = ref.push().key // L33TP4THxyzxyzxyzxyz
var updates = {};
updates['path1/'+key1] = 'value1'
updates['path2/'+key2] = 'value2'
ref.update(updates);
that would create this:
{
'path1':
{
'L33TP4THabcabcabcabc': 'value1'
},
'path2':
{
'L33TP4THxyzxyzxyzxyz': 'value2'
}
}
I'm new to firebase, please correct me if I'm wrong.

Prevent a duplicate item being added in Localstorage with AngularJS

I am working on a prototype that stores products (like a favourite) into localStorage but I am struggling to check to see if an item already exists in localStorage so its not added again.
Where would the best place be to check for a duplicate entry and handle it gracefully?
My sample controller is below:
function dCtrl($scope, $filter) {
$scope.d = [
{id:'1',d_name:'Product 1',colour:'Blue'},
{id:'2',d_name:'Product 2',colour:'Red'},
{id:'3',d_name:'Product 3',colour:'Cream'},
{id:'4',d_name:'Product 4',colour:'White'},
{id:'5',d_name:'Product 5',colour:'Green'},
{id:'6',d_name:'Product 6',colour:'Black'},
{id:'7',d_name:'Product 7',colour:'Purple'},
{id:'8',d_name:'Product 8',colour:'Grey'},
{id:'9',d_name:'Product 9',colour:'Yellow'},
{id:'10',d_name:'Product 10',colour:'Indigo'}
];
$scope.getDetails = function (id, favDresses) {
//get the object of the item clicked
single_object = $filter('filter')($scope.d, {id:id})[0];
// If you want to see the result, check console.log
console.log(single_object);
console.log('ID:' + id + ' - save this object to localStorage');
//set localstorage var
var storage = localStorage.getItem('newfavdresses');
//check to see if the localStorage array is empty (not null)
if(storage != null) {
//if it isnt, parse the string
favDresses = JSON.parse(localStorage.getItem('newfavdresses'));
//push into the array
favDresses.push(single_object);
//set the item in localstorage
localStorage.setItem("newfavdresses",JSON.stringify(favDresses));
} else {
//if the array is null, create it
var favDresses = [];
//and push the item into it
favDresses.push(single_object);
//set the item in local storage
localStorage.setItem("newfavdresses",JSON.stringify(favDresses));
}
}
$scope.clearStorage = function() {
localStorage.clear();
alert('Local Storage Cleared');
}
//get localStorage items
var dresses = localStorage.getItem("newfavdresses");
dresses = JSON.parse(dresses);
console.log(dresses);
}
jsFiddle demo - https://jsfiddle.net/dwhiteside86/Lt7aP/2261/
My suggestion is work with live javascript array stored in service.
You would load this array from localStorage when service initializes or set to empty array if nothing in storage.
Then whenever you update the stored array you always store back the whole thing into localStorage so that the stored version is always a string replica of the live one.
This way you only use getItem() once and then have a simple service method storeLocal() that you call each time you modify array or object in array.
Another thing you might look at is ngStorage that does all of the above for you
Look at https://github.com/grevory/angular-local-storage, I believe it will solve all your issues. This library will bind your scope property to local storage so You'll dont care about how it stores.

HTML5 Local Storage with saved integers and variables

I'm trying to achieve a function that makes the user able to save a mathematical formula that uses static variables that I've already created and save them with Local Storage.
Then the script fetches that formula from the Local Storage, does the math and displays the results on a table.
I have everything in order, except the fetching part;
as localStorage.getItem() returns a string, and converting it with parseFloat()/parseInt() only returns the first integer or NaN.
Both of this messes up the expected the results.
Is there any way I can get Objects from localStoage that contains both integers and variables?
Heres an example of a formula that should work, fetched by 5 localStorage.getItem() requests.
avgFrags*250
avgDmg*(10/(avgTier+2))*(0.23+2*avgTier/100)
avgSpots*150
log(avgCap+1,1.732)*150
avgDef*150
Any ideas or alternatives?
EDIT:
Each line represents the output of a getItem() request;
form_frag = localStorage.getItem('formula_frag');
form_dmg = localStorage.getItem('formula_dmg');
form_spot = localStorage.getItem('formula_spot');
form_cap = localStorage.getItem('formula_cap');
form_def = localStorage.getItem('formula_def');
localStorage store in a key-value store where every value is pushed to a string. If you are certent that you are handling "integers" you can push the string to a number:
var avgFrags = +localStorage.getItem('avgFrags'); // The + infront pushes the string to number.
I'm not completely sure that I understand your question.
(+"123") === 123
You can convert easily convert your strings to functions if you know the variable names before hand using Function(). The first parameter(s) are your function arguments and the last is your function body.
var func1 = Function('avgFrags', 'return avgFrags * 250;');
This is equivalent to:
function func1(avgFrags) {
return avgFrags * 250;
}
Known Function Signature
If you know what variable names will be used for each item in local storage then it should be easy for you to do what you want with function:
// from your edited question
form_frag = localStorage.getItem('formula_frag');
form_dmg = localStorage.getItem('formula_dmg');
// ... create functions
var fragsFunc = Function('avgFrags', form_frg );
var dmgFunc = Function('avgDmg', 'avgTier', form_dmg );
// ... get frags
var frags = fragsFunc (10); // frags = 2500; // if sample in storage
Unknown Function Signature
Now if you have a limited amount of variable names and you don't know which ones will be used with each function then you can do something like:
var avgFrags, avgDamage, avgTier, avgSpots, avgCap, avgDef;
// ... get from storage
form_frag = localStorage.getItem('formula_frag');
form_dmg = localStorage.getItem('formula_dmg');
// ... create functions
var fragsFunc = Function('avgFrags', 'avgDamage', 'avgTier', 'avgSpots', 'avgCap', 'avgDef', form_frag);
var dmgFunc = Function('avgFrags', 'avgDamage', 'avgTier', 'avgSpots', 'avgCap', 'avgDef', form_frag);
// ... get frags, only the first argument is used, but we don't know that.
var frags = fragsFunc (avgFrags, avgDamage, avgTier, avgSpots, avgCap, avgDef); // frags = 2500; // if sample in storage
You can make this simpler by having just one variable passed into the function which is an object that holds all of the arguments that can be passed to the function. Just have to make sure that the function writer uses that object.
var settings = {
avgFrags: 10,
avgDamage: 50,
// ...
};
var fragsFunc = Function('s', 's.avgFrags * 250');
var frags = fragsFunc (settings);
Getting parts with an regex
I am assuming that the above will get the job done, that you don't really want an object with variable names and numbers and operators.
If you just need the variable names and numbers (and operators) you can use a regex for that.
([a-z_$][\w\d]*)|([0-9]*\.?[0-9]+)|([^\w\d\s])
You can use that to create an array with each part. Also each part is grouped so you know which is a variable name, which is a number, and which is an other (parenthesis or operator)
var re = /(\w[\w\d]*)|([0-9]*\.?[0-9]+)|([^\w\d\s])/g,
match,
results;
while ((match = re.exec(localStorage.getItem('formula_frag'))) {
results.push({
text: match[0],
type: (match[1]) ? 'var' | (match[2]) ? 'number' : 'other'
})
}
You can view the output of the regex with your sample data using REY.
Yes you can set Objects in localstorage
Here is the fiddle for that - http://jsfiddle.net/sahilbatla/2z0dq6o3/
Storage.prototype.setObject = function(key, value) {
this.setItem(key, JSON.stringify(value));
}
Storage.prototype.getObject = function(key) {
var value = this.getItem(key);
return value && JSON.parse(value);
}
$(function() {
localStorage.setObject('x', {1: 2, 2: "s"})
console.log(localStorage.getObject('x'));
});

Categories