How to save a variable with local storage - javascript

I have created a timer with javascript which is started when the user begins a game, and stops when the game is completed. I would like to be able to record the users best time and save it using local storage. The code below shows my function which is fired on completion of the game, and works as far as displaying the user's best time on the page, however local storage is not retaining the variable, userBestTime, after the page is reloaded. Any help would be much appreciated.
function stop() {
clearInterval(timer);
timer = false;
$(stopwatchEl).addClass('endgame');
let timeTaken = stopwatchEl.textContent;
let timeInMs = ((Number(timeTaken.split(':')[0])*60000) +
(Number(timeTaken.split(':')[1])*1000) +
(Number(timeTaken.split(':')[2])));
let bestTime = 9999999;
if (timeInMs < bestTime) {
bestTime = timeTaken;
}
localStorage.setItem('bestTime', JSON.stringify(bestTime));
let jsonString = localStorage.getItem('bestTime');
let userBestTime = JSON.parse(jsonString);
$('.best-time').html('Best Time: ' + userBestTime);
console.log(userBestTime);
}

Related

(Beginner Coder. Entry Entry Level) Save/Load function on HTML clicker game not working

Beginner learning from forums websites and youtube, bear with me pls.
(plus im dumb)
I'm making a stupid clicker game just to see if i can do it (clearly not).
I've got some buttons with onclick functions and multipliers setup whatever everything works fine.
Until Saving/Loading.
I followed a tutorial i found for the save function, to save/load your progress via localStorage/cookies, and it's saving the total "money" (score) upon refresh, but my "scorepersecond" and every upgrade via button doesn't save, even though i've included their cost and name values to tell which variables i want to save. I'm using VS Code with Live Server extension to test (firefox).
function loadGame() {
var savedGame = JSON.parse(localStorage.getItem("gameSave", "score", "scorepersecond", "cursors", "cursorcost", "lighters", "lightercost", "grinders", "grindercost", "devils", "devilcost", "trays", "traycost", "dealers", "dealercost"));
if (typeof savedGame.score !== "undefined") score = savedGame.score;
}
function saveGame() {
var gameSave = {
score: score,
scorepersecond: scorepersecond,
clickingPower: clickingPower,
cursors: cursors,
cursorcost: cursorcost,
lighters: lighters,
lightercost: lightercost,
grinders: grinders,
grindercost: grindercost,
devils: devils,
devilcost: devilcost,
trays: trays,
traycost: traycost,
dealers: dealers,
dealercost: dealercost,
};
localStorage.setItem("gameSave", JSON.stringify(gameSave));
document.getElementById("score").innerHTML = score;
document.getElementById("scorepersecond").innerHTML = scorepersecond;
document.getElementById("cursorcost").innerHTML = cursorcost;
document.getElementById("cursors").innerHTML = cursors;
document.getElementById("lightercost").innerHTML = lightercost;
document.getElementById("lighters").innerHTML = lighters;
document.getElementById("grindercost").innerHTML = grindercost;
document.getElementById("grinders").innerHTML = grinders;
document.getElementById("devilcost").innerHTML = devilcost;
document.getElementById("devils").innerHTML = devils;
document.getElementById("traycost").innerHTML = traycost;
document.getElementById("trays").innerHTML = trays;
document.getElementById("dealercost").innerHTML = dealercost;
document.getElementById("dealers").innerHTML = dealers;
}
window.onload = function() {
loadGame();
updatescorepersecond();
document.getElementById("score").innerHTML = score;
document.getElementById("cursorcost").innerHTML = cursorcost;
document.getElementById("cursors").innerHTML = cursors;
document.getElementById("lightercost").innerHTML = lightercost;
document.getElementById("lighters").innerHTML = lighters;
document.getElementById("grindercost").innerHTML = grindercost;
document.getElementById("grinders").innerHTML = grinders;
document.getElementById("devilcost").innerHTML = devilcost;
document.getElementById("devils").innerHTML = devils;
document.getElementById("traycost").innerHTML = traycost;
document.getElementById("trays").innerHTML = trays;
document.getElementById("dealercost").innerHTML = dealercost;
document.getElementById("dealers").innerHTML = dealers;
};
Thing's I've Tried.
function loadGame() {
var savedGame = JSON.parse(localStorage.getItem("gameSave"));
if (typeof savedGame.score !== "undefined") score = savedGame.score;
}
function loadGame() {
var savedGame = JSON.parse(localStorage.getItem("gameSave"));
if (typeof savedGame.score !== "undefined") score = savedGame.score;
if (typeof savedGame.scorepersecond!== "undefined") scorepersecond = savedGame.scorepersecond;
}
along with other variables i want to save, in the form of "(typeof " which have also failed.
Not sure if this bit literally means anything, but if i inspect element on the page and access local storage it updates accordingly every 30 seconds with proper values, but upon page refresh it poof's (except for total "money" (score) on top of the page).
Not sure what people need to see or if i shared enough, but if anyone could help without being a d-bag that'd be cool :) even if not to solve it but a general idea of where i f'd up besides the whole thing. thanks in advance and lmk if you need to see more of my poopy clicker game.
You can only get one value with getItem().
If you want to get the json object of all values, simply use localStorage.
A Storage object which can be used to access the current origin's local storage space.
var savedGame = localStorage;
Refernce:
getItem()
localStorage

