I am trying to make a basic theme switching code using HTML and JavaScript. But if I hit back or refresh, the selection is cancelled and the page is back to normal.
Can I add any function in JavaScript so that the selection stays till cache clean or something like that?
var x = 0;
var themeValue = 0;
function changeTheme3() {
themeValue ++;
if (themeValue > 2) {
themeValue = 1;
}
if (themeValue == 1) {
document.body.style.backgroundColor = "grey";
} else if (themeValue == 2) {
document.body.style.backgroundColor = "white";
}
}
button {
display: block;
margin: 0 auto;
padding: 0;
width: 250px;
height: 70px;
border: 2px solid #1ECD97;
border-radius: 40px;
background: transparent;
color: #1ECD97;
letter-spacing: 1px;
font-size: 18px;
font-family: 'Montserrat', sans-serif;
}
button:hover {
background-color: #1ECD97;
color: #fff;
}
<div id="theme-button">
<button type="button" onclick="changeTheme3()">Change Theme</button>
</div>
I'd suggest making use of LocalStorage. If you want the user to be able to customize their experience, you need to save that somewhere. This is typically done through a Session or Database, however both of those are back-end solutions.
For front-end, you have the options of setting a cookie or using localstorage. If you want the theme selection to be limited to a single session, you can also use sessionStorage
For implementation
function changeTheme3() {
themeValue ++;
if (themeValue > 2) {
themeValue = 1;
localStorage.setItem('themeValue', themeValue);
}
if (themeValue == 1) {
document.body.style.backgroundColor = "grey";
} else if (themeValue == 2) {
document.body.style.backgroundColor = "white";
}
}
Then, somewhere when you load a page, you need to pull this value from storage. (Note, localStorage saves values as strings, so you may want to parseInt() your value when retrieving).
function loadTheme(){
if (localStorage && localStorage.getItem('themeValue'){
var storedTheme = parseInt(localStorage.getItem('themeValue'));
//do your logic to set the theme based on value
} else {
//do nothing or choose to set your default theme as the value into storage
}
}
One side note, depending on which browsers you are supporting, you may want to make sure you're checking to see if localStorage is supported. It has good support for any modern browser.
you can do that using sqlite html5 for example check this link http://www.html5rocks.com/en/tutorials/webdatabase/todo/ :D
here for simple example sir
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
var db = openDatabase('db', '1.0', 'theme selector', 1000); //db name, version, desc, size in byte
var msg;
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS THEME (id unique, theme)');
});
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM THEME WHERE id = 1', [], function (tx, results) {
var len = results.rows.length, i;
var value = 'theme_1';
if(len == 0 ){
tx.executeSql('INSERT INTO THEME (id, theme) VALUES (1, ?)', [value]);
}else{
value = results.rows.item(0).theme;
}
document.querySelector('#theme_selected').innerHTML = value;
document.getElementById('theme_select').value = value;
}, null);
});
function update (){
var selector = document.getElementById('theme_select');
var value = selector[selector.selectedIndex].value;
db.transaction(function (tx) {
tx.executeSql('UPDATE THEME SET theme = ? WHERE id=1', [value]);
document.querySelector('#theme_selected').innerHTML = value;
});
}
</script>
</head>
<body>
<select id="theme_select">
<option value="theme_1" >theme 1</option>
<option value="theme_2">theme 2</option>
</select>
<button onclick="update()">update</button>
<div id="theme_selected"></div>
</body>
</html>
Related
soo, i am trying to use localstorage to store the classlist so it will remember whether or not something was added to their favorites list. i need to do this with JavaScript. The error provided comes from the console in my web browser (chrome)
The ERROR
main.js:99 Uncaught TypeError: Cannot read property 'value' of undefined
at storeFavo (main.js:99)
at HTMLButtonElement.favorites (main.js:71)
HTML
<!-- Showcase -->
<section class="showcase">
<div class="container grid ">
<div class="showcase-form card">
<h2>*Input Car Name*</h2>
<img alt="" src="#" >
<button id="favo" class="btn">Add to Favorites</button>
<button id="info" class="btn">More Info</button>
</div>
</div>
</section>
JavaScript
window.addEventListener('load', init);
const info = document.querySelector('#info');
const div1 = document.querySelector('.moreInfo');
const favo = document.querySelector('#favo');
let apiUrl = 'webservice/includes/actions.php';
let apiUrl2 = 'webservice/index.php';
let Favos = document.getElementById('favo').getElementsByClassName('favorited')[0];
function init() {
info.addEventListener('click', moreInfo);
favo.addEventListener('click', favorites);
if (typeof window.localStorage === "undefined") {
console.error('Local storage is not available in your browser');
return;
}
checkFromLocalStorage()
carList;
}
function carList() {
fetch(apiUrl)
.then((response) => {
if (!response.ok) {
throw new Error(response.statusText);
}
return response.json();
})
.then(getAjaxSuccessHandler)
.catch(getAjaxErrorHandler);
}
function getAjaxSuccessHandler(data) {
console.log(data);
}
function getAjaxErrorHandler(data) {
console.error(data);
}
// Generate Cards
// getCars.map((item)=>{
// return (
// <div>
// <p> {item.brand}</p>
// <p> {item.type}</p>
// </div>
// );
// }),
// More Info Button
function moreInfo() {
let title= document.createElement('h1');
title.innerHTML = 'Info';
div1.appendChild(title)
console.log("info?")
if (div1.style.display == 'block'){
div1.style.display = 'none';
} else {
div1.style.display = 'block';
}
}
// Add To Favorites Button
function favorites() {
console.log("favo")
if (favo.classList == 'btn') {
favo.classList.remove('btn')
favo.classList.add('favorited')
favo.innerHTML = 'Remove from favorites';
storeFavo()
}
else {
favo.classList.remove('favorited')
favo.classList.add('btn')
favo.innerHTML = 'Add to Favorites';
deleteClickHandler()
}
}
//Check
/**
* Is local storage is available on page load? Let's fill the form
*/
function checkFromLocalStorage() {
if (localStorage.getItem('favos') !== null) {
Favos.value = localStorage.getItem('favos');
}
}
//Store
/**
* After submitting the form, let's save the values in the local storage
*
* #param e
*/
function storeFavo(e) {
localStorage.setItem('favos', Favos.value);
localStorage['Favos'] = document.getElementById("favo")
}
//Delete
/**
* Make sure we clean up the local storage again
*
* #param e
*/
function deleteClickHandler(e) {
localStorage.removeItem('favos');
}
CSS
.favorited {
display: inline-block;
padding: 10px 30px;
cursor: pointer;
background: #470aed;
color: #ffffff;
border: none;
border-radius: 5px;
}
.btn {
display: inline-block;
padding: 10px 30px;
cursor: pointer;
background: var(--primary-color);
color: #ffffff;
border: none;
border-radius: 5px;
}
I will do my very best to respond fast and to provide any needed information if asked for.
Check the documentation of localStorage.setItem https://developer.mozilla.org/en-US/docs/Web/API/Storage/setItem, you can write only string values, but you are trying to write an Object value (https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName). If you want to have some persistence fo your HTML element, you can save outerHTML https://developer.mozilla.org/ru/docs/Web/API/Element/outerHTML to the storage and parse it on load.
I am absolutely a noob when it comes to Javascript so I hope someone can help me please. I made a very simple Vanilla JS + HTML code that counts the number of times that it reaches 10 seconds (10 seconds = 1 count). This code will also refresh the page onmouseleave and when I change tab using window.onblur. My problem is that every time the page refreshes, the counter will go back to zero. What I want is that for the counter to deduct just one (or a specific number of) count every page refresh instead of completely restarting the count to zero. Please help me with Vanilla Javascript only and no JQuery (because I am planning to use this code personally and offline). Thank you in advance.
For those who may wonder what's this code is for, I want to create this to encourage myself to stay away from my computer for a certain period everyday. Like, if I can stay away from my computer for 100 counts, then I can use my computer freely after. I am addicted to the internet and I want to make this as my own personal way of building self-control.
Here is my code:
<style>
label {
color: orange;
}
p {
border-radius: 0px;
color: black;
text-decoration: none;
font-family: Consolas !important;
font-size: 16px;
font-weight: normal;
outline: none;
line-height: 0.25 ;
}
</style>
<body onmouseleave="window.location.reload(true)">
<p>You have earned <label id="pointscounter">00</label> point/s.</p>
<script>
var PointsLabel = document.getElementById("pointscounter");
var totalCountPoints = 0;
setInterval(setTimePoints, 10000);
function setTimePoints() {
++totalCountPoints;
PointsLabel.innerHTML = pad(totalCountPoints);
}
function pad(val) {
var valString = val + "";
if (valString.length < 2) {
return "0" + valString;
} else {
return valString;
}
}
</script>
<script>
var blurred = false;
window.onblur = function() { blurred = true; };
window.onfocus = function() { blurred && (location.reload()); };
</script>
</body>
Storage
If you want the data to survive a reload, you need to save it somewhere. There are multiple options you can use. I used localStorage. You can learn more about it here: https://www.w3schools.com/jsref/prop_win_localstorage.asp. localStorage even survives closing the Browser Tab.
If you want to reset the data in a new session, you can use sessionStorage (just replace localStorage with sessionStorage): https://www.w3schools.com/jsref/prop_win_sessionstorage.asp.
What I did:
Save data on blur
If a blur-event occurs, the data is saved.
I also stopped the interval because there is no need for the interval anymore.
blurred variable
There is (currently?) no need for this variable.
The only usecase seems to be:
window.onfocus = function() {
blurred && location.reload();
};
To my knowledge you don't need this variable here.
Comming back
If the user already has points in localstorage, the current Points are calculated based on the points in localstorage. It currently deducts 1 point.
Using onmouseleave
I replaced the location.reload(true) on the body-tag with a function call. Everytime the mouse leaves, it calls this function. This function calls the onBlur function. The onBlur function is there, to ensure, that both window.onblur and onmouseleave do the same thing (save & stop). After the onBlur function is called, an EventListener is added to wait for mouseenter. When the mouse is seen again, we can reload the page with the onFocus function. It wouldn't reload the page as soon as the mouse left, because the timer would start (bc of reload), even if the mouse wasn't on the document.
Todo:
There is currently no check to see, if a the mouse in on the document after a reload. The timer will begin, even if the mouse isn't on the document.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<style>
label {
color: orange;
}
p {
border-radius: 0px;
color: black;
text-decoration: none;
font-family: Consolas !important;
font-size: 16px;
font-weight: normal;
outline: none;
line-height: 0.25;
}
</style>
</head>
<body onmouseleave="mouseLeft()">
<p>You have earned <label id="pointscounter">00</label> point/s.</p>
<script>
var PointsLabel = document.getElementById("pointscounter");
var totalCountPoints = 0;
// Calculate Points if user has already collected points
if (localStorage.getItem("points") !== null) {
// You can change, how many points to deduct
const pointsToDeduct = 1;
var tempPoints = localStorage.getItem("points");
totalCountPoints = tempPoints - pointsToDeduct;
// Reset to 0 if points now negative
if (totalCountPoints < 0) {
totalCountPoints = 0;
}
PointsLabel.innerHTML = pad(totalCountPoints);
}
// need to save, to stop/clear it later
var timePointsInterval = setInterval(setTimePoints, 10000);
function setTimePoints() {
++totalCountPoints;
PointsLabel.innerHTML = pad(totalCountPoints);
}
function pad(val) {
var valString = val + "";
if (valString.length < 2) {
return "0" + valString;
} else {
return valString;
}
}
function mouseLeft() {
onBlur();
document.addEventListener("mouseenter", onFocus);
}
function onBlur() {
// save Current Points:
localStorage.setItem("points", totalCountPoints);
//stop the timer
clearInterval(timePointsInterval);
}
function onFocus() {
location.reload();
}
// Blur Detection
var blurred = false;
window.onblur = function () {
// [-] blurred = true;
onBlur();
};
window.onfocus = function () {
// [-] blurred && location.reload();
onFocus();
};
</script>
</body>
</html>
I'm quite new to JS.
I want to have my html page stay the same when JS text will be appearing in one exact place without starting from blank page.
I trigger JS function via button on HTML, function in HTML:
function match () {
setTimeout(function () {
player_hp -= monster_dmg
monster_hp -= player_dmg
if (player_hp<=0) {
document.write("\nPlayer dies!")
menu();
return;
}
if (monster_hp<=0) {
document.write("\nPlayer wins!")
menu();
return;
}
if (fight=1) {
document.write("\nPlayer hp:" + player_hp)
document.write("\nMonster hp:" + monster_hp)
document.write("\n");
match()
}
}, interval)
}
One easy way to handle this is to simply create a <div> or a <span> element that has an ID attribute like this:
<div id="status"> </div>
Now you can access this element by using the Javascript method
document.querySelector("#status") and then use the innerHTML function of that element to change the internal content. You can even place the document.querySelector function into a convenient function which I have named send_status()
Here's the whole thing
/* default values */
var player_hp = 300;
var monster_dmg = 30;
var monster_hp = 200;
var interval = 500;
var player_dmg = 50;
match();
/* heres a function that will replace your document.write() functions */
function send_status(message) {
document.querySelector("#status").innerHTML = message;
}
function match() {
setTimeout(function() {
player_hp -= monster_dmg
monster_hp -= player_dmg
if (player_hp <= 0) {
send_status("\nPlayer dies!") // replaced document.write with send_status
menu();
return;
}
if (monster_hp <= 0) {
send_status("\nPlayer wins!")
menu();
return;
}
if (fight = 1) {
send_status("\nPlayer hp:" + player_hp)
send_status("\nMonster hp:" + monster_hp)
send_status("\n");
match()
}
}, interval)
}
function menu() {}
#game {
width: 100%;
height: 100px;
border: 2px solid black;
}
#status {
width: 100%;
height: 50px;
background-color: grey;
}
<div id="game">Game Goes Here</div>
<!-- here is your status area -->
<div id="status"></div>
You should create a results div, in which will be shown the match result.
Just add <div id="match_results"></div> in your HTML code.
And replace all yours document.write() for
document.getElementById('match_results').innerHTML += "<br>Player wins!"
This command is appending content in the element with ID match_results.
You should use <br> instead of \n because it is the proper way to break line in HTML code.
I have a simple script designed to increment a counter each time an image is clicked:
<script>
function clickCounter() {
if (typeof(Storage) !== "undefined") {
if (localStorage.clickcount) {
localStorage.clickcount = Number(localStorage.clickcount) + 1;
} else {
localStorage.clickcount = 1;
}
document.getElementById("counter").innerHTML = localStorage.clickcount;
} else {
document.getElementById("counter").innerHTML = "Your browser does not support web storage...";
}
}
</script>
The html:
<img id="heart" src="../assets/images/redheart.png" title="Give Love!" onclick="clickCounter()"><p id="counter"></p>
It's working fine but I'd like to be able to display the count BEFORE the click. Right now the counter shows only once the image button is clicked.
Thanks for any and all input.
If this isn't what you're going for, please let me know.
First, a few tweaks:
For accessibility reasons:
I made the <img> a <button> (with a background image). Buttons are super accessible and keyboard friendly (tab, enter key, etc.)
Added an aria-label to the button, since it contains no text content
Cleaned up the JavaScript a little.
Behavior:
On first page load…
Then we perform five clicks followed by a page refresh.
Note: This demo will not work here on Stack Overflow due to security restrictions in the editor. Have a look over in the fiddle I've created.
document.querySelector("button").addEventListener("click", clickCounter);
document.addEventListener("DOMContentLoaded", showValue);
let counter = document.getElementById("counter");
function showValue() {
counter.innerHTML = `Current count = ${localStorage.clickcount || 0}`;
}
function clickCounter() {
if (typeof(Storage) !== "undefined") {
if (localStorage.clickcount) {
localStorage.clickcount = Number(localStorage.clickcount) + 1;
} else {
localStorage.clickcount = 1;
}
showValue();
} else {
counter.innerHTML = "Your browser does not support web storage...";
}
}
button {
background-image: url(http://icons.iconarchive.com/icons/benzlee/free-christmas/512/heart-icon.png);
background-repeat: no-repeat;
background-size: 64px 64px;
background-color: transparent;
border: none;
display: inline-block;
width: 64px;
height: 64px;
cursor: pointer;
}
<button title="Give Love!" aria-label="Give Love!">
<div id="counter"></div>
https://jsfiddle.net/mgejhcnf/3/
Essentially, I am trying to create a webpage that has 2 buttons; one will cause the screen to flash randomly, and the other will cause it to slowly change colours. I want to be able to switch between these two (if you press the first button it starts flashing and then if you press the second button it slowly changes without any kind of cancel button).
The buttons each call a function which sets the 'running' variable of the other function to false and it's own 'running' variable to true. It then calls a recursive function (recursive in that it just calls itself over and over). These recursive functions only execute their code when their 'running' variable is true.
If you run the snippet you can see that the program is very inconsistent (you may need to play with it for a bit to see the issue since it sometimes seems to work). Sometimes it refuses to change function and other times the two functions seem to both be active and they both try to execute (it almost looks as if they are fighting for control). I don't understand how this is happening since, I believe, only one of the 'running' variables can be true at any time.
var runningDisco = false;
var runningColours = false;
function startColours() {
if (runningDisco == true); //Is disco running?
{
runningDisco = false; //If yes, stop it
}
runningColours = true; //Indicate we are running
window.setTimeout(Colours, 100, 0); //Run
}
function startDisco() {
if (runningColours == true); {
runningColours = false;
}
runningDisco = true;
window.setTimeout(Disco, 100);
}
function Disco() {
if (runningDisco == true); {
hex = "#";
for (discoCount = 0; discoCount < 6; discoCount++) {
hex = hex.concat((Math.floor(Math.random() * 17)).toString(16));
}
document.body.style.background = hex;
window.setTimeout(Disco, 10);
}
}
function Colours(colourCount) {
if (runningColours == true); {
if (colourCount > 359) {
colourCount -= 359;
}
document.body.style.background = "hsl(" + colourCount + ", 50%, 50%)";
window.setTimeout(Colours, 10, colourCount + 1);
}
}
input {
font-family: 'Roboto', sans-serif;
text-align: center;
background-color: #dd1021;
border: none;
color: white;
padding: 16px 32px;
text-decoration: none;
margin: 4px 2px;
cursor: pointer;
}
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<input id="clickMe" type="button" value="Start Disco" onclick="startDisco();" />
<input id="clickMe" type="button" value="Start Colours" onclick="startColours();" />
The semicolons after your if-statements are causing a problem
For example, replace:
if (runningColours == true); {
if (runningDisco == true); {
with
if (runningColours == true) {
if (runningDisco == true) {
Here it is fixed in jsfiddle.
You have semicolons in the wrong place
If you need to run a single animation you need to use a single global variable to hold the timeout handler and clear it when starting a new one.
Like this:
var running;
function startColours() {
clearTimeout(running);
running = setTimeout(Colours, 100, 0); //Run
}
function startDisco() {
clearTimeout(running);
running = setTimeout(Disco, 100);
}
function Disco() {
var hex = "#";
for (discoCount = 0; discoCount < 6; discoCount++) {
hex = hex.concat((Math.floor(Math.random() * 17)).toString(16));
}
document.body.style.background = hex;
running = setTimeout(Disco, 10);
}
function Colours(colourCount) {
if (colourCount > 359) {
colourCount -= 359;
}
document.body.style.background = "hsl(" + colourCount + ", 50%, 50%)";
running = setTimeout(Colours, 10, colourCount + 1);
}
input {
font-family: 'Roboto', sans-serif;
text-align: center;
background-color: #dd1021;
border: none;
color: white;
padding: 16px 32px;
text-decoration: none;
margin: 4px 2px;
cursor: pointer;
}
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<input id="clickMe" type="button" value="Start Disco" onclick="startDisco();" />
<input id="clickMe" type="button" value="Start Colours" onclick="startColours();" />
The real problem is the semicolons after the if statements inside the Disco and Colours functions:
if (runningDisco == true); {
document.body.style.background = …
}
will execute as
if (runningDisco == true)
;
{
document.body.style.background = …
}
which runs the content regardless of the boolean variable. Why does it work at all sometimes? I guess when the two setTimeout callbacks run close enough to each other that only the latter is rendered at all it feels consistent. Of course that is very unstable - they are indeed fighting each other for screen time.
You made a common mistake to those new to JavaScript - including a semi-colon after you if header. This creates an if statement with no body that is followed by a block containing the single statement runningColours = false, which will not execute correctly. The below should fix this:
if (runningColours == true)
{
runningColours = false;
}
The following JSFiddle link should have a working version of your script:
https://jsfiddle.net/4qhmtnhe/
I hope it starts working, and you continue to learn JavaScript.