how do I create list of unique values and systematically store them in localstorage - javascript

I'm trying to build a history list of clicked clicked page elements and store that list into HTML local storage, to be later displayed back to the user. The main pre-requisite is that the list cannot contain duplicates, so for example if the user clicks on item A and then on item B and again back on item A, only A and B are recorded. The third click is not recorded because it is not unique.
I'm also using persist.js.
I noticed that I am able to name the storage and give it a key and both are stored together in the real key of the localstorage thus: myStorageName>myKeyand my value is whatever I put there.
Here's the thing. I know you can store stringyfied JSON there but my list is built up from simple javascript variables one at at time.
I know what to do for the first click:
myStorageName.set(myKey, myCurrentElementId); // myCurrentElementId = this.id
now on the second click this is where I'm beginning to getting stuck. There is the original variable value already stored, now I want to append the new variable value. Assume that I can get the value from the store like this:
var dataExtract = myStorageName.get(myKey);
myObject = JSON.parse(dataExtract);
But how do I then turn this into a JSONstring -able thing (sorry I don't even know what it should be) that contains only a list of unique values. Does this make any sense to anyone?

First of all, you don't want to keep writing to/from localStorage everytime a link is clicked, because this'll slow down your page. Keep an updated Array populated with the element ids, then write to localStorage before the user navigates away from the page (by binding to the window's onbeforeunload event, for instance).
First:
var clickedLinks = []; // this Array will hold the ids of the clicked links
function uniqueClick(id){
return !~clickedLinks.indexOf(id); // this tests whether the id is already in the Array
};
In your click handler:
if(uniqueClick(this.id)){
clickedLinks.push(this.id); // append the new element id to the Array
}
Bind to window.onunload to save the Array before the user navigates from the page:
window.onunload = function(){
localStorage.setItem('clickedLinks',JSON.stringify(clickedLinks)); // stringify the Array and save to localStorage
}
To retrieve clickedLinks on subsequent page visit:
// convert the String back to an Array; try/catch used here in case the value in localStorage is modified and unable to be parsed, in which case clickedLinks will be initialized to an empty Array
try{
var clickedLinks = JSON.parse(localStorage.getItem('clickedLinks')) || [];
}catch(e){
var clickedLinks = [];
}
You may want to replace the first line (var clickedLinks = [];) with this last bit of code, as it will initialize the Array if it doesn't exist.
UPDATE:
IE8 does not support Array.indexOf. Alternatives might be:
use jQuery's $.inArray by replacing !~clickedLinks.indexOf(id); with !~$.inArray(id, clickedLinks);
Detect whether Array.prototype.indexOf is supported. If not, shim it with the code provided on this page.

Your model has an error. At the first time, you save a primitive value. Then, you want to "append" another value to it. Seems like you actually want to use an object:
var myObj = localStorage.getItem("myName");
if(myObj) myObj = JSON.parse(myObj); //Variable exists
else myObj = {}; //Elsem create a new object
function appendNewValue(name, value){
myObj[name] = value;
localStorage.setItem("myName", JSON.stringify(myObj));
/* Saves data immediately. Instead of saving every time, you can
also add this persistence feature to the `(before)unload` handler. */
}

I suggest to define in your code this:
localStorage.set= function(key,val)
{
localStorage.setItem(JSON.stringify(val));
}
localStorage.get = function(key,defval)
{
var val = localStorage.getItem(key);
if( typeof val == "undefined" ) return defval;
return JSON.parse(val);
}
and use them instead of get/setItem. They will give you ready to use JS values that you can use in the way you need.

Related

How to store <div> elements to localStorage?

I´m trying to set an array of items(divs) to Local Storage for when the page reloads these elements being shown in the Ui. The function checks if there is an array already stored with that name, and if so, the local storage must clean this item and then set the array updated whit these items that were added in another part of the code. But when I see what local storage is returning after I set this array I find an array with empty objects with the same length that would must have, and in this same function before I set the array is correct with all the items there.
What am I missing?
function setToLocalStorage(){
console.log(items); //the is array is there with all items
if(!!localStorage.getItem("items")){
localStorage.removeItem("items");
}
localStorage.setItem("items",JSON.stringify(items));
}
function getDataFromLocalStorage(){
let elements=JSON.parse(localStorage.getItem('items'));
console.log(elements); //I get an array with empty objects with the same length of the first
}
to set an array of items(divs) to Local Storage
The localStorage code is fine, the thing is that you cannot simply JSON-serialise a DOM element.
For example, this code:
let el = document.createElement('div');
el.textContent = "Test";
console.log('element:', el);
console.log('element to JSON:', JSON.stringify(el));
will output:
element: <div>​Test​</div>​
element to JSON: {}
So you will need to use JSON.stringify on the actual data that you used to create those DIVs.

Checking for a key in an object containing array of objects saved in chrome.storage.local

I currently save a bunch of objects (thousands) into the chrome.storage.local and then when on a specific web page checking whether specific IDs on the web page are in fact saved in local storage.
Here's a pseudo code
Bakcground script:
var storage = chrome.storage.local;
var json = '[{"kek1": {"aaa": "aaaValue", "bbb": "bbbValue", "ccc": "cccValue"}},{"kek2": {"ddd": "dddValue", "eee": "eeeValue", "fff": "fffValue"}}]';
var jsonParsed = JSON.parse(json);
jsonParsed.forEach(function(object) {
storage.set(object);
});
Content script (when on a specific page):
ids.forEach(function(id) {
storage.get(id, function(result){
if(!isEmpty(result)) {
//we found it, nice, now flag it as found
}
});
});
function isEmpty(obj) {
for(var key in obj) {
if(obj.hasOwnProperty(key))
return false;
}
return true;
}
Which is easy and nice since I only have to do storage.get(id, ...
Unfortunately, I save a lot of stuff in storage, some of it I need to be removing periodically, which then becomes a hustle since I have to loop through all the objects and determining whether that particular object needs to be removed or it needs to remain.
So i decided I would do like these "parent object". Ie one object for settings, containing an array of objects with different settings the user would save. One object for the stuff that needs to be removed, containing an array objects. Etc
Like so - all relevant info that I want to remove periodically will be under one key "test" (temp name):
var json = '{"test":[{"kek1": {"aaa": "aaaValue", "bbb": "bbbValue", "ccc": "cccValue"}},{"kek2": {"ddd": "dddValue", "eee": "eeeValue", "fff": "fffValue"}}]}';
I know how to access the nested objects and their values:
var jsonParsed = JSON.parse(json);
jsonParsed.test[0].kek1.aaa
But I don't know how I would easily check for the keys saved in the storage since I would have to specify the "element number" ([i]).
Do I just do a for loop itterating over the array like so?
for (i = 0; i < jsonParsed.test.length; i++) {
var getKey = Object.keys(jsonParsed.test[i]);
if (getKey[0] == 'theKeyImLookingFor') {
//do stuff
}
}
To me that feels like non ideal solution since the for loop would have to run for each of the ids on the page and there could sometimes be close to 4000 of them. (4000 for loops back to back)
Is it a good idea to save a single object holding an array of thousands of other objects?
Am I doing it wrong or is this the way to go?
But I don't know how I would easily check for the keys saved in the storage
Use the standard Array methods like find or findIndex:
const i = arrayOfObjects.findIndex(o => 'someKey' in o);
Is it a good idea to save a single object holding an array of thousands of other objects?
It's a bad idea performance-wise.
What you probably need here is an additional value in the storage that would contain an array with ids of other values in the storage that need to be processed in some fashion e.g. expired/removed. It's basically like a database index so you would update it every time when writing an individual object. Since it contains only the ids, updating it is cheaper than rewriting the entire data.
Also, instead of performing lots of calls to the API, do just a single call:
// writing
chrome.storage.local.set(Object.assign({}, ...arrayOfObjects));
// reading
chrome.storage.local.get(arrayOfIds, data => {
for (const id of arrayOfIds) {
const value = data[id];
if (value !== undefined) {
// ok
}
}
});

How to get checkbox value from localStorage

There is a page with a lot of different checkbox questions which then get submitted and populate the next page, this page however gets refreshed and the already annoyed potential client needs to go back and fill out the form again.
Now I have localstorage set up so he doesn't need to reselect all the checkbox again, he just needs to resubmit the form and his back in action.
How does one keep the values populated on the problem page so this fella doesn't have to go back to resubmit?
//SIZE SAVE
function save() {
localStorage.setItem('100', checkbox.checked);
var checkbox = document.getElementById('100');
localStorage.setItem('200', checkbox.checked);
var checkbox = document.getElementById('200');
//SIZE LOAD
function load() {
var checked = JSON.parse(localStorage.getItem('100'));
document.getElementById("100").checked = checked;
var checked = JSON.parse(localStorage.getItem('200'));
document.getElementById("200").checked = checked;
//THIS PAGE NEEDS THE CHECKMARK
echo get_site_url().
"/the/checkmark/selected/was/".$_POST['check_group'].
"/.png";
}
I think is much simple for now and especially for the feature if you write some code to make the management for all checkboxes form your form.
First of all it will be best if you group all your checkboxes into a single place.
Into a function like this you can declare all your checkbox selectors you want to save into the localStoarge (now you don't need to make variables for each selector into multiple places into your code)
function getCheckboxItems() {
return ['100', '200']
.map(function(selector) {
return {
selector: selector,
element: document.getElementById(selector)
}`enter code here`
});
}
Then to make things much simpler you can store all the values from the checkbox into a single object instead of save the result in multiple keys, in this way is much simpler to make management (let's say you want to erase all values or to update only a part)
The following function will take as argument all checkbox items from the function above, the point is the function above will return an array with the checkbox id and the checkbox element, than you just reduce all that array into this function into an single object containing all the ids and values, after this you just store the object into the localStorage
function serializeCheckboxes(elements) {
var container = elements.reduce(function (accumulator, item) {
accumulator[item.selector] = item.element.checked;
return accumulator;
}, {})
localStorage.setItem('container', JSON.stringify(container));
}
function save() {
var elements = getCheckboxItems();
serializeCheckboxes(elements);
}
After this you need another function who will read all the values from the localStorge and place them into your checkbox "checked" state
function readCheckboxes() {
var storage = localStorage.getItem('container'), //Your key
container = (storage) ? JSON.parse(storage) : {};
Object.keys(container).forEach(function(key) {
var element = document.getElementById(key);
if(element) {
element.checked = container[key];
}
});
}
This is just a simple service who can manage your problem but I think, for any additional changes you can customize this solution much simpler instead of keeping all into multiple variables, also if you add more checkbox elements into your application with this solution you just add the corresponding id into the array from the first function.
A live example here:
https://jsbin.com/xejibihiso/edit?html,js,output
localStorage has two main functions, getItem and setItem. For setItem you pass in a key and a value. If you write to that key again, it will rewrite that value. So in your case, if a box is checked you would do
localStorage.setItem("checkbox_value", true)
and when it is unchecked you would pass in false instead. To get the value you can look at using jQuery like so:
$(checkbox).is(':checked')
and use a simple if-else clause to pass in true or false. then when you reload your page, on $(document).ready() you can get the values using
localStorage.getItem(key)
and use JavaScript to set the check boxes values.
localStorage only allows you to store strings. What you can do is use a loop to create a string that has all the check boxes values separated by some delimiter. So, for example, if there are four check boxes with values true false false true your string would be "true\nfalse\nfalse\ntrue" where \n is the delimiter. then you can store that string in localStorage and when you retrieve it you can put all the values into an array like so:
array = localStorage.getItem(key).split('\n').
Then you can populate your check boxes with that newly retrieved array. Ask if anything needs clarification.

Change the div's in another html page

still learning some javascript here, got done other things but now the final and most important part of it.
I have two html pages - one of which uses javascript to dynamically add text-fields (and to remove them of course) (genmain.html) and the other one where the text field input should go(table.html).
So i have already created a function to retrieve the array of values.
function getElementArray(divName){
var names = document.getElementsByName("namefield");
}
The variable names is an array and it has all the values from fields.
The problem is I would like to set these values from array to the values of another div on the page. After some searching i understood that it could be done with 'id'-s but i'm not that sure and don't completely understand how.
Let's say i have a lot of div's on another page (table.html) but some of them have id="MAIN". I would like to change the value inside of the div
For example
<div id="MAIN">THIS PART I WANT TO CHANGE</div>
Javascript is not part of my school system and i've done CodeAcademy tutorials and that's the most i've got about this, I hope you guys can help with my issue.
The variable names is an array and it has all the values from fields.
function getElementArray(divName){
var names = document.getElementsByName("namefield");
}
Nope, you've only got reference to the elements here. You've not got the value yet.
You can get the values by iterating through the names Nodelist array and use names[i].value
The problem is I would like to set these values from array to the
values of another div on the page
If it's going to be in same page, then use innerHTML or textContent property of the DOM to assign the value.
document.getElementById("MAIN").textContent= names[1].value;
Just for demo purpose am using names[1] here so it will load the second input value.
Let's say i have a lot of div's on another page (table.html) but some
of them have id="MAIN". I would like to change the value inside of the
div
Once you move to another page, the javascript state will be lost. So you wont have access to names inside that page.
Either you must store the values into localStorage and retrieve in next page.
Else add the values to query string of your URL and retrive it there.
Edit: Update based on comments
Let us assume you have var names = document.getElementsByName("namefield"); so to store the values inside localStorage.
var myValues = [],
names = document.getElementsByName("namefield");
for(var i = 0; i < names.length; i++) {
myValues.push(names[i].value);
}
localStorage.myValues = JSON.stringify(myValues);
Now if your next page, Iinside window.onload event:
window.onload = function() {
var myValues = localStorage.getItem("myValues") ? JSON.parse(localStorage.getItem("myValues")) : [],
divElements = document.querySelectorAll("#MAIN");
for(var i =0; i < myValues.length; i++) {
divElements[i].textContent = myValues[i];
}
}
If you want to set or change the contents of an element, you can use the innerHTML property.
So in your case, document.getElementById("MAIN").innerHTML = "Whatever you want";
For the record, names in your example technically isn't an array, but a NodeList. See https://developer.mozilla.org/en/docs/Web/API/NodeList#Why_is_NodeList_not_an_Array.3F.

Why is my array losing its contents when I refresh the page?

I have created an:
var checkboxFarm = new Array();
then I want to record a checkbox status in that array, as there are 11 checkboxes.
Button.addEventListener("click", function() {
rp_farmAtivada(index);
}, false);
when clicked change the variable in the array:
function rp_farmAtivada(index) {
checkboxFarm[index] = !checkboxFarm[index];
};
but every time I refresh the page it loses all the checkboxes status and I'm aware that all that array gets the "undefined" value.
the checkboxFarm array is defined in the beginning of the script, so it should have a global scope.
Am I missing something?
You will need to save the status of the checkboxes to be able to refresh and keep their state, as HTTP is stateless.
You could add some AJAX on click to save the results to a database, or to a cookie.
Then on DOM ready, you could retrieve these previous results and change the checkbox values accordingly (or alternatively use a server side language to echo the default states in the markup).
Update
Your comment on LukeN's answer...
can I define the default value for all
the array as true without setting it
for each one?
Yes, you can. Look at this code...
// I'm using an empty array literal here, more succinct and widespead than the old `new Array()`
var checkboxFarm = [];
// You will need to define here how many array members you want to have the `true` value
for (var i = 0; i <= 10; i++) {
checkboxFarm[i] = true;
}
See it working online at JSbin.
That's just how it works. If you want to save state, use cookies. Or generate the values inside a server sided script and echo them to the Javascript.

Categories