How can I get the timer started from the user input NOT the just constant value and keep my session storage still working?

I made a timer going even after reloading the page using javascript's session storage.
BUT regarding the timer at the first place, I want to get it started from getting USER INPUT.
Instead of specific number of time like 300(what I did so far below), I want to get a value from the user. Like, when the user clicked on a button on the page a pop up shows up asking the user how much time you want to put for the timer and the user put the value whatever he/she wants and the timer gets started upon that.
var userTime1 = 300;
var time = sessionStorage.getItem('timer_time');
var min = sessionStorage.getItem('timer_min');
var sec = sessionStorage.getItem('timer_sec');
if (!time){
time = userTime1;
min = parseInt(time/60);
sec = time%60;
}
var interval = setInterval(function () {
time--;
min = parseInt(time/60);
sec = time%60;
sessionStorage.setItem('timer_time', time);
sessionStorage.setItem('timer_min', min);
sessionStorage.setItem('timer_sec', sec);
document.getElementById("timeLeft1").innerHTML = min + "min" + sec + "sec";
};
if (time == 0) {
clearInterval(interval);
sessionStorage.removeItem('timer_time');
sessionStorage.removeItem('timer_min');
sessionStorage.removeItem('timer_sec');
sessionStorage.clear();
alert("Timer Expired!");
}
}, 1000);

Understanding how to use asynchronous functions in Javascript - counts and timers?

I'm trying to make a small page that runs a survey. I'd like the survey to be repeatable within the page, but the user needs to enter a login name when they enter the page. I'm attempting to write code such that they fill out the login, and then the survey begins. I'm trying to have a JSON that feeds in 100+ random images, sending in a new one each time the user completes the survey application.
So, whats happening is every time the start function is called, the survey function runs. However, it only runs for around 1 second, rather than the continuous running I'd like to have. When I've played with the ordering of the page and added timers, I've managed to get it such that the survey runs a single time but does not reset itself upon completion. It also doesn't seem to be picking up variables from the other function - I wanted the "count" variable to increase as the survey is repeatedly completed. It also isn't picking up the username variable, which is created inside of the outside "start" function.
I think my problem here has to do with not understanding how functions and variables are supposed to be nested inside of each other, and with how asynchronicity works in Javascript. Can anyone point me in the right direction? Here's a JSfiddle for the problem, and a code snippit:
//button Login
function serv (){
Survey
.StylesManager
.applyTheme("modern");
window.survey = new Survey.Model(json);
survey
.onComplete
.add(function (result) {
count ++;
var PID = username;
var results = PID + "|||" + (keyname) + ":\n" + JSON.stringify(result.data, null, 3) + (count) ;
document
.querySelector('#surveyResult')
.textContent = results;
survey.clear();
survey.render();
});
$("#surveyElement").Survey({model: survey});
}
function start() {
var username = document.getElementById("user_PID").value;
alert("your PID is " + username);
modal.style.display = "none";
serv();
}
var knlist = {}
var count = 13
var knx = ("kn" + count)
var keyname = (knlist[knx])
var mapilink = "https://images.mapillary.com/" + (keyname) + "/thumb-1024.jpg";
var json = {}
var modal = document.getElementById('id01');

trying to create a leaderboard with score and time. Local Storage?

