how to persist an onclick function after page reload - javascript

I have an html here which executes a simple alarm based on the input time. I'm running nodejs webserver and this is my index.html
My problem is after clicking the "set alarm" button the function initiates but of course after reloading the page everything is gone. I've read about local storage but I don't know how to implement it in this scenario. I tried using garlic.js but only works on input forms like text field and checkboxes, not a button that executes a function.
var alarmSound = new Audio();
alarmSound.src = 'alarm.mp3';
var alarmTimer;
function setAlarm(button) {
var ms = document.getElementById('alarmTime').valueAsNumber;
if (isNaN(ms)) {
alert('Invalid Date');
return;
}
var alarm = new Date(ms);
var alarmTime = new Date(alarm.getUTCFullYear(), alarm.getUTCMonth(), alarm.getUTCDate(), alarm.getUTCHours(), alarm.getUTCMinutes(), alarm.getUTCSeconds());
var differenceInMs = alarmTime.getTime() - (new Date()).getTime();
if (differenceInMs < 0) {
alert('Specified time is already passed');
return;
}
alarmTimer = setTimeout(initAlarm, differenceInMs);
button.innerText = 'Cancel Alarm';
button.setAttribute('onclick', 'cancelAlarm(this);');
};
function cancelAlarm(button) {
clearTimeout(alarmTimer);
button.innerText = 'Set Alarm';
button.setAttribute('onclick', 'setAlarm(this);')
};
function initAlarm() {
alarmSound.play();
document.getElementById('alarmOptions').style.display = '';
};
function stopAlarm() {
alarmSound.pause();
alarmSound.currentTime = 0;
document.getElementById('alarmOptions').style.display = 'none';
cancelAlarm(document.getElementById('alarmButton'));
};
function snooze() {
stopAlarm();
alarmTimer = setTimeout(initAlarm, 6000); // 5 * 60 * 100
};
<input id="alarmTime" type="datetime-local">
<button onclick="alarmButton" id="setAlarm(this);">Set Alarm</button>
<div id="alarmOptions" style="display: none;">
<button onclick="snooze();">Snooze 5 minutes</button>
<button onclick="stopAlarm();">Stop Alarm</button>
</div>

Local storage would be a good way to keep track of the alarm time between sessions/page refreshes.
To save alarmTime to local storage, use:
window.localStorage.setItem('alarmTime', alarmTime)
Then when you want to use alarmTime, retrieve it from local storage with:
window.localStorage.getItem('alarmTime')
One thing to note is that local storage only stores strings, at least in the more popular browsers (see this post), so keep that in mind here.
See MDN docs on local storage for more: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
To have your function execute again after the page is refreshed, you can add a line like this:
document.onload = () => setAlarm(button);
Which will cause setAlarm to be called when the page finishes loading.
Edit
Here is a rough layout of how you can incorporate the above information into your code. I think it's actually better to store ms in local storage rather than alarmTime so that you can populate the input with ms from local storage when your document loads.
document.onload = function() {
var ms = window.localStorage.getItem('ms');
if (ms) {
populateTimeInput(ms);
var alarmButton = document.querySelector('#alarmButton');
setAlarm(alarmButton);
}
}
function populateTimeInput(newTime) {
var timeInput = document.querySelector('#alarmTime');
timeInput.value = newTime;
}
function setAlarm(button) {
var ms = document.getElementById('alarmTime').valueAsNumber;
if (isNaN(ms)) {
alert('Invalid Date');
return;
}
window.localStorage.setItem('ms', ms);
// then everything else is the same
}
function cancelAlarm(button) {
window.localStorage.clear();
// and everything else the same
}
Three main things this code adds:
When your page finishes loading, this code will check local storage for ms, if it finds a value for ms, it populates the alarmTime input with the value it's found and then calls setAlarm automatically.
When setAlarm is called, save ms to local storage (if ms has a valid value).
When cancelAlarm is called, clear local storage.
This is perhaps not the most elegant way to handle all of this, but I hope it at least gets you going in the right direction — keep iterating!

