I would like to have a countdown timer always show a countdown for every new user. Basically, if I close the webpage, and reopen it, the timer should still be running. I'm thinking of using the JS variable code functions to define a new client's timezone together with an if statement comment and make it a repeat loop?
Basically, I would want to run a timer on the server side, not the client side.
Has anyone done this before?
Sounds something that you could try to solve with browsers localStorage. If your only requirement is to keep saved time available after you close tab/browser and come back to your page, this is a good fit for you.
Here's a small Codesandbox example code of how to conditionally check and save to localStorage and then start counter based on that value.
https://codesandbox.io/s/4xw97q02m0
EDIT: same code pasted to a post
function setCurrentTime(){
let localStore = window.localStorage.getItem("myTime") // Check if already exists
if(localStore) return localStore
const time = Date.now(); // get current time stamp
window.localStorage.setItem("myTime", time) // Save to localStorage
return time
}
function startCount(){
const time = setCurrentTime()
const elem = document.getElementById("app")
setInterval(() => {
elem.innerHTML = `seconds since time saved:
${Math.floor((Date.now() - time) / 1000)}
`
}, 1000)
}
startCount()
<div id="app"></div>
Related
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!
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.
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);
}
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.
I have a React+Redux application, and I display the date in it using Moment.js. I want a function to run when the date changes.
Right now I have a function to check the date:
checkDate(local) {
if (local === null) {
localStorage.setItem('date', moment().format('MM-DD-YYYY'));
} else if (moment(local).isBefore(moment().format('MM-DD-YYYY'))) {
this.props.resetAll(); // This calls an action.
}
}
And if I call it manually, or refresh the page when the date changes, it works just fine. But, I want to be able to have my application run that this.props.resetAll() line on its own without my having to refresh the page. What would the best way be to go about it? Should it be something that happens on the Redux side of things in an action or reducer? Should I have checkDate() be called every X seconds or so somewhere in the component lifecycle (if so, where)?
Thanks in advance for any help!
I would set a timeout until 24:00 which then calls the update function:
moment() is defined as the current date/time, to get the difference to a specific time, you can use the .diff() function. So for example if you want the milliseconds till the start of the next day:
var msTillEndOfDay = moment().endOf('day').add(1, 'seconds').diff(moment(), 'milliseconds');
.endOf('day') would be 23:59:59 so you just add 1 seconds to have the next day.
You then simply set the Timeout with the specific update function or dispatch the right action:
setTimeout( () => {
this.props.dispatch({type: 'UPDATE_DATE'})
}, msTillEndOfDay);
I want to keep track of how many seconds a user spend on my project website on all of his pages and for doing this I want to use JavaScript session cookies.
This is because I will host it using Github Pages where I have no access to PHP and also because I want to try working with JS cookies (It's the first time I am doing this).
To count the seconds I am using the followings:
var time_spent = 0;
setInterval(function(){
++time_spent;
$('#counter_container span').html(time_spent);
}, 1000);
The above code works where the counter is but as expected is reseting every time I change the page.
I've tried using a js-cookie library (https://github.com/js-cookie/js-cookie) in the following manner:
Cookies.set('time_spent', time_spent);
var counted_time = Cookies.get('time_spent');
console.log(counted_time);
But the counted_time variable is always 'undefined' whatever I've tried.
I would really apreciate any guidance I can get in order to solve this little issue.
I wouldn't use a timer for this. Instead try setting a timestamp when the user enters the page, and then onbeforeunload get the duration and add it to the value stored in the cookie. Something like this:
var load = new Date();
window.onbeforeunload = function() {
var leave = new Date();
var duration = leave.getTime() - load.getTime() / 1000;
var counted_time = parseFloat(Cookies.get('time_spent')) || 0;
Cookies.set('time_spent', counted_time + duration);
}
Working example
EDIT: I think I should make things more obvious.
What I am trying to do is to make the function that displays the "time ago" from the submitted date of the post auto refresh every minute so that it stays relatively accurate even if the template is not re rendered.
I'd like to auto update my timeago value in my template but it is not working.
I've tried to set up my code with a reactive function, based on the answer to a similar question (https://stackoverflow.com/a/17933506)
Here's my code:
var timeAgoDep = new Deps.Dependency(); // !!!
var timeAgo;
var timeAgoInterval;
Template.postItem.created = function() {
function getTimeago() {
//var now = new Date();
timeAgo = moment(this.submitted).twitter();
timeAgoDep.changed(); // !!!
};
getTimeago(); /* Call it once so that we'll have an initial value */
timeAgoInterval = Meteor.setInterval(getTimeago, 5000);
};
Template.postItem.posted = function() {
timeAgoDep.depend(); // !!!
return timeAgo;
};
Template.postItem.destroyed = function() {
Meteor.clearInterval(timeAgoInterval);
};
I'm pretty sure that the problem comes from this.submitted because if I assign timeAgo = now for example, it will display the time and update like it's supposed to.
I also know that moment(this.submitted).twitter() works fine because when all I do is return it through a helper, it works.
A much better way to do this is to just embrace Meteor's reactivity and render time-dependent values reactively. In your case, the problem is that you are invalidating the dependency once every 5 seconds for each postItem rendered, which will quickly turn into a huge mess.
See https://github.com/mizzao/meteor-timesync for a package that provides reactive time variables on the client (and they are synced to server time too!) It's basically doing what you want, but in a cleaner way. (Disclaimer: I wrote this package.)
You can use moment in the same way to compute the actual string to display. For example, get rid of all the other stuff and just use
Template.postItem.posted = function() {
return moment(this.submitted).from(TimeSync.serverTime());
}
The moment().twitter() extension doesn't seem like a good choice because it only uses the current client time and doesn't allow you to pass in a specific (i.e. server-synced) time or reactive value.
I will try my best to explain my problem in a correct english.
I have a global countdown in ajax which display the timeleft (calculated with server time) with a setinterval.
The aim is to call a function only once when the timeleft reach some target.
$timeLeft = strtotime($wallet->date_upd)- time();
if ($timeLeft <= 3)
{
function() 'this function update or not $wallet->date_upd to add time'
}
As the ajax countdown is global, and due to transfer and rendering delays, the function can be called by several users.. Any ideas?
I asume that when the timleft is over and your script runs that you also update the date_upd to a new time?
In that case you can just do the update and check if there is an affected row.
If another script was faster than the WHERE in the query will not work anymore and the affected_rows will be 0.
$new_date_upd = date('Y-m-d H:i:s', strtotime('+2 hours'));
mysql_query("UPDATE wallet SET date_upd = '{$new_date_upd}' WHERE date_upd = '{$wallet->date_upd}'");
if (mysql_affected_rows() > 0) {
// this script is the only one doing this stuff
}
So that should be something working in MySQL.
If you're managing your own server and can install some stuff then I advise you to checkout Redis.io which is a great tool for doing in memory stuff ( like an advanced memcache ) and it can also help you with doing 'locking' in a nice way