How I add an item to localStorage JS? - javascript

I have a function that sets the color theme of my site when clicked, but when I reload the page or go to a new page, it reverts back to the default theme. There's a line of my code that is supposed to get the previous theme from localStorage and apply it to the new one, but I think why it isn't working is that there isn't actually any code that saves the theme to Storage. Either that, or localStorage resets when the page is reloaded/changed. Either way, I'm not sure how to fix it.
This is my code:
<a class="switch-light-purple color-palette" id="color-palette" onclick="setTheme('theme-light-purple')">
<script>
// function to set a given theme/color-scheme
function setTheme(themeName) {
localStorage.setItem('theme', themeName);
document.documentElement.className = themeName;
}
// Immediately invoked function to set the theme on initial load
(function () {
if (localStorage.getItem('theme') === 'theme-light-purple') {
setTheme('theme-light-purple');
}
})();
</script>
</a>
<a class="switch-dark-blue color-palette" id="color-palette" onclick="setTheme('theme-dark-blue')">
<script>
// function to set a given theme/color-scheme
function setTheme(themeName) {
localStorage.setItem('theme', themeName);
document.documentElement.className = themeName;
}
// Immediately invoked function to set the theme on initial load
(function () {
if (localStorage.getItem('theme') === 'theme-dark-blue') {
setTheme('theme-dark-blue');
}
})();
</script>
</a>

Separation of concerns:
Keep your html, css, and js in their respective files ALWAYS, there's no substitution for this.
So your index.html should look something like this (assuming index.html, style.css, and main.js are all in the same folder).
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="parent-container">
<a data-theme="theme-dark-blue" class="switch-dark-blue color-palette" id="color-palette">Dark Blue </a>
<a data-theme="theme-light-purple" class="switch-light-purple color-palette" id="color-palette2">Light Purple</a>
</div>
<script src="main.js"></script>
</body>
</html>
Your CSS will be in a file called style.css,
And your JS,
// This waits for the DOM to complete loading
document.addEventListener('DOMContentLoaded', function() {
// all your code goes inside this.
});
Also, as #Sebastian Simon pointed out in the comments,
Repeating the same id is invalid in HTML. Inline event handlers like onclick are not recommended. They are an obsolete, hard-to-maintain and unintuitive way of registering events. Always use addEventListener instead.
Unique IDs:
You could change the id of one of your anchor tags to color-palette2 for instance, but since you have a lot of different themes you could pick names that are more self-explanatory. But, as long as your ids are unique (1 unique id per page), it's fine.
Event Listeners:
Use .addEventListener to add events to your DOM nodes. I've done this in the code snippet I've shared. It's very easy once you get used to it.
I've also used data attributes to pass your theme in a more "dynamic" way to your logic. StackOverflow snippets don't support localStorage hence I've commented that line out.
function setTheme() {
let theme;
let savedTheme = localStorage.getItem('theme')
// check if localstorage already has a theme defined
// if it has, then set theme variable to it
// otherwise, get the theme from the data-theme attribute
// of the current anchor tag clicked represented by this.
theme = savedTheme || this.dataset.theme
let div = document.querySelector('div.parent-container')
// I'm adding this to a div
// you can add it to the body tag.
div.classList.add(theme)
// this code can be better but the idea is
// to remove all other themes and keep only the intended one.
if (theme === 'theme-dark-blue') {
div.classList.remove('theme-light-purple')
} else {
div.classList.remove('theme-dark-blue')
}
console.log(`Set theme to ${theme}`)
}
let palettes = document.querySelectorAll('.color-palette')
palettes.forEach(function(p) {
p.addEventListener('click', setTheme)
})
a {
cursor: pointer;
text-decoration: underline;
color: blue;
}
.switch-light-purple {
color: purple;
margin: 0 15px;
}
<div class="parent-container">
<a data-theme="theme-dark-blue" class="switch-dark-blue color-palette" id="color-palette">Dark Blue </a>
<a data-theme="theme-light-purple" class="switch-light-purple color-palette" id="color-palette2">Light Purple</a>
</div>
PS: the code snippet won't work since StackOverflow does not support localStorage.

Related

How do I make an element disappear after a set amount of time?

