I am creating a simple Tetris game using React JS. My main Component besides App.js is a Tetris.js functional component. In useEffect() I am storing components like the stage or current player tetromino using Local Storage. While playing, retrieving data in the console is possible and the data is not null.
useEffect(() => {
localStorage.setItem("dropTimeStored", JSON.stringify(dropTime));
localStorage.setItem("stageStored", JSON.stringify(stage));
localStorage.setItem("playerStored", JSON.stringify(stage));
localStorage.setItem("rowsClearedStored", JSON.stringify(rowsCleared));
localStorage.setItem("scoreStored", JSON.stringify(score));
localStorage.setItem("rowsStored", JSON.stringify(rows));
localStorage.setItem("levelStored", JSON.stringify(level));
localStorage.setItem("gameOverStored", JSON.stringify(gameOver));
}, [dropTime, stage, player, rowsCleared, score, rows, level, gameOver])
I would like to give users a choice to continue the game after instantly closing the browser. Thats why in starting game function i am doing:
const startGame = () => {
console.log(loadLocalStorage);
if (loadLocalStorage){
setDropTime(JSON.parse(localStorage.getItem("dropTimeStored")));
setStage(JSON.parse(localStorage.getItem("stageStored")));
player = JSON.parse(localStorage.getItem("playerStored"));
rowsCleared = JSON.parse(localStorage.getItem("rowsClearedStored"));
setScore(JSON.parse(localStorage.getItem("scoreStored")));
setRows(JSON.parse(localStorage.getItem("rowsStored")));
setLevel(JSON.parse(localStorage.getItem("levelStored")));
setGameOver(JSON.parse(localStorage.getItem("gameOverStored")));
} else {
localStorage.clear();
setStage(createStage());
setDropTime(1000);
resetPlayer();
setGameOver(false);
setScore(0);
setRows(0);
setLevel(0);
}
}
But while the "loadLocalStorage" flag is set to True, which means that the user has clicked the button and is willing to continue the game, nothing has happened. Elements retrieved from local storage are empty, for example the stage has no elements - JSON.parse(localStorage.getItem("stageStored")) gives me empty stage, with no tetrominoes. Why it is happening? Is closing browser or closing browser's card flushes localStorage? Thanks.
Move your localStorage.setItem() calls from useEffect block. For each app refresh, calling setItem in useEffect is overriding the actual storage values.
For this to work, set your local storage data whenever you are updating the state.
For Example, write a common method to update the localStorage data like this :
const updateLocalStorage = (key, value) => {
localStorage.setItem(key, value);
}
Whenever you are updating the state like below, immediately set the localStorage value as well :
const dropTime = 1000 / (level + 1) + 200;
setDropTime(dropTime);
updateLocalStorage('dropTimeStored', dropTime);
As an example, I have done this change in your code for dropTime value in your pastebin code. You can do the same for other values as well.
Related
I need some help.
I'm trying make it so that when I use text.splice() it keeps the changes when i reload the page.
Here is what I'm trying to do. It will Delete the item of the array that I wrote in the input element, but its not saving the changes made with splice().
function DeleteButton(){
const dltinpt = Deleteinput.value();
const index = secretPasswords.indexOf(dlinpt);
if (index > -1) {
secretPasswords.splice(index, 1);
}
}
Changes made to a value stored in a variable will not be persisted between page loads. That's just a fundamental principle of JavaScript and web browsers. If you want to preserve state between page loads you are going to need to use cookies or localStorage.
I'm trying to make a code which lets me show how much a certain part of my website has been views.
My problem is, when I fresh refresh, it goes back to zero, instead of 2. I hope you can help me out. I want the code to run forever, or as long as I want it to, and it will just add a 1 to what it has been, even if it was yesterday. Here's the sample of the code.
<script type="text/javascript">
var bannerViews = 0;
function addViews (){
bannerViews = bannerViews + 1;
}
addViews();
</script>
<p>This banner has been viewed <script type="text/javascript">document.write(bannerViews);</script> timesĀ </p>
Hope you can help me out.
It is because every time you refresh your page, your code reinitializes. In-order to persist the data, you need to store it somewhere. Either in a cookie or a localstorage.
If you go ahead with the localstorage, here's how you do it.
var bannerViewCount = localStorage.getItem('bannerViews');
if(!bannerViewCount) {
bannerViewCount = 0;
}
function addViews() {
localStorage.setItem('bannerViews', ++bannerViewCount);
document.body.innerHTML = 'Banner view count is :' + bannerViewCount;
}
addViews();
Demo (click on Run on the top bar multiple times and see it incrementing)
Here, what am doing is first, fetching the banners view count. If I don't get it, I initialize it with zero.
Later, I on addViews() call, I increment the bannerViewCount by one and store it to the localStorage. That's it.
Note that the data is stored in your local storage, so if you are expecting that the count should be visible to other users too, you need to store it in a database or a text file and later parse it.
If you want to store it on the cloud, so that you can share the count across the visitors, you can do something like this.
function addViews() {
$.get('//jsonbin.io/b/5974382ca489d40388582791/latest', function(data) {
var bannerViewCount = data.bannerviews;
$.ajax({
url: '//jsonbin.io/b/update/5974382ca489d40388582791',
type: 'post',
dataType: 'json',
data: {
snippet: JSON.stringify({
bannerviews: ++data.bannerviews
})
},
success: function(fetch) {
var data = fetch.data;
document.body.innerHTML = 'Banner view count is : ' + JSON.parse(data).bannerviews;
}
});
});
}
addViews();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Click on "Run Code Snippet" button and see the counter incrementing. Go to any other browser and the count will persist as expected. Note that the data stored here can be manipulated as there is no authentication in place. So avoid it if you want the count to be precise and legit.
It goes back to 0 because the variable bannerViews is reinitialised to 0 on every page load.
You will need to store this variable in a JSON file/DB and fetch/update the value there.
Every time you refresh the page the code is going to be reset and variables are included.
To solve this you have to either use a web server and have the variable saved there or find a way to save the variable to the filesystem and load it
back.
The reason the counter is reset constantly is because you're declaring the variable during runtime. There is no persistence to the variable so every time the website is loaded, the variable starts against from 0. Each browser client would keep track of the variable separately so even if you were able to get the variable to persist on your local browser, you would not be able to keep track of the page views from other browsers. The solution to this problem is to keep track of the page views from a centralized server.
You can use a free service such as http://www.webestools.com/pages-views-counter-free-number-pages-views-statistics.html to create the counter that would persist between page views and different clients.
What you need to do is to get the initial value 0 , store in on the server , database or file.
change line var bannerViews = 0; to something like;
var bannerViews = getValueFromServer();
and every after re assigning it, you store it back to the external storage;
For now everytime you refersh the page .
the code var bannerViews = 0; will run and hence bannerViews will alwayz be re assigned to 0
I am trying to implement a navigation to my ajax controlled site, and I am encountering some strange errors.
I am using History JS, the HTML5 only version.
This is how I initialize it:
function initializeHistory() {
var History = window.History;
if ( !History.enabled ) {
console.log("Not enabled!");
return false;
}
// Changing the main page state to -1.
History.replaceState({id:-1}, baseTitle, baseUrl);
// Bind to StateChange Event
History.Adapter.bind(window,'statechange',function(){
var State = History.getState();
console.log(History.savedStates);
if (historyData.manualStateChange)
{
if (State.data.id=='-1') alert('History start');
historyData.allowHistoryPushPop=false;
var gotoState=historyData.data[State.data.id];
var currentState=historyData.currentNavigation;
/* Some code here to revert to the previous state */
historyData.allowHistoryPushPop=true;
}
History.log(State.data, State.title, State.url);
});
};
I am using a global object, named historyData, in which I store the following things:
var historyData={
data: new Array(), //an array which contains objects that refer to the data that needs to be shown, when back or forward button is pushed
manualStateChange: true, //using this to figure out if the back or forward button was pressed in the browser, or if I am adding or removing a state from History programmatically
allowHistoryPushPop: true, //using this to prevent history from being changed in certain situations
currentNavigation: {
page: 'dashboard',
pageid: null,
module: null,
moduleid: null
}, // stores the current object from the historyData.data array
status: true // boolean that enables or disables History on my page
}
Whenever I click on a link in my page, a function, called navigation fires, which changes the History's state, and eventually runs a chain of functions to display the page which was asked for by the user. The relevant parts from the navigation function are as follows:
function navigation(gotofunc, navData) {
if ((historyData.allowHistoryPushPop) && (historyData.status))
{
if (navData['urlData']==null) // if this is null, then the title and the url for the asked page, will be returned by the server, after an ajax call, so we set it to the current url and current title
{
var curState=History.getState();
urlData={
title: curState.title,
url: curState.url
};
} else {
urlData=navData['urlData'];
if (!urlData['title']) urlData['title']=curState.title;
if (!urlData['url']) urlData['url']=curState.url;
}
navData['parameters']=new Array();
if (arguments.length>2) for (i=2;i<arguments.length ;i++) navData['parameters'].push(arguments[i]);
historyData.manualStateChange=false; // we are making a programmatic change, so we don't want the binded 'statechange' to fire
historyData.data.push(navData); // store the history data in our own array
History.pushState({id:historyData.data.length-1}, urlData['title'], urlData['url']); // push the History state, and set it's id to point to our newly added array element
historyData.manualStateChange=true; // re-enable the manual state change
}
}
If I don't know up front what the URL will be after I fetch the data via ajax, my Ajax call, replaces the current state with the correct data, this way:
if ((dataArray['navDat']) && (historyData.status))
{
historyData.manualStateChange=false;
var State = History.getState();
History.replaceState(State.data, dataArray['navDat']['title'], dataArray['navDat']['url']);
historyData.manualStateChange=true;
}
This works fine for the most part. If I navigate forward a few pages, and then go backwards, everything works greatly, if I then go forward once again(all by using the browsers back and forward button), it works greatly. There is only one exception: if I load the page, load a subpage, then try to click on the back button, this line never fires:
if (State.data.id=='-1') alert('History start');
It basicaly won't figure out that I arrived back at the front page, when I only navigate one page forward.
The other strange thing is the following(perhaps this is what's causing my original problem also): I tried fetching the savedStates of the History object, to see what is going on, and strangely, when I use the replaceState event, it adds a new state in savedStates. One of the objects that is added, is with the correct data id, the other one is with the previous data id.
What could be causing the problem, is there an error in my script somewhere? Or is this completly normal? (the part of adding multiple objects to History.savedStates after replaceState)
Thanks for the help in advance!
If I replace the url, or the title of the page with the first replaceState, the program realizes when I return to the front page, I dunno why, but till then this is the best solution I can figure.
I'm new to HTML and Javascript, and to learn it I am making an incremental game (similar to CookieClicker or CivClicker).
I'm trying to save and load progress, and I can save it just fine, but when I load it, it loads all the variables correctly, but when I click on a button to increment a variable, it does some weird stuff, it's hard to explain, I'll post the code so you can look at it some more.
JSFiddle Here
function loadProgress() {
if (typeof (Storage) !== "undefined") {
progress = localStorage.progress;
speed = localStorage.speed;
quality = localStorage.quality;
isDone = localStorage.isDone;
totalMoney = localStorage.totalMoney;
speedCost = localStorage.speedCost;
gamesSold = localStorage.gamesSold;
autoclick = localStorage.autoclick;
autoclickCost = localStorage.autoclickCost;
currentBugs = localStorage.currentBugs;
refreshDisplay();
} else {
console.log("LocalStore not appliable.")
}
}
Press 'Design' until you get to 100% then click 'Sell your game'. Then just press Save Progress then Load progress and click design and sell game again, you will see the numbers increase very oddly and that isn't expected at all.
'ShowMeTheMoney' will show you the variables in the console so you can verify that the variables were stored correctly.
I have no idea why this is happening, so if someone could help that would be awesome.
Local storage aka Web Storage, stores values as strings, so you need to convert/cast to numbers when you retrieve the values, otherwise the variables will remain as strings, and you'll see concatenation instead of the value being incremented. For example 1 + 1 becomes 11 not 2.
Updated working fiddle
There are many ways of converting to a number, one way is the + method:
progress = +localStorage.progress;
speed = +localStorage.speed;
quality = +localStorage.quality;
I've been playing around with http://almende.github.com/chap-links-library/timeline.html which allows the user to add/edit/delete events on the timeline. Closing or refreshing the browser resets it to the pre-loaded data source - JSON, table info or Google Spreadsheet. Nothing the user adds or changes is saved.
How do you make user changes persistent?
I've used HTML5 localStorage before for saving text, checkbox, and select box entries, etc. but with this Timeline the only entry is:
div id="mytimeline"
which has a script associated with it:
// Instantiate our timeline object.
timeline = new links.Timeline(document.getElementById('mytimeline'));
which is the reference to the JS that builds the timeline container.
Any ideas or examples or pointers?
Thanks.
Update:
Here is what I have so far:
//Check to see if localStorage is supported
var db = getLocalStorage() || alert("Local Storage Not supported in this browser. Try updating to the latest Firefox, Chrome or Safari browsers.");
function getLocalStorage() {
try {
if(window.localStorage ) return window.localStorage;
}
catch (e)
{
return undefined;
}
}
//Store Timeline Data to localStorage
function storeTimelineData(){
var data=timeline.getData();
localStorage.setItem('mytimeline', JSON.stringify(data));
var storedData=JSON.parse( localStorage.getItem('myTimeline') );
// clear storage
function clearLocal() {
clear: localStorage.clear();
return false;
}
I've also made these changes - body onload="storedData()" to try to load localStorage saved values and changed div id="mytimeline" onmouseup="storeTimelineData()" to store the values when changes are made to the timeline.
Changes to the Timeline are being saved in localStorage and I can see these changes in the console for Key/Values. When I refresh the browser though, these are not being loaded into mytimeline. What did I miss?
Thanks.
I've never seen plugin until your post but in the API docs are all sorts of methods. The most important one you would need to start would be getData().
Simplest storage scenario would be to set up a timed interval to get the data , convert it to JSON and store it. Alternative would be to update your stored data every time use interacts with events.
A basic storage update function would be along the lines of:
function storeTimelineData(){
var data=timeline.getData();
localStorage.setItem('myTimeline', JSON.stringify(data));
}
Then when page loads you would need to check if there is data in localStorage , convert it to a javascript object using :
var storedData= JSON.parse( localStorage.getItem('myTimeline') );
And use this data to initialize the plugin if the data exists.
I have really just given you a basic overview. There are numerous details you will have to sort out from here