Array with localStorage doesn't save or gets overwritten? - javascript

In order to summarize the problem I'll explain what the task is first.
So for the eastern event, we are going to add 3 bunny images across a website (different pages, same domain, same website). Once you've found and clicked on all 3 images it should open a new window with a specific URL.
Right now I managed to write the code which saves the clicks of the 3 pictures in an array and then opens the new window with an URL. But sadly it doesn't work once I change the page. The Array either didn't save in the browser storage or gets overwritten once I open a new page.
I'm not exactly sure what the issue is right now. I hope any of you could help me out.
I've tried to work with localStorage and sessionStorage but I don't think I used them properly. I'll provide you with my current code below.
Javascript
$(function(){
var imageStore = [];
$('.osterhasen').click(function(e){
localStorage.id = $(this).attr('id');
// returns index of the element in the array, if the element was not found returns false
var imageExists = $.inArray(localStorage.id, imageStore);
if (imageExists >= 0){
// If element exists, do nothing
e.preventDefault;
} else {
// If element doesn't exist, add element
imageStore.push(localStorage.id);
}
localStorage.setItem('imageStore', JSON.stringify(imageStore));
localStorageimageStorage = JSON.parse(localStorage.getItem('imageStore'));
console.log(localStorageimageStorage);
if (localStorageimageStorage.length == 3) {
window.open('https://www.google.ch');
}
});
});
HTML
<body>
<div class="container">
<div id="1" class="osterhasen"><img src="img/choco.png"></img></div>
<div id="2" class="osterhasen"><img src="img/geschichte.png"></img></div>
<div id="3" class="osterhasen"><img src="img/mitarbeiter.jpg"></img></div>
</div>
</body>
In the end the clicks on the images should be saved in the browser storage across the whole website and once you've found all 3 images it should open a new window with a specfic URL.
Thank you very much for your time.
Best regards

You can't assign properties to localStorage like this (it doesn't exist, and you should be using it's setItem method anyway):
localstorage.id = $(this).attr('id');
var imageExists = $.inArray(localstorage.id, imageStore);
So assign id to a variable instead:
const id = $(this).attr('id');
const imageExists = $.inArray(id, imageStore);
Working version