Try this, I am using setInterval instead of setTimer and I am storing the remaining time in local storage and decreasing it by 500 after every 0.5sec.
var alarmSound = new Audio();
alarmSound.src = 'alarm.mp3';
var alarmTimer;
function setAlarm(button) {
var ms = document.getElementById('alarmTime').valueAsNumber;
if (isNaN(ms)) {
alert('Invalid Date');
return;
}
var alarm = new Date(ms);
var alarmTime = new Date(alarm.getUTCFullYear(), alarm.getUTCMonth(), alarm.getUTCDate(), alarm.getUTCHours(), alarm.getUTCMinutes(), alarm.getUTCSeconds());
var differenceInMs = alarmTime.getTime() - (new Date()).getTime();
if (differenceInMs < 0) {
alert('Specified time is already passed');
return;
}
startTimer(differenceInMs)
button.innerText = 'Cancel Alarm';
button.setAttribute('onclick', 'cancelAlarm(this);');
};
function startTimer(time){
localStorage.setItem("timeLeft",time)
alarmTimer = setInterval(initAlarm, 500);
}
function cancelAlarm(button) {
clearInterval(alarmTimer);
button.innerText = 'Set Alarm';
button.setAttribute('onclick', 'setAlarm(this);')
};
function initAlarm() {
var timeLeft = parseInt(localStorage.getItem("timeLeft"))-500;
if(timeLeft <= 0){
alarmSound.play();
document.getElementById('alarmOptions').style.display = '';
} else {
localStorage.setItem("timeLeft",timeLeft)
}
};
function stopAlarm() {
alarmSound.pause();
alarmSound.currentTime = 0;
document.getElementById('alarmOptions').style.display = 'none';
cancelAlarm(document.getElementById('alarmButton'));
};
function snooze() {
stopAlarm();
alarmTimer = startTimer(6000); // 5 * 60 * 100
};
<input id="alarmTime" type="datetime-local">
<button onclick="alarmButton" id="setAlarm(this);">Set Alarm</button>
<div id="alarmOptions" style="display: none;">
<button onclick="snooze();">Snooze 5 minutes</button>
<button onclick="stopAlarm();">Stop Alarm</button>
</div>

Related

How to make a toggle variable persist?

I'm working on a quiz page where I have a timer that I would like to be able to toggle on or off so it doesn't distract the user, and save the setting after submitting an answer. The timer function works, and calls on localStorage.getItem(). But when I try the below with a boolean to see if the showHideTimer() button is clicked, the timer always shows up when the next question appears. The console always logs true when the page loads a new question.
<script>
var clickCookie = 'clicked';
var clicked = localStorage.getItem(clickCookie);
console.log(clicked);
function showHideTimer(){
if(clicked==true){
document.getElementById("testHeaderRight").style.color = "black";
clicked=false;
localStorage.setItem(clickCookie, clicked);
console.log(clicked);
return clicked;
}
else{
document.getElementById("testHeaderRight").style.color = "white";
clicked=true;
localStorage.setItem(clickCookie, clicked);
console.log(clicked);
return clicked;
}
};
window.onload = function(){
if(clicked===null){
localStorage.setItem(clickCookie, false);
} else {
showHideTimer(clickCookie);
}
};
</script>
<body>
<button id="showHideTimer" onclick="showHideTimer()">Toggle Timer</button>
<div id="testHeaderRight">
Time Remaining :
<span id="time"></span>
</div>
<script>
var cookieName = 'startTimer';
var savedSeconds = localStorage.getItem(cookieName);
function startTimer(duration, display) {
var timer = duration, seconds;
setInterval(function () {
seconds = parseInt(timer);
display.textContent = secondsToHms(seconds);
var runningTime = (parseInt(seconds));
localStorage.setItem(cookieName, runningTime);
}, 1000);
}
window.onload = function () {
var startTime = 7200,
display = document.querySelector('#time');
if (savedSeconds === null){
startTimer(startTime, display);
} else {
startTimer(savedSeconds, display);
}
};
</script>
</body>
I've tried moving the window.onload call into the same function as the timer since that is functioning properly, but seems to make no difference. I've tried switching the clicked=true/false; variables around to make sure I'm not confusing myself with booleans, and they switch freely in the console when clicking on the button. I've tried changing the return value of the showHideTimer() function to be localStorage.setItem(clickCookie, clicked);
When you get the item out of storage it's a string, "true", not a boolean.
So your if(clicked==true) comparison never passes and you end up on the "false" path every time.

JavaScript Timeout reset mechanism