I am trying to create a leaderboard when someone completes my quiz. I can get the person to enter their name via a prompt with their score when they complete quiz. I just can get the data to stay. I think I need to store the data with storage? Or is it there a better way to do this?
I added my code to codepen since it's kind of long:
https://codepen.io/rob-connolly/pen/xyJgwx
Edit: fixed broken codepen link
// variables
var score = 0; //set score to 0
var total = 10; //total nmumber of questions
var point = 1; //points per correct answer
var highest = total * point;
//init
console.log('script js loaded')
function init() {
//set correct answers
sessionStorage.setItem('a1', "b");
sessionStorage.setItem('a2', "a");
sessionStorage.setItem('a3', "c");
sessionStorage.setItem('a4', "d");
sessionStorage.setItem('a5', "b");
sessionStorage.setItem('a6', "d");
sessionStorage.setItem('a7', "b");
sessionStorage.setItem('a8', "b");
sessionStorage.setItem('a9', "d");
sessionStorage.setItem('a10', "d");
}
//hide all questions to start
$(document).ready(function() {
$('.questionForm').hide();
//show question 1
$('#question1').show();
$('.questionForm #submit').click(function() {
//get data attribute
current = $(this).parents('form:first').data('question');
next = $(this).parents('form:first').data('question') + 1;
//hide all questions
$('.questionForm').hide();
//show next question in a cool way
$('#question' + next + '').fadeIn(400);
process('' + current + '');
return false;
});
});
//process answer function
function process(n) {
// get input value
var submitted = $('input[name=question' + n + ']:checked').val();
if (submitted == sessionStorage.getItem('a' + n + '')) {
score++;
}
if (n == total) {
$('#results').html('<h3>Your score is: ' + score + ' out of ' + highest + '!</h3> <button onclick="myScore()">Add Your Name To Scoreboard!</a>')
stop()
}
return false;
}
window.yourPoints = function() {
return n;
}
function myScore() {
var person = prompt("Please enter your name", "My First Name");
if (person != null) {
document.getElementById("myScore").innerHTML =
person + " " + score
}
}
var x;
var startstop = 0;
window.onload = function startStop() { /* Toggle StartStop */
startstop = startstop + 1;
if (startstop === 1) {
start();
document.getElementById("start").innerHTML = "Stop";
} else if (startstop === 2) {
document.getElementById("start").innerHTML = "Start";
startstop = 0;
stop();
}
}
function start() {
x = setInterval(timer, 10);
} /* Start */
function stop() {
clearInterval(x);
} /* Stop */
var milisec = 0;
var sec = 0; /* holds incrementing value */
var min = 0;
var hour = 0;
/* Contains and outputs returned value of function checkTime */
var miliSecOut = 0;
var secOut = 0;
var minOut = 0;
var hourOut = 0;
/* Output variable End */
function timer() {
/* Main Timer */
miliSecOut = checkTime(milisec);
secOut = checkTime(sec);
minOut = checkTime(min);
hourOut = checkTime(hour);
milisec = ++milisec;
if (milisec === 100) {
milisec = 0;
sec = ++sec;
}
if (sec == 60) {
min = ++min;
sec = 0;
}
if (min == 60) {
min = 0;
hour = ++hour;
}
document.getElementById("sec").innerHTML = secOut;
document.getElementById("min").innerHTML = minOut;
// document.getElementById("hour").innerHTML = hourOut;
}
/* Adds 0 when value is <10 */
function checkTime(i) {
if (i < 10) {
i = "0" + i;
}
return i;
}
function reset() {
/*Reset*/
milisec = 0;
sec = 0;
min = 0
hour = 0;
document.getElementById("milisec").innerHTML = "00";
document.getElementById("sec").innerHTML = "00";
document.getElementById("min").innerHTML = "00";
document.getElementById("hour").innerHTML = "00";
}
//adding an event listener
window.addEventListener('load', init, false);
]2]2
localStorage, as the name suggests is local - the data will only be accessible in the browser it's saved in. sessionStorage is also local. Generally anything that doesn't rely on a server will be local.
To store and display the data across multiple clients, you will need a server. What you need in this case is a simple back end that will provide two endpoints - one that will display the scoreboard (GET) and another that will save the data into the scoreboard (POST). There are many options you can use to create that, if you're familiar with node.js you could try express and sequelize with sqlite (if you need a database) or you could store the data in a text (CSV) file.
To retrieve the data from the web app you will need to use AJAX, if you want an easy way to make HTTP requests from JS try fetch - it's available in all modern browsers. Make sure to configure CORS properly on the server - this will cause some headaches in the beginning but a value of * for Access-Control-Allow-Origin is generally fine for projects like that.
The general flow would be like this:
After your web app is opened, the JS will fetch /scores (without any options).
Whenever there's a need to store a score you would fetch /scores/create with method: 'POST' and body: JSON.stringify(scoreObject).
Here's an example on how to get data from fetch:
async function getScores() {
try {
const res = await fetch('http://localhost:8080/scores');
const json = await res.json();
// json will contain your scores
} catch (e) {
// Something went wrong.
console.log(e); // Check console for more details.
}
}
It may sound extremely difficult at first but once you start working on this everything will start to make sense.
To reiterate:
Make a back end and host it somewhere. Make sure to configure CORS.
Use fetch to get your data to (and from) your page.
Keep on experimenting, that's the best way to learn.
You will need to host the site somewhere in order for multiple users to share application state. The "Local Storage" API's are out of the question, unfortunately.
Read up on web storage API's here: https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API
As soon as you have the need to persist data across multiple browsers and users you have now entered some fiery challenges. There's a thousand ways to solve this one. Some of the concerns to consider are:
Security: How will you be able to securely store each users' data and know which requests come from which user?
Storage: The data has to live somewhere outside of any individual users browser. Thus, you will need some sort of hosting.
What about when you need to update the quiz? What happens to old completed quizzes? Will they be schema-compatible? Data migration is... lovely.
I would suggest the following study:
Figure out a way to persist your web application data. This means you will need to either host or setup an account with a provider such as Amazon, Google or Microsoft Azure where you can host your data.
For simple testing you can use the AJAX API's (the fetch thing mentioned before), or it is worth spending some time studying up on modern frameworks such as Angular, React or Vue.
If you feel the momentum while grappling with AJAX or one of the web UI frameworks, then these links might help:
https://aws.amazon.com/serverless/build-a-web-app/
https://aws.amazon.com/websites/
https://firebase.google.com/docs/web/setup
https://azure.microsoft.com/en-us/services/app-service/web/
Ultimately there are a TON of options here... these are just a few approaches to solving the problem. You can setup your own VM, you can use a myriad of "serverless" options, you can create hosted "functions" with persistence... look around a bit.
The most important thing I would suggest learning is how data is stored in backend databases for web applications. Check out the free options for some of the major services. They almost all have an option for using their services for free as long as you don't exceed monthly thresholds. Even after those thresholds are met, it's really not that expensive to have a hosted web application with some sort of database back-end.
It may sound daunting but it might be worth considering grabbing a good book on building web applications. Something using .NET Core, Python or node.js makes a reasonable back-end for API code. It really comes down to whatever you're comfortable with.
Ask some specific questions on here once you latch on to something specific and I'm sure the community will be happy to help.
Good luck!