Yes, you're overriding the key every time. To store an array as you want, you can try the following:
$(function(){
var imageStore = [];
$('.osterhasen').click(function(e){
if(localStorage.getItem('imageStore') === null){ // check if such key exists
localStorage.setItem('imageStore', JSON.stringify([$(this).attr('id')])); // if it doesn't create an array with first item imageStore and set it to key imagestore
} else {
var currentStorage = JSON.parse((localStorage.getItem('imageStore')));
if(!currentStorage.includes($(this).attr('id')){ // if id doesn't exist add it.
currentStorage.push($(this).attr('id')); // push to new image inside of it
localStorage.setItem('imageStore', JSON.stringify(currentStorage)); // set the key to the new value
}
}
localStorageimageStorage = JSON.parse(localStorage.getItem('imageStore')); // you should have all the 3 pictures here in an array
console.log(localStorageimageStorage);
if (localStorageimageStorage.length == 3) {
window.open('https://www.google.ch');
}
});
});

Related

Hiding an element by ID when in local storage once clicked not working

I am using this script to refresh the page after a button has been clicked and to hide that button once the ID (the shortcode) has been stored locally and to show a second element underneath:
function myVote(shortcode) {
$(document).on('submit', 'form', function() {
// Set product in local storage
localStorage.setItem(shortcode, "true");
// Refresh page after 3000 milliseconds
setTimeout(function() { location.reload(true); }, 3000);
});
};
</script>
<script>
for(let i=0; i<localStorage.length; i++) {
document.getElementById(localStorage.key(i)).style.display = "none";
}
</script>
The button has the following value: onClick="myVote('shortcode');"
The "shortcode" values are dynamic, each element has it's own.
I have built an upvoting system and the above means that once a vote has been placed they won't be able to vote for it again (unless they use another device or clear storage), the vote button is hidden and the "voted" button is now displayed. But for some reason, it's not working as it should and I'm struggling to figure it out. Check it out at https://www.carryr.com/vote.
At first, I thought I didn't configure the z-index for both of the element but they seem fine to me; the element underneath has a z-index of 11 and the one on top 100.
The SetTimeout may be the reason as after clicking on the said button, tahe page gets reload and localstorage value become null. Hence, the page throws document.getElementById(...) is null exception.
Please remove Timeout and retry the same.
You are storing many things in local storage which are not element ids.
So there will be an error when you try to access style property on an element that does not exist. Hence this code doesn't work.
Suggestion:
1.
const elm = document.getElementById(localstorage.key(i));
if (elm) {
elm.style.display="none"
}
2.It's better if you store the voted ids in a separate object and store it in storage. and read that object on load and style based on that.
// setting to storage
let voted = localStorage.getItem('voted');
if (!voted) {
voted = {};
} else {
voted = JSON.parse(voted);
}
voted.shortCode = true;
localStorage.setItem('voted',JSON.stringify(voted));
// reading from storage
voted = localStorage.getItem('voted');
if (!voted) {
voted = {}
} else {
voted = JSON.parse(voted);
}
Object.keys(voted).forEach(key => document.getElementById(key).style.display = 'none';
The above methods only store data in localstorage. so if user clears cache, opens a incognito window, opens in another system he won't be able to see the votes. better persist the state in a DB if possible

Iterate through multiple web pages in JS with sleep in between

I was checking some simple solutions for showing multiple web pages for some dashboard and currently fighting with simple HTML page with javascript inside to achieve what I want to see there.
var urls = new Array();
urls[0] = "https://stackoverflow.com/"
urls[1] = "https://www.google.com"
var arrayLength = urls.length;
for (var i = 0; i < arrayLength; i++) {
window.location.assign(urls[i]);
sleep(3000);
}
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds) {
break;
}
}
}
Currently this page opens only first page (after some time) and looks like it doesn't do iteration trough other pages. Maybe you could help me to make it work? I want to rotate those pages forever on screen (will add some infinite while loop after making this part working).
Currently this page opens only first page (after some time) and looks
like it doesn't do iteration trough other pages.
Once you change your window.location, and go to the first url from the array, you are losing all of your JS code (as it is not present in just opened url any more).
You can do this by installing a chrome plugin (which will not lose your JS after window.location change).
The plugin will run the added JS at DOMContentLoaded (no need to attach any event listener).
I needed also to do this, check things on the page, store some information and move on to the next page. I know, this can be done with Python and other stuff but by doing this it can be done on the FE side also.
I used the localStorage to store my information.
I pasted this into the browser console to prepare all the stuff and clean the localStorage:
// clear the localStorage
localStorage.clear();
// set an array that will keep all our pages to iterate into the localStorage
localStorage.setItem(
"pages",
JSON.stringify([
"https://my-page-1.html",
"https://my-page-2.html",
"https://my-page-3.html",
"https://my-page-4.html",
])
);
// set an array that will keep our findings
localStorage.setItem("resultArray", JSON.stringify([]));
// move to the first page of the iteration
window.location.href = "https://my-page-1.html";
After doing this, I opened the plugin interface and added the following code:
(function check() {
// array saved into the localStorage that contains all the pages to iterate
const pagesArray = JSON.parse(localStorage.getItem("pages"));
// array to store your stuff
const resultArray = JSON.parse(localStorage.getItem("resultArray"));
// whatever you want to check on that page
const myFancyCondition = true;
if (myFancyCondition) {
// push any data to the array so that you can check it later
resultArray.push({
page: pagesArray[0],
message: "I found what I was looking for!",
});
}
//remove the current page from the array
pagesArray.shift();
//reset the array value after the first page was already checked
localStorage.setItem("pages", JSON.stringify(pagesArray));
//store the array data
localStorage.setItem("resultArray", JSON.stringify(resultArray));
// quit if the iteration is over and there are no more pages to check
if(!pagesArray.length) return;
//go to the next page
window.location.href = pagesArray[0];
})();
Then, to check the results you just need to read the data from the localStorage like:
JSON.parse(localStorage.getItem('resultArray'))
I hope this helps :)!

JavaScript Tab Amount

is there a way to check if the user has more than one tab open (not globally, only on my website) or how many tabs the user has open?
In the best case i need the amount but a boolean value would be enough.
I need a solution in vanilla JavaScript (ES6) without jQuery or something else.
Thank you in advance.
You could create an ID for every opened tab and save it in an array in the localStorage (document.cookie would also work, but requires a bit more effort with getting and setting):
var tabId = Math.random();
var tabs = JSON.parse(localStorage.getItem('tabs')) || [];
tabs.push(tabId);
localStorage.setItem('tabs', JSON.stringify(tabs));
Now, to check how many tabs we have open on the current domain, we check the length of the tabs array in the localStorage:
function getTabCount()
{
return JSON.parse(localStorage.getItem('tabs')).length;
}
Now, you can use getTabCount() to get the amount of tabs that are currently open.
Finally, we need to make sure our tabId is removed from the array when we close it:
window.addEventListener('beforeunload', function(e)
{
tabs = JSON.parse(localStorage.getItem('tabs'));
var index = tabs.indexOf(tabId);
if (index !== -1)
tabs.splice(index, 1);
localStorage.setItem('tabs', JSON.stringify(tabs));
});
Do keep in mind that you need to keep using getTabCount() to check if any tabs have been opened or closed since you last used it.