What I want:
There are two pictures that are being switched/swapped every three seconds.
I want to make it so that when the button is clicked, the picture switches and the auto-swap resets. So if the button is clicked, the image swaps and three seconds later, it will auto-swap, until the button is clicked again in which the cycle will repeat.
What I have right now
Currently, the problem is that: when the button is clicked, it messes up the timing of the auto-switches.
Edit:
Please don't create a new code base. Just modify mines. The code doesn't have to be an expert super concise level. I'm only three weeks into JavaScript (and it's my first programming language). I have to explain to classmates and it wouldn't be nice the code had elements I don't understand. So sorry for the inconvenience.
Right now I just need the button to correctly stop and restart the time.
<html>
<head>
<script>
let reset = setTimeout(change, 3000);
function change() {
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
setTimeout(change, 3000);
}
function fastChange() {
clearTimeout(reset);
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
}
</script>
</head>
<body>
<input type="button" onclick="fastChange();">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350" id="picture">
</body>
</html>
The reason why your timer resets is because you are not clearing the timeout.
you need to make a reference to the timeout and then use clearTimeout() on it whne you make the fast change. I don't think it is possible or wise to do that inline the way you have it so you code needs to be refactored
let imgSrc1 = 'https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350'
let imgSrc2 = 'https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350'
let imgElement = document.getElementById('picture');
let timeout;
function change() {
if(imgElement.src === imgSrc1) {
imgElement.src = imgSrc2;
} else {
imgElement.src = imgSrc1;
  }
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(change, 3000);
}
You don't even need the second function fastChange. Now you can sent the onClick listener to change() like this
document.getElementById('whatever you want to click').onCLick = change;
Setting and clearing timeouts in multiple places will work, but I prefer using a "main loop" and a variable to count frames.
Here's an example that uses setInterval and resets a timer variable when the button was clicked:
const url1 = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
const url2 = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
function change() {
picture.src = picture.src == url1 ? url2 : url1;
}
var timer = 0;
setInterval(function() {
timer++;
time.textContent = timer;
if (timer === 30) fastChange();
}, 100);
function fastChange() {
change();
timer = 0;
}
picture.src = url1;
swap.onclick = fastChange;
#picture {
height: 70vh
}
<button id="swap">SWAP</button> <span id="time"></span><br>
<img id="picture">
You can do this by calling setTimeout and updating the index as necessary. Just be sure to store the most recent timeout id so that it can be cancelled on reset using clearTimeout.
// store the reference to the <img> that contains the picture
const pic = document.getElementById('picture')
// store a list (array) of the two picture urls
const sources = [
'https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350',
'https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350'
]
// used to store a reference to the interval timer you created.
var lastTimer
// a starting index of the list (i.e. which image we are up to right now)
var index = 1
// this functions swaps the image and sets a timer
function startRotation() {
// update the index to the next one (goes 0-1-0-1->etc)
index = 1 - index
// sets the .src of the image element
pic.src = sources[index]
// starts a 3 second timer to call this same function again
// but also stores a reference to the timer so that it can be cancelled
lastTimer = setTimeout(startRotation, 3000)
}
// this functions resets the timer and restarts the process
function reset() {
// stop the current timer if there is one
if(lastTimer){
clearTimeout(lastTimer)
}
// restart the process
startRotation()
}
// start the swapping process on start
startRotation()
<input type="button" onclick="reset();">
<img id="picture">
NOT HOW YOU CLEARTIMEOUT:
<html>
<head>
<script>
var i;
function change() {
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
i = setTimeout(change, 3000);
}
function fastChange() {
clearTimeout(i);
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
i = setTimeout(change, 3000);
}
</script>
</head>
<body onload="setTimeout(change, 3000)">
<input type="button" onclick="fastChange();">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350" id="picture">
</body>
</html>

how to clear interval of timer based on the row where button was clicked