i am trying to make the element with ID thanks1 disappear after a set amount of time. So far I have tried many things like setTimeout but none have worked
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test</title>
<script src="scripts.js"> </script>
</head>
<body>
<h1> 1 </h1>
<p> QUESTION </p>
<button onclick="rightAnswer()" id="a"> PLACE HOLDER </button>
<button onclick="wrongAnswer()"> PLACE HOLDER </button>
<p id="output"> </p>
<p id="thanks1"> Well Done </p>
</body>
</html>
This is a quiz and it gets you to the next page when you get a question correct, I tried putting a timeout in the rightAnswer function so as soon as you load 1.html the Well Done disappears after some time.
const wrong = "Wrong, try again!";
function wrongAnswer() {
document.getElementById('output').innerHTML = wrong
}
function rightAnswer() {
if (document.getElementById('a')) {
location.href = "1.html";
setTimeout(document.getElementById('thanks1').style.display = "none", 3000)
}
if (document.getElementById('b')) {
location.href = "2.html"
}
if (document.getElementById('c')) {
location.href = "3.html"
}
}
function goBack() {
if (document.getElementById('b')) {
location.href = "index.html"
}
if (document.getElementById('c')) {
location.href = "1.html"
}
if (document.getElementById('d')) {
location.href = "2.html"
}
}
I wanted to make the element with the ID "thanks1" disappear once its corresponding page has loaded and after a set amount of time. I tried using setTimeout but nothing that I wanted seemed to happen.
Your syntax is incorrect.
MDN Docs: setTimeout()
From the docs:
The global setTimeout() method sets a timer which executes a function or specified piece of code once the timer expires.
setTimeout(functionRef, delay)
// Parameters
// functionRef - A **function** to be executed after the timer expires.
// delay - The time, in milliseconds that the timer should wait before
// the specified function or code is executed.
For simplicity, I used the same 'thanks1' container for outputting the values
function wrongAnswer() {
// "wrong" should be a string unless you're calling a variable
document.getElementById('thanks1').innerHTML = "wrong";
}
function rightAnswer() {
if (document.getElementById('a')) {
location.href = "1.html";
setTimeout(wrongAnswer, 3000)
}
...
}
Example:
https://codepen.io/carbonspace/pen/QWxwvRo

Light and Dark mode based on system setting and button click in html

