0

I'm writing a script that lets a user know how much time he spent on a page before refreshing it. To this purpose, I increment a time counter with a setInterval function, and store the data in the browser thanks to localStorage. Once the page is refreshed, I retrieve the data stored, and display them. Meanwhile, the time counter goes back to 0 and starts incrementing again.

Unfortunately, something is wrong with my script because localStorage doesn't store the updated time value (it's always -1). What's wrong with my script?

//TimeSpent = -1, so setInterval sets it to 0s instead of 1s when the page opens. 
var timeSpent = -1

//Update time every second
var timer = setInterval(()=>{
    timeSpent +=1;
    }, 1000);

//If first visit, ask to refresh. Else, display timeSpent on previous page by retrieving localStorage data.
function start(){
  if (localStorage.timeData){
  var timerJson = localStorage.getItem("timeData");
  var timerParsed = JSON.parse(timerJson);
  console.log(`You spent ${timerParsed.time} seconds on previous page`)
  }
  else{
  console.log("Reload the page and see how much time you spent reading this.")
  }
}

//Trig function when page opens.
window.onload = start();

//Before page reloads, store timeSpent in localStorage as a Json file.
   var timeData = {
   time: timeSpent, 
   }

  function storeData (timeData){
  var timerJson = JSON.stringify(timeData) 
  localStorage.setItem("timeData", timerJson);
  }

window.onbeforeunload = storeData (timeData) 

Thanks!

DoneDeal
  • 149
  • 2
  • 3
  • 11
  • 2
    On SO, your whole question (including any necessary code) has to be **in** your question, not just linked. Two reasons: People shouldn't have to go off-site to help you; and links rot, making the question and its answers useless to people in the future. That's why SO wouldn't let you actually link to CodePen. Rather than ignoring and working around the msg you got, put a [mcve] **in** the question. More: [*How do I ask a good question?*](/help/how-to-ask) and [*Something in my web site or project doesn't work. Can I just paste a link to it?*](https://meta.stackoverflow.com/questions/254428/) – T.J. Crowder Dec 29 '18 at 11:27
  • 2
    All my apologies, I though it would be easier to directly access the script on Codepen. The code is now displayed. – DoneDeal Dec 29 '18 at 11:41

3 Answers3

1

window.onbeforeunload must have a value of type function but in your code it is undefined. Hence you should change it to this:

window.onbeforeunload = function storeData (){
  var timerJson = JSON.stringify(timeData) 
  localStorage.setItem("timeData", timerJson);
  }

I've also removed the parameter from the function, making it a closure.

UPD. As Jonas Wilms noted, you should do the same wilth onload event and start function.

ALSO. In order to always have the actual (fresh) value of timeSpent, you should do this:

const state = {timeSpent: -1}

And everywhere replace timeSpent with state.timeSpent.

This way the closures will have a link to state object, instead of just taking the initial value of a primitive timeSpent.

Nurbol Alpysbayev
  • 19,522
  • 3
  • 54
  • 89
  • 1
    ... same with `start` – Jonas Wilms Dec 29 '18 at 11:53
  • Thanks for your help. However, the issue remains the same: localStorage only stores the starting `timeSpent` value `-1`. I've done a few tests with `setInterval`and `console.log`, it seems timeData's time key value (which is supposed to be timeSpent) is never updated. Yet, timeSpent is updated. It is really weird. – DoneDeal Dec 29 '18 at 12:00
  • @DoneDeal Please check the addition. – Nurbol Alpysbayev Dec 29 '18 at 12:06
  • @DoneDeal Sorry bro, there are too many problems in your code! You should thoroughly debug it and understand it yourself. I am having hard time to do it. Then, when you can't understand a specific, small place in your code, feel free to ask on SO, you'll get *many* answers this way. – Nurbol Alpysbayev Dec 29 '18 at 12:09
  • The idea of updating timeSpent by using it as an "state" object property - like in React - is smart. However, localStorage keeps storing `-1`. – DoneDeal Dec 29 '18 at 12:12
  • 1
    @DoneDeal There are too many things you'll have to change, I've no enough time for that, sorry. For example you should store in localstorage the object `state` and `timeData` is redundant here, etc. You should also learn about mutable (objects) and immutable (primitives) data in JS. – Nurbol Alpysbayev Dec 29 '18 at 12:16
0

This code works well for me:

let timeData = {
time: -1
}
timeData.time = setInterval(()=>{
    timeData.time += 1 
    console.log(timeData.time)
  }, 1000);
function start(){
  if (localStorage.timeData){
  var timerJson = localStorage.getItem("timeData");
  var timerParsed = JSON.parse(timerJson);
  console.log(`You spent ${timerParsed.time} seconds on previous page`)
  }
  else{
  console.log("Reload the page and see how much time you spent reading this.")
  }
}
window.onload = start();
window.onbeforeunload = function () {
  var timerJson = JSON.stringify(timeData) 
  localStorage.setItem("timeData", timerJson);
}
  • For a useful answer this reaction needs to be extended. Explain why this is an answer to the question. – Jeroen Heier Dec 29 '18 at 14:26
  • Yes, it works because you have modified timeData.time in the setInterval, while I used to modify a mere variable called timeSpent. I eventually obtained the same result, came back here to share it, and I just see your code haha! Well done. Also, you may delete function start() and simply write window.onload = function(){if blabla} – DoneDeal Dec 29 '18 at 14:55
0

I assume you testing this locally. Since local-storage is stored like a cookie domain based (and you dont have a domain when you test your script locally) the data is simply not saved.

In HTML5, is the localStorage object isolated per page/domain?

Edit: By local i mean a simple Html-File without using a webserver.

SirPilan
  • 4,649
  • 2
  • 13
  • 26