Toggling localStorage item - javascript

I want to create a toggle function for my localStorage as I am trying to install a dark mode on my site and I want it to remember the user's choice.
I want it load the current preference on page load, if one has been made, and then toggle the state on click. My code is below - however I am clearly making some error on my attempt to toggle the localStorage state.
// ON PAGE LOAD, IF USER PREFERS DARK, ADD DARK CLASS TO HTML
if (window.localStorage.getItem('preferDark')) {
$('html').toggleClass('dark');
}
// TOGGLE STATE ON CLICK
$('.wrapper').click(function(){
if (window.localStorage.getItem('preferDark', true)) {
window.localStorage.setItem('preferDark', false);
} else {
window.localStorage.setItem('preferDark', true);
}
$('html').toggleClass('dark');
});
I know there are various localStorage toggle questions out there but I can't find one quite the same as mine.

You can't keep boolean in localStorage. That's why you have an error.
Try to keep, for example, 0 for false and 1 for true. But remember that localStorage also can't keep integer - you can pass integer or boolean but it will be converted to string.
Try this:
if (+window.localStorage.getItem("preferDark")) {
$("html").toggleClass("dark");
}
$(".wrapper").click(function () {
if (+window.localStorage.getItem("preferDark")) {
window.localStorage.setItem("preferDark", 0);
} else {
window.localStorage.setItem("preferDark", 1);
}
$("html").toggleClass("dark");
});
Pay attention: I use + sign before getting value from localStorage to convert it to Number

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

How would one set the initial value of an editable div?

So, I've got a notepad extension for Google Chrome that syncs and displays stored notes from a user. Currently my problem is as follows.
When the extension is run for the first time after download, the word 'undefined' is displayed in the editable div (id = edit_notepad). I want it to just be blank instead of displaying anything. Obviously, I know its undefined because the user hasn't been able to add any text yet.
Picture of what's displayed on initial run:
From my content script, here are my chrome.storage get and set functions (which do work):
document.body.onload = function() {
chrome.storage.sync.get("edit_notepad", function(items) {
if (!chrome.runtime.error) {
console.log(items);
document.getElementById("edit_notepad").innerHTML = items.edit_notepad;
}
});
}
document.getElementById("edit_notepad").onkeyup = function() {
var d = document.getElementById("edit_notepad").innerHTML;
chrome.storage.sync.set({ "edit_notepad" : d }, function() {
if (chrome.runtime.error) {
console.log("Runtime error.");
}
});
}
I presume I'm going to need some sort of if statement, but after hours of playing around, I'm lost as to what exactly it'd contain. The issue I've kept running into is that whatever I set the initial value of edit_notepad to, it always reverts back to "undefined" even when a user has written some notes! e.g. "This is a notes test" would revert back to "undefined" when the notepad is closed and reopened.
Well, an easy way to do this would be to specify a default value in your chrome.storage.sync.get(). Doing so would apply the default value when the key does not exist in the storage. However, given that you are replacing any contents which might already exist, the better solution would be not to set the contents when you have no value, or an invalid value, stored. The only valid value will be a string. This will prevent you from overwriting any default value supplied by the webpage when you have no value stored. Thus, an if statement something like the following should work (alternately, you could test for !== 'undefined':
document.body.onload = function() {
chrome.storage.sync.get("edit_notepad", function(items) {
if (!chrome.runtime.error) {
console.log(items);
if(typeof items.edit_notepad === 'string') {
document.getElementById("edit_notepad").innerHTML = items.edit_notepad;
}
}
});
}
Note: Storing the contents of the editable <div> on every key will result in many users running into both the MAX_WRITE_OPERATIONS_PER_MINUTE and MAX_WRITE_OPERATIONS_PER_HOUR quotas. You will need to have some other criteria for writing to storage.sync. Perhaps you could temporarily store the value in storage.local and only to storage.sync every couple of minutes.

Why isn't my cookie updating?

I am making a dark mode for a site using a button toggle. To keep the dark mode saved when changing pages, I am using cookies. When pressing the toggle again, the dark mode is disabled but is not saving and I am not sure why.
Ps. I am new at javascript so this may be a dumb mistake.
if ($.cookie('darkModeOn')){
$('html').toggleClass('dark-mode');
$('#dark-toggle').click(function(){
$.cookie('darkModeOn', false, { expires: 7 });
$('html').toggleClass('dark-mode');
});
}
else
{
$('#dark-toggle').click(function(){
$.cookie('darkModeOn', true, { expires: 7 });
$('html').toggleClass('dark-mode');
});
}
When you press the toggle button you also want to toggle the True/False value of the cookie. Now you always either set it to True or to False depending on the first state.
Use ! $.cookie('darkModeOn') as value to store into the cookie to automatically toggle the boolean value.
EDIT
It was indeed not working, and I found out that it was not working because of the boolean values.
The boolean values are stored as string ("false" and "true") since if ( "false") gives boolean true, the if is always executed. When you use integers instead of booleans this would work, but you can also change the if to:
if ($.cookie('darkModeOn')=="true") //...
If you use integers it also works:
https://jsfiddle.net/6m2ydrh2/12/
$('#dark-toggle').click(function(){
//this gets executed each click so we need to toggle the boolean value.
if ($.cookie('darkModeOn')==0){
$.cookie('darkModeOn', 1, { expires: 7 });
}else{
$.cookie('darkModeOn', 0, { expires: 7 });
}
console.log( "cookie:"+$.cookie('darkModeOn')) ;
$('#test').toggleClass('dark-mode');
});
if ($.cookie('darkModeOn')){
//this is only executed on load
$('#test').toggleClass('dark-mode');
}
See also this post: jquery cookie set value to boolean true.
The boolean values are stored as string and therefor causing problems.

Cannot switch between classes with jQuery

I've got a problem with switching between element classes - probably sth stupid, but I couldn't find the answer.
In my system I display a list of items. Now I want to be able to promote items, so that they appear at the top of the list. I created some backend infrastructure which works ok and added things to my frontend: a star (a span with star bg) next to every item's title and a jQuery script which is supposed to:
listen to 'click' event - when I click on a star
get some data- attributes from the span
post them to my controller
the controller checks if I'm allowed to promote items and replies 'true' or 'false'
if 'true' then I switch between 'gold-star' and 'silver-star' classes of the item
For some reason the classes don't switch - only when I refresh the page I can see the effect. I tried debugging with Firebug - it gets to the toggle line, but then nothing happens.
Here's the code:
<span class="silver-star promote">
$(".promote").bind("click", function() {
var $this = $(this);
var itemId = $this.attr("data-id"),
isPromoted = true;
if ($this.hasClass("gold-star")) {
isPromoted = false;
}
$.post('/promoteitems', { itemId: itemId, isPromoted: isPromoted }, function(allowPromotion) {
if (allowPromotion == true) {
$this.toggleClass("silver-star").toggleClass("gold-star");
}
});
});
Thanks in advance!
When you are getting a response back it might not recognise it as a boolean simple test would be to check response as string
From your comment on the question:
...the allowPromotion value is 'True' (with a capital T)...
That tell us it's a string, not a boolean. You don't want to just do if (allowPromotion), because that will toggle the classes even if you get back "False".
Instead:
if (allowPromotion == "True") { // Note the quotes and capital T
// ...toggle the classes
}
Or if you want to allow for possibly getting back something with a lower-case T at some point in the future:
if (/^\s*true\s*$/i.test(allowPromotion)) {
// ...toggle the classes
}
That's over-engineering it a bit (it'll work with "True", "true", " True " [note the spaces], and even an actual boolean true)...