Can't overwrite object saved with rhaboo in javascript

I'm trying to save an object with rhaboo in javascript. The first time after initialising it is working but when I'm trying to save it again it gives me the
rhaboo.min.js:1 Uncaught TypeError: Cannot read property 'refs' of undefined error. I pinned down the error to the line where I save the keyArray with notes.write('presentationNotes', keyArray);
How I get the error in detail:
I open my webapplication with a clean localStorage (nothing is saved) and rhaboo gets initialised. After that I navigate to a document and open the notes-div with the notes-button. I write something in the notes-area and hit the notes-submit button to save the notes with rhaboo to localStorage. I do the same for a second document. For now everything works. Both notes get saved correctly so that I have an object like this:
keyArray = {activeDoc1: ['note1', 'note2'], activeDoc2: ['note1', 'note2']}
saved in rhaboo in notes.presentationNotes. Then I reload my webapplication and rhaboo is already initialised. I navigate to the documents as before and check if I can load the saved notes. This works as expected but when I try to hit the notes-submit button again it gives me the aforementioned error. What am I doing wrong?
var notes = Rhaboo.persistent('Presentation Notes');
$(document).ready(function(event) {
var keyArray, activeDoc;
if (!notes.initialised) {
notes.write('initialised', true);
notes.write('presentationNotes', {});
console.log('Rhaboo Initialised');
keyArray = {};
} else {
console.log('Rhaboo already initialised');
keyArray = notes.presentationNotes;
console.log('notes.presentationNotes onLoad = ');
console.log(notes.presentationNotes);
}
//Notes open
$(document).on('click', '#notes-button', function() {
$('.notes-div').show();
activeDoc = $('.node.active').attr('id');
if (notes.presentationNotes[activeDoc] != null) {
//Iterate notes
$.each(notes.presentationNotes[activeDoc], function(index, value) {
$('#notes-area').append(value + '\n');
});
}
});
//Notes save
$(document).on('click', '#notes-submit', function() {
$('.notes-div').hide();
var str = $('#notes-area').val();
var array = str.split("\n");
keyArray[activeDoc] = array;
//Save notes
notes.write('presentationNotes', keyArray);
//Clear textarea
$('#notes-area').val('');
});
}
Without the HTML I haven't been able to try this, so I'm just guessing here, but I suspect your problem will go away if you stop using keyArray and activeDoc. The whole point of rhaboo is that it is not a place to store your data. It IS your data.
I see no transient data in your program, i.e., no data which you actively want to delete when the user goes away and comes back. All the data is supposed to be persistent, therefore it should all be under the Rhaboo.persistent.
That's the philosophy, but to be more specific, I think your problem is here:
keyArray[activeDoc] = array;
When I wonder what keyArray is is find:
keyArray = notes.presentationNotes;
so the earlier line actually says:
notes.presentationNotes[activeDoc] = array;
but it says on the tin that that should read:
notes.presentationNotes.write(activeDoc, array);
The upshot is that that the hooks that make rhaboo work have not been inserted into array, as notes.presentationNotes.write would have done.
When you next said:
notes.write('presentationNotes', keyArray);
it meant:
notes.write('presentationNotes', notes.presentationNotes).
which is clearly not what you meant. Rhaboo doesn't suspect that array has no hooks yet because it can see that notes.presentationNotes does have hooks.
I also forget to use write sometimes, and it really bugs me that JS offers no way to hook into the creation of a NEW key within an object X, no matter what you've done to X. Without that limitation, there'd be no need for write and it could be foolproof.

strategies for loading data into a textarea

I have a system where the user can select templates from a dropdown menu of up to 300 options.
When the user selects one, a readonly textarea is filled with a corresponding string of length <= 1000 characters.
When the page loads, should I:
store them all in a JavaScript variable, and reference the variable on the select change?
load the content via ajax when the select changes?
You seem to already know the answer: you can preload the templates into your HTML, but then the page becomes large and slow to download, with most of the templates never being used. If you use AJAX, only the minimum necessary information gets downloaded.
You could set a function on click:
var infoArray = new Array();
$('item').click(function() {
var itemName = $(this).attr('id');
if(infoArray[itemName] !== undefined)
{
$('loader').empty().load('url', function() {
infoArray.push({itemName:$('loader').text()});
});
} else {
$('loader').empty().append(infoArray[itemName]);
}
});

Categories