multiple setInterval timers on node server

My app is a game where a user has 30 mins to finish....node backend
Each time a user starts a game then a setInterval function is triggered server side....once 30mins is counted down then I clearInterval.
How do I make sure that each setInterval is unique to the particular user and the setInterval variable is not overwritten each time a new user starts a game? (or all setInterval's are cleared each time I clear).
Seems like I might need to create a unique "interval" variable for each new user that starts game??
Below code is triggered each time a new user starts a game
let secondsLeft = 300000;
let interval = setInterval(() => {
secondsLeft -= 1000;
if (secondsLeft === 0) {
console.log("now exit");
clearInterval(interval);
}
}, 10000);
Thanks!!
We used agenda for a pretty big strategy game backend which offers the benefit of persistence if the node app crashes etc.
We incorporated the user id into the job name and would then schedule the job, along with data to process, to run at a determined time specifying a handler to execute.
The handler would then run the job and perform the relevant tasks.
// create a unique jobname
const jobName = `${player.id}|${constants.events.game.createBuilding}`;
// define a job to run with handler
services.scheduler.define(jobName, checkCreateBuildingComplete);
// schedule it to run and pass the data
services.scheduler.schedule(at.toISOString(), jobName, {
id: id,
instance: instance,
started: when
});
Worked pretty well and offered decent protection against crashes. Maybe worth considering.
First: Concurrent Intervals and Timers are not the best design approach in JS, it is better to use one global timer and a list of objects storing the start, end, userid etc and update these in a loop.
Anyway. To have your interval id bound to a certain scope, you can use a Promise like so:
const createTimer = (duration, userid) => new Promise(res => {
const start = new Date().getTime();
let iid;
(function loop () {
const
now = new Date().getTime(),
delta = now - start
;
//elapsed
if (delta >= duration) {
clearTimeout(iid);
res(userid);
//try again later
} else {
iid = setTimeout(loop, 100)
}
})();
});
This way each timer will run »on its own«. I used setTimeout here since that wont requeue loop before it did everything it had to. It should work with setInterval as well and look like that:
const runTimer = (duration, userid, ontick) => new Promise(res => {
const
start = new Date().getTime(),
iid = setInterval(
() => {
const delta = new Date().getTime() - start;
if (delta < duration) {
//if you want to trigger something each time
ontick(delta, userid);
} else {
clearInterval(iid);
res(userid);
}
}, 500)
;
});
You do not even need a promise, a simple function will do as well, but then you have to build some solution for triggering stuff when the timer is elapsed.
Thanks #Chev and #philipp these are both good answers.
I was also made aware of a technique where you use an array for the setInterval variable.....this would make my code as follows;
let intervals = []
let secondsLeft = 300000;
intervals['i'+userId] = setInterval(() => {
secondsLeft -= 1000;
if (secondsLeft === 0) {
console.log("now exit");
clearInterval(interval);
}
}, 10000);
Does anyone else foresee this working?.
UPDATE 6.56pm PST.....it works!!

Categories