Setting a cookie and then replacing a div with another div

I'm having an issue where i'm trying to use the jQuery plugin by Carhartl : https://github.com/carhartl/jquery-cookie
I thought this would a fairly easy thing to do, but i'm fairly new to jQuery and cookies especially and i'm really struggling now.
What I want to do is:
Set a cookie that registers the visit
Switch one div for another (in this case, change the sticky bar for a different sticky bar with different content)
Keep the new content in place for the returning visitor for x amount of time (if I can specify the exact time, the better)
Current code looks like this:
$(function() {
if(!$.cookie('repeatVisitor')) {
$.cookie("repeatVisitor", "true", { expires: 3 }); //expires in 3 days
setTimeout('showDivTwo();', 3000);
}
})
function showDivTwo() {
$('#sticky-bar').fadeOut();
$('#sticky-private').fadeIn();
}
I would really appreciate some help, i'm in desperate need!
Your cookie plugin usage looks correct; so does all of your code. I think it may be a logic issue.
Your code will never show the private div after the first time.
You can make this adjustment, but note that if you do, you will ALWAYS see the private div.
What seems to be missing is a specific action that the user needs to take to trigger the cookie, not just the cookie's lack of existence:
$(function() {
if(!$.cookie('repeatVisitor')) {
// if the user is not a repeat visitor, set the cookie
$.cookie("repeatVisitor", "true", { expires: 3 }); //expires in 3 days
}
if ($.cookie('repeatVisitor')) {
// if the cookie exists, show the custom div
setTimeout('showDivTwo();', 3000);
}
})
function showDivTwo() {
$('#sticky-bar').fadeOut();
$('#sticky-private').fadeIn();
}

Categories