I have the following code on my website where I am trying to set light or dark mode based on the settings of the users system/browser as well as the ability to change the setting based on a button press.
What I want to happen is:
It is daytime orthe users browser is set to light. The website loads the light.css and the button shows the moon icon to switch to the light theme.
It is night time or the user has their theme set to dark mode. The website loads the dark.css theme and the icon in the button switches to the sun.
Perhaps I am missing something here to get it all functioning correctly? Mainly the buttons do not switch.
function lightDark() {
var el = document.querySelectorAll(".light, .dark")
if (el.href.match("light.css")) {
el.href = "dark.css";
} else {
el.href = "light.css";
}
}
<
script type = "text/javascript" >
$('#lightDarkToggle').click(function() {
if (window.matchMedia('prefers-color-scheme: dark').matches) {
$(this).find('i').toggleClass('fa-sun'),
el.href = "dark.css";
} else {
$(this).find('i').toggleClass('fa-moon'),
el.href = "light.css";
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link class="light" rel="stylesheet" href="light.css" media="(prefers-color-scheme: no-preference), (prefers-color-scheme: light)" />
<link class="dark" rel="stylesheet" href="dark.css" media="(prefers-color-scheme: dark)" />
<button id="lightDarkToggle" onclick="lightDark()"><i class="fas fa-moon"></i></button>
I think this line var el = document.querySelectorAll("#light, #dark")
should be var el = document.querySelectorAll(".light, .dark"), because your link tags have a class, not an id.
Another thing, in your second script tag, you try to update el.href, but in this function, el is never defined. It has been defined in another function (lightDark()), so it is not accessible anymore at the end of it.

Theme switcher in JS

I want to save the user preferred theme (light/dark) in cookies. Can someone help me with it? I'm really bad at JS. I submit my current script.
Stylesheets:
<link rel="stylesheet" href="custom.css" id="pagestyle2" type="text/css" charset="utf-8"/>
<link href="file-upload.css" id="pagestyle4" rel="stylesheet">
<link href="bootstrap.css" id="pagestyle3" rel="stylesheet">
<link href="hg.css" id="pagestyle" rel="stylesheet">
Switcher:
<li class="nav-item" id="pagestylechoose">
</li>
Switcher JS:
function swapStyleSheet(sheet) {
document.getElementById('pagestyle').setAttribute('href', sheet);
}
function swapStyleSheet2(sheet) {
document.getElementById('pagestyle2').setAttribute('href', sheet);
}
function swapStyleSheet3(sheet) {
document.getElementById('pagestyle3').setAttribute('href', sheet);
}
function swapStyleSheet4(sheet) {
document.getElementById('pagestyle4').setAttribute('href', sheet);
}
Although it requires a little modification of your CSS, there is another solution instead of having to load different style sheets.
Load a default version, for this example, lets say its the light version. Then when the visitor wants the dark version, a class is added to the BODY called dark.
Then within your DARK version of the CSS, just add body.dark to the beginning of all CSS selectors.
Fiddle: https://jsfiddle.net/Lw7461ey/ (SO Snippets blocks localstorage so I used jsfiddle)
This way you can load all of the CSS files at once, you can even compress them if you wanted to.
var ChangeTheme = document.querySelector(".ChangeTheme");
if(localStorage.getItem("theme") === undefined){
localStorage.setItem("theme","light");
}
function setTheme(){
document.body.classList.remove("dark");
document.body.classList.remove("light");
document.body.classList.add(localStorage.getItem("theme"));
}
ChangeTheme.addEventListener("click",function(){
localStorage.setItem("theme",(localStorage.getItem("theme") === "dark") ? "light" : "dark");
setTheme();
});
setTheme();
For your CSS for example
Lets say in light you have:
a{color:#000000;}
For dark, just change it to:
body.dark a{color:#ffffff;}
I would suggest you have a single function that get called when the button is clicked, specially that the stylesheet names are hard coded anyways
<li class="nav-item" id="pagestylechoose">
</li>
..
function changeStyleToDark() {
document.cookie += "style=dark";
swapStyleSheet('dark.css');
swapStyleSheet2('custom-dark.css');
swapStyleSheet3('bootstrap-dark.css');
swapStyleSheet4('file-upload-dark.css');
}
function swapStyleSheet(sheet) {
document.getElementById('pagestyle').setAttribute('href', sheet);
}
function swapStyleSheet2(sheet) {
document.getElementById('pagestyle2').setAttribute('href', sheet);
}
function swapStyleSheet3(sheet) {
document.getElementById('pagestyle3').setAttribute('href', sheet);
}
function swapStyleSheet4(sheet) {
document.getElementById('pagestyle4').setAttribute('href', sheet);
}
Now to get the read the user style later you can use
function getUserStyle() {
return getCookieByName("style");
}
function getCookieByName(cookieName) {
var cookieString = RegExp(cookieName + "=[^;]+").exec(document.cookie);
return decodeURIComponent(!!cookiestring ? cookiestring.toString().replace(/^[^=]+./,"") : "");
}
Now, on the beginning of the script, and whenever the page loads, check for the cookie and call changeStyleToDark if it's set to dark.
window.onload = (event) => {
if (getUserStyle() === "dark") changeStyleToDark();
};

How can we style a word in css with special character?

I made an application in angular 2(5.0). The application is all about getting the trending tweets.
I faced one problem while styling. I am getting one paragraph though API
Eg:#_NAN_DINI #InTheWordsOfK #maidros78 Self immolation is still a form of social protest in India. Remember the guy w…
My need is, i want to give additional style to the words which having characters like # and #
Eg:
#_NAN_DINI
#InTheWordsOfK
#maidros78
#ereaad
So is it possible to add some basic style to these kind of word without heavy JavaScript ??
Can we solve it with CSS ? How ?
Note: I am using SCSS.
This is not something that can be done with only CSS. You will need JavaScript and the example below in raw JS without the need for any framework, but it can be use in any framework.
Try this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Twitter CSS 1</title>
<style>
#input {
font: 14px/1.2em Tahoma;
height: 12em;
width: 500px;
}
.class-at {
color: blue;
}
.class-hash {
color: green;
}
</style>
</head>
<body>
<h3>Enter Text Here</h3>
<textarea id="input">#_NAN_DINI #InTheWordsOfK #maidros78 Self immolation is still a form of social protest in India. Remember the guy w…</textarea>
<hr/>
<div id="output"></div>
<script>
var inEl = document.getElementById('input');
var outEl = document.getElementById('output');
function encodeStr(str) {
return str.replace(/(\#\S+)/g, (key) => `<span class="class-at">${key}</span>`).replace(/(\#\S+)/g, (key) => `<span class="class-hash">${key}</span>`);
}
function inputHandler() {
outEl.innerHTML = encodeStr(inEl.value);
}
inEl.addEventListener('input', inputHandler);
inputHandler();
</script>
</body>
</html>
See: https://jsfiddle.net/intervalia/bu3rxq8q/
The function encodeStr contains two calls to replace. And those add either a <span class="class-at"> or a <span class="class-hash"> around the words you are looking for.
All that is needed
The function encodeStr is all the JS that is really needed to do the conversion. It is up to you to get the string into the function and use the result. You will also need the CSS that colors your fields the color you want. .class-at and .class-hash. Of course you can change those to whatever you want them to be called.
function encodeStr(str) {
return str.replace(/(\#\S+)/g, (key) => `<span class="class-at">${key}</span>`).replace(/(\#\S+)/g, (key) => `<span class="class-hash">${key}</span>`);
}

Strange behavior in Polymer data-binding to an attribute

Using Polymer 1.0 I'm trying to bind to an attribute of a custom element, and just display it.
The custom element is in fact an <iron-input> list, that has an add and a delete button. I'd like to reflect any change in that list to the host. It also has a minItemSize attribute meaning it has at least this many elements. So I added a check to the observer, adding extra elements in case it goes under this number.
But when I bind to the attribute that holds the list, things get out of sync, and I can delete all of the inputs from the ui.
I have two <dyn-inputlist> elements. In one of them I don't bind to the data
attribute, in the other I do.
The first one behaves as expected: adds and removes on the button click.
The other doesn't work, because you can remove all input boxes. Even though the data itself is updated, and filled with extra items, for some reason the UI doesn't reflect this. (Checking the data property of the element does show that it has the correct number of items)
I also expect that if I set data={{myData}} on both dyn-inputlist element, they always display the same thing. But pressing add/remove buttons randomly on either component gets them out of sync.
Am I missing something?
Thanks in advance.
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="bower_components/webcomponentsjs/webcomponents.js"></script>
<link rel="import" href="components/dyn-inputlist.html"/>
</head>
<body>
<template is="dom-bind">
<dyn-inputlist min-item-size="4"></dyn-inputlist>
<div>{{mydata}}</div>
<dyn-inputlist min-item-size="4" data="{{mydata}}"></dyn-inputlist>
</template>
</body>
</html>
dyn-inputlist.html:
<link rel="import" href="../../polymer/polymer.html">
<link rel="import" href="../../iron-input/iron-input.html">
<dom-module id="dyn-inputlist">
<template>
<button on-click="removeItem">x</button>
<button on-click="addItem">+</button>
<template is="dom-repeat" items="{{data}}">
<div>
<span>{{index}}</span>
<input is="iron-input" bind-value="{{item.content}}">
</div>
</template>
</template>
<script>
Polymer({
is: 'dyn-inputlist',
properties: {
minItemSize: {
type: Number,
notify: true,
value: 1
},
data: {
type: Array,
reflectToAttribute: true,
notify: true,
value: function () {
return []
}
}
},
observers: ['_dataChanged(data.*)'],
addItem: function (e) {
this.unshift('data', {content: ""});
this.reflectPropertyToAttribute('data')
},
removeItem: function (e) {
this.shift('data');
this.reflectPropertyToAttribute('data')
},
_dataChanged: function (e) {
if (this.data != null) {
while (this.data.length < this.minItemSize) {
this.push('data', {content: ""})
}
} else {
this.data = [{content: ""}];
}
this.reflectPropertyToAttribute('data');
}
});
</script>
</dom-module>
EDIT:
This is the live code: http://jsbin.com/poquke/1/edit?html,output
I have played around a bit with your code and I noticed that it will work if you wrap the code in your changed handler in an async function. This fixed both issues that you described.
_dataChanged: function (e) {
this.async(function(){
if (this.data != null) {
while (this.data.length < this.minItemSize) {
this.push('data', {content: ""})
}
} else {
this.data = [{content: ""}];
}
});
}
I don't have a perfect explanation for this behaviour. I assume it is related somehow to the way Polymer handles the observation for changes. Each time you push to the data array in the changed handler, this in fact changes data and should in turn trigger the handler again.
No async is required if you simplify.
Here is the simplified code, this removes the repeated calls to _dataChanged when you push the minimum values, and allows polymer's built-in eventing system to take care of updating and notifying the other elements. A function: _createNewItem() is for creating an object. This simplifies where item object creation is handled.
http://jsbin.com/vemita/6/edit?html,output
The link and URL references have changed from the sample code in the question above to conform to the polymer element and demo page standards to be used with polyserve.
I've commented on your original code for why each line should or shouldn't be there. this includes the reason for the changes to _dataChanged
http://jsbin.com/ponafoxade/1/edit?html,output

Categories

Resources