I have basic understanding of javascript and jquery, but so far all i have done is client side validation and occasional ajax call to servlet. I need to display multiple countup timers(dynamically generated).
My page will have many timers(each with their own start/pause/resume/stop buttons). I am able to start the timers individually, but unable to pause them individually.
Referred this link from stackoverflow.(http://jsfiddle.net/6nv3qy88/)
I created another setting "pause:null" in the above plugin.
(function($) {
$.fn.upCount = function(options, callback) {
var settings = $.extend({
startTime: null,
resume: null,
pause: false
}, options);
var container = this;
globalContainer = container.parent().html();
var currentDate = function() {
// get client's current date
var date = new Date();
return date;
};
if(settings.startTime){
resumeTimer(new Date(settings.startTime));
}
var original_date = currentDate();
var paus = settings.pause;
if(paus){
alert("In settings.pause" + paus);
var target_date = new Date('12/31/2014 12:00:00');
paus = true;
}else{
var target_date = new Date('12/08/2015 14:55:00'); // Count up to this date
}
// Given a start time, lets set the timer
function resumeTimer(startTime){
alert('Resume Timer Needs to Start From StartTime ' +startTime)
}
// Start the counter
function countUp() {
// Set our current date
var current_date = currentDate();
//alert("In countUp paus--" + paus);
// difference of dates
var difference = current_date - new Date(settings.startTime);
if (current_date >= target_date) {
// stop timer
alert("In stop timer --" + target_date);
clearInterval(interval);
interval = 0;
if (callback && typeof callback === 'function') callback();
return;
}
//Code for Counting timer
};
interval = setInterval(countUp, 1000);
};
})(jQuery);
I am able to start the timers individually independent of each other based on rowIndex and start button id.
My code for starting timer:
function startTimer(id, rowIndex){
var startTimeId = 'id="list:'+rowIndex+':projectStartTime"';
var y = $('['+startTimeId+']').text();
//alert("value of y##" + y);
if(y.length > 0){
//$('#'+id).upCount({startTime: '12/04/2015 07:00:00', resume: true});
$('#'+id).upCount({startTime: $('['+startTimeId+']').text()});
}
}
Above code helps me start multiple timers independently. But I am unable to pause the timers individually. If I click on any pause all timers stop. I use clearInterval(interval)
for pausing the timers.
pause function:
function pause(id, rowIndex){
alert("In Function" + id);
var timer = $('#'+id+' span').text();
$('#'+id).upCount({startTime: '12/04/2015 07:00:00',pause: true});
}
Help needed for:
I would like to know how to clear interval only for the row from which the button is clicked i.e. the timer should pause once pause button is clicked.
JSF commandButton code:
<p:commandButton id="startBtn" action="#{timeBB.addTask}" value="Start" style="align:center;" styleClass="button" onstart="startTimer(#{impl.timerId},#{rowIndex});">
<f:param name="currentRow" value="#{impl.timerId}"/>
</p:commandButton>
<p:commandButton id="pauseBtn" value="Pause" action="#{timeBB.pause}" style="align:center;" styleClass="buttonStyle" onstart="pause(#{impl.timerId},#{rowIndex});">
<f:param name="currentProjectRowIndex" value="#{impl.timerId}" />
</p:commandButton>
Can anyone point out what I am doing wrong here?

Countdown and local storage

I don't know very well JavaScript but i must use it in my project.
I need countdown timers which after refresh page don't stop, not cleared and shown all time.
After press button you are redirect to other page, countown start ant button have 'disable value. After countdown time, button automatically must have enable value.
Here is my project: http://licznikii.cba.pl/dopostu/
In my first version everything works well but not after refresh page. Countdowns are cleared.
In my second version I used LocalStorage and it works well to but not much that I won't. After refresh page countowns are hidden. After countdown time button not have automatically enable value but after refreshpage. After refresh page after countdown time everything are showed good.
Please Help
After modifying your second-version it works. I've tested it in all browsers. Sorry for not code-refactoring, but I think you cope with this now :)
<!-- -------------------------------------------------------- SECOND VERSION -->
<script>
$(document).ready(function(){
$('#defaultCountdown3').countdown({until: 0, onTick: highlightLast5});
var teraz = Date.now();
var zapisanyCzas = localStorage.getItem("defaultCountdown3");
if (zapisanyCzas !== null && teraz < +zapisanyCzas) {
var restTime = secDiff(teraz, +zapisanyCzas);
console.log(restTime);
$("#YourButton3").prop('disabled',true);
$('#defaultCountdown3').removeClass('highlight').countdown('option', {until: Math.round(restTime), onExpiry: countdownFinished});
} else {
localStorage.removeItem("defaultCountdown3");
}
function highlightLast5(periods) {
if ($.countdown.periodsToSeconds(periods) === 5) {
$(this).addClass('highlight');
}
}
$('#YourButton3').click(function() {
localStorage.setItem("defaultCountdown3", Date.now() + 60 * 1000);
$('#defaultCountdown3').removeClass('highlight').countdown('option', {until: 60, onExpiry: countdownFinished});
$("#YourButton3").prop('disabled',true)
});
function countdownFinished(){
// Finished - disable your button
localStorage.removeItem("defaultCountdown3");
$("#YourButton3").prop('disabled',false)
}
function secDiff(start, end){
var diff = Math.abs(start-end);
return (diff/1000);
}
});
</script>
<script>
$(document).ready(function(){
$('#defaultCountdown4').countdown({until: 0, onTick: highlightLast5});
var teraz = Date.now();
var zapisanyCzas = localStorage.getItem("defaultCountdown4");
if (zapisanyCzas !== null && teraz < +zapisanyCzas) {
var restTime = secDiff(teraz, +zapisanyCzas);
console.log(restTime);
$("#YourButton4").prop('disabled',true);
$('#defaultCountdown4').removeClass('highlight').countdown('option', {until: Math.round(restTime), onExpiry: countdownFinished});
} else {
localStorage.removeItem("defaultCountdown4");
}
function highlightLast5(periods) {
if ($.countdown.periodsToSeconds(periods) === 5) {
$(this).addClass('highlight');
}
}
$('#YourButton4').click(function() {
localStorage.setItem("defaultCountdown4", Date.now() + 120 * 1000);
$('#defaultCountdown4').removeClass('highlight').countdown('option', {until: 120, onExpiry: countdownFinished});
$("#YourButton4").prop('disabled',true)
});
function countdownFinished(){
// Finished - disable your button
localStorage.removeItem("defaultCountdown4");
$("#YourButton4").prop('disabled',false)
}
function secDiff(start, end){
var diff = Math.abs(start-end);
return (diff/1000);
}
});
</script>

Hide download link for 10 seconds? js

hey, how can I have my download link hidden, and make a count down type thing. Maybe have it count down from 10 and once it's done that have the download link appear, it would be best to do it in js right?
does anyone know how to do this? :D
Thanks
Complete example:
<span id="countdown"></span>
<a id="download_link" href="download.zip" style="display:none;">Download</a>
<noscript>JavaScript needs to be enabled in order to be able to download.</noscript>
<script type="application/javascript">
(function(){
var message = "%d seconds before download link appears";
// seconds before download link becomes visible
var count = 10;
var countdown_element = document.getElementById("countdown");
var download_link = document.getElementById("download_link");
var timer = setInterval(function(){
// if countdown equals 0, the next condition will evaluate to false and the else-construct will be executed
if (count) {
// display text
countdown_element.innerHTML = "You have to wait %d seconds.".replace("%d", count);
// decrease counter
count--;
} else {
// stop timer
clearInterval(timer);
// hide countdown
countdown_element.style.display = "none";
// show download link
download_link.style.display = "";
}
}, 1000);
})();
</script>
You can use setInterval for this. setInterval behaves like a timer, where you can run a certain function periodically. Something like this should do the work(untested):
$(".link").hide();
var iteration = 0;
var timer = setInterval(function() {
if(iteration++ >= 10) {
clearTimeout(timer);
$(".link").show();
$(".counter").hide();
}
$(".counter").text(10 - iteration);
}, 1000);
This will initially hide the download link and run a function every second which counts down from 10. When we reaced ten, we hide the counter and show the link. ClearTimeout is used so that we don't count after we reached ten. Easy as dell.
Edit: As mentioned in the comments, this function is using jQuery to find the elements.
Take a look at the setTimeout function. You can do something like:
function displayLink() {
document.getElementById('link_id').style.display = 'block';
}
setTimeout(displayLink, 10000);
var WAIT_FOR_SECONDS = 10;
var DOWNLOAD_BUTTON_ID = "btnDownload";
if (document.body.addEventListener) {
document.body.addEventListener("load", displayDownloadButton, false);
} else {
document.body.onload = displayDownloadButton;
}
function displayDownloadButton(event) {
setTimeout(function() {
_e(DOWNLOAD_BUTTON_ID).style.display = "";
}, WAIT_FOR_SECONDS*1000);
}
function _e(id) {
return document.getElementById(id);
}

Categories

Resources