Pressing the button it generates a countdown to request a new password. After this gets to 0 you get a new link to request it. The issue is when during existing countdown I am pressing the button. It seems somehow I am running in the same time 2 counters and not sure how to fix this. Can you please help:
https://codepen.io/acode2/pen/poaWpmv
<form class="olr-form">
<input
data-sc-field-name="secondsToNextOTP"
value="30"
>
<p class="passcodeReRequest">Don't have a valid passcode?</p>
<button type="submit" class="button__next button__test">Test</button>
</form>
const opt = () => {
$('.test').remove();
$('.otpLinkAvailable').remove();
let gCountdownTimerHandle = 0;
let gDateTimeForNextOTP = null;
// getting the seconds to cowntdown
let secsToNextOTP = $("[data-sc-field-name=secondsToNextOTP]").val() * 1;
if (secsToNextOTP) {
let passCodeResendlink = $(".passcodeReRequest");
Date.prototype.addSecs = function (s) {
this.setTime(this.getTime() + (s * 1000));
return this;
}
// this function is polled and updates the status of time until a new OTP request can be made by the user
function showTimeToWaitForOTP() {
try {
const linkAvailableInTag = $(".otpLinkAvailable");
const secondsToNextOTP = Math.round((gDateTimeForNextOTP - new Date()) / 1000);
if (linkAvailableInTag && linkAvailableInTag.length > 0) {
if (secondsToNextOTP > 0) {
linkAvailableInTag.text(" you can re-request a passcode in " + secondsToNextOTP + " seconds");
} else {
clearInterval(gCountdownTimerHandle);
linkAvailableInTag.text("");
linkAvailableInTag.after(" <a class='test' href='javascript:document.location = document.location+\"&resendOTP=true\"'>Send a new passcode</a>");
}
}
else {
clearInterval(gCountdownTimerHandle);
}
} catch { // any errors, cancel the timeout
clearInterval(gCountdownTimerHandle);
}
}
// // check if we need to trigger the OTP countdown timer
if (passCodeResendlink && passCodeResendlink.length > 0 && secsToNextOTP >= 0) {
gDateTimeForNextOTP = new Date().addSecs(secsToNextOTP);
passCodeResendlink.append("<span class='otpLinkAvailable'></span>");
gCountdownTimerHandle = setInterval(showTimeToWaitForOTP, 500); // issue countdown
}
}
}
$(".button__test").click(function(e) {
e.preventDefault();
opt();
});
gCountdownTimerHandle should be outside the opt() function. Each time you are clicking the button - you are resetting gCountdownTimerHandle to 0 at line number 3 inside opt() function. That is why your clearInterval is not capturing the actual id of setInterval and hence it is not getting cleared.
Hope it helps!
You just need a check to see if the countdown is already running and not start the countdown if it is - right now it just starts a new interval, that runs side-by-side with the old one(s) for every time you click it.
Related
I can't for the life of my figure out how to get this to work bug free.
The button in the code below needs to do three things.
Start a countdown when clicked (works)
End the countdown automatically, and reset itself when it reaches 0(works)
Reset itself prematurely if its clicked in the middle of a countdown(works, sort of)
Bug: when clicked repeatedly it starts multiple countdowns, and more or less breaks. It needs to either reset itself or start a countdown if clicked repeatedly. There should never be more than one countdown.
It works fines as long as people press the button, wait a second, and then press it again to stop it.
The bug I'm running into is if someone spam clicks it, it starts multiple countdowns and generally just breaks the button. I've tried a lot of different methods to fix it, and this is the closest I've gotten.
var i = 29;
let running=false;
$("#startButton").click(function () {
if(running==false){
var countdown = setInterval(function () {
$("#startButton").text("Reset Timer");
running=true;
$("#stopWatch").html(i);
i--;
if (i <0)
{
$("#startButton").text("Start Timer");
running=false;
clearInterval(countdown);
i = 29;
$("#stopWatch").html(i);
}
$("#startButton").click(function () {
$("#startButton").text("Start Timer");
running=false;
clearInterval(countdown);
i = 29;
$("#stopWatch").html(i+1);
});
}, 1000);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="stopWatch">30</div>
<button id="startButton">Start Timer</button>
Welcome to Stack Overflow #William!
I'm not sure what this means: Reset itself prematurely if its clicked in the middle of a countdown(works, sort of). But I managed to fix your bug on spamming button click and for item 3, i just do reset the countdown from initial state. See snippets below:
// Get attribute value from div `stopwatch`. This is for resetting from default value.
var initial = $('#stopWatch').attr("value");
// Assigned initial value to var i.
var i = initial;
$("#stopWatch").html(i);
let running = false;
// Created a separate function to call from button click.
function run(timer = true) {
if (timer) {
running = true;
$("#startButton").text("Reset Timer");
$("#stopWatch").html(i);
var countdown = setInterval(function () {
i--;
$("#stopWatch").html(i);
if (i <= 0) {
running = false;
$("#startButton").text("Start Timer");
clearInterval(countdown);
i = initial;
$("#stopWatch").html(i);
}
}, 1000);
} else {
running = false;
clearInterval(countdown);
i = 0;
$("#startButton").text("Start Timer");
}
}
$("#startButton").click(function () {
// Check if its not running and var i is not 0
if(!running && i != 0) {
run();
// Check if its running and var i is not 0 to ensure that if someone spam the button it just reset the countdown.
} else if (running && i != 0) {
// Will return the else{} on function run().
run(false);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="stopWatch" value="30"></div>
<button id="startButton">Start Timer</button>
Added some comments on the snippet. Feel free to ask if you have any questions.
I'm trying the make a chrome extension in javascript. So far, my popup.js looks like this:
let bg;
let clock;
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('button1').addEventListener('click', butClicked);
bg = chrome.extension.getBackgroundPage();
//clock = document.getElementById("label1");
});
let timeStamp;
let isClockRunning = false;
function butClicked() {
let test = bg.getURL();
document.getElementById('test').innerHTML = test;
timeStamp = new Date();
isClockRunning = !isClockRunning;
runCheckTimer();
}
function runCheckTimer() {
var handle;
if(isClockRunning == true) {
handle = setInterval(updateClock, 1000);
}
else if(isClockRunning == false) {
clearInterval(handle);
handle = 0;
}
}
function updateClock() {
let seconds = bg.returnTimeSince(timeStamp);
document.getElementById("label1").innerHTML = "Seconds: " + seconds;
}
The program works just fine when I click the button once; it starts the timer. But when I click the button the second time, timeStamp gets set to 0, but the updateClock keeps running at the same interval; the interval doesn't get cleared even though I'm toggling the isClockRunning boolean. It's almost as if javascript is forgetting to run the else if part in runCheckTimer(). How can I fix this?
EDIT: On a sidenote, am I doing the timer thing the right way? Or is there a better way to do it? I basically want a timer to keep ticking every second since you've pressed the button, and then when you click it again it'll stop and reset to 0.
You have scoped handle to runCheckTimer. When runCheckTimer starts, it will create a new handle every time.
Move handle outside of the function.
var handle;
function runCheckTimer() {
if(isClockRunning == true) {
handle = setInterval(updateClock, 1000);
}
else if(isClockRunning == false) {
clearInterval(handle);
handle = 0;
}
}
I am using this function to auto-click a button after 15 seconds. The problem is the user doesn't leave the page after the option is run and it may be re-run again on the same page but the timer continues. In fact, the timer continues even if I do the action myself.
<script type="text/javascript">
time = 15;
interval = setInterval(function() {
time--;
document.getElementById('Label1').innerHTML = "You must choose in " + time + " seconds"
if (time == 0) {
// stop timer
clearInterval(interval);
// click
document.getElementById('thebutton').click();
}
}, 1000)
</script>
So this script should run the timer and "press" the "thebutton" in fifteen seconds and then the timer should stop counting and reset until run again. If the button is pressed manually before 15 seconds it should still reset.
<input type='submit' id='thebutton' value='Done'></input>
Hopefully this is clear. I am still new and learning.
Set a base time and then reset it to that.
<script type="text/javascript">
time = 15;
baseTime = 15;
interval = setInterval(function() {
time--;
document.getElementById('Label1').innerHTML = "You must choose in " + time + " seconds"
if (time == 0) {
// stop timer
clearInterval(interval);
// click
document.getElementById('thebutton').click();
time = baseTime;
return false;
}
}, 1000)
</script>
I had a look at the code and the most critical thing that I think you should look at is that the button has no "onclick" function.
This means that clicking the button does nothing because you have not put a function there that does something when you click it.
I wrote some code that I hope helps:
let time = 15;
const label = document.getElementById("Label1");
const button = document.getElementById("thebutton");
const getText = () => `You must choose in ${time} seconds`;
const interval = setInterval(() => {
time--;
label.innerHTML = getText();
if (time === 0) {
// stop timer
clearInterval(interval);
// click
button.click();
}
}, 1000);
const stopTime = () => {
clearInterval(interval);
time = 15;
label.innerHTML = getText();
};
And in your html something like this:
<input type='submit' id='thebutton' value='Done' onclick="stopTime()" />
Finally I made a small video where I walk through the code, it could be useful as well: https://youtu.be/ZYS9AcxO3d4
Have a great day!
If you only want the button to be clicked once after 15 seconds then you should use the setTimeout() function instead of setInterval().
Then if you do not want the auto-click to happen if the user clicks the button then you would need to add an onClick handler to your button that calls clearTimeout().
I assume you want the label updated as the seconds count down? And it's unclear how the timer is started. Check the below code and see if it does what you expect.
var time, interval;
function stopTimer() {
if (interval) {
clearInterval(interval);
interval = null;
}
time = 15;
}
function timerAction() {
$('#lblStatus').text("You must choose in " + time + " seconds");
if (time-- <= 0) {
stopTimer();
console.log("done!");
$("#btnStop").click();
}
}
function startTimer() {
stopTimer();
timerAction();
interval = setInterval(timerAction, 1000);
}
$("#btnStart").click(function() {
startTimer();
});
$("#btnStop").click(function() {
stopTimer();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id=lblStatus></span>
<button id='btnStart'>Reset / Start</button>
<button id='btnStop'>Stop</button>
If you want to run only once, you can use setTimeout function
setTimeout(your code, 15000);
I have a timer ticker on Layout(MVC4.0) (With 1 Second Interval) page and it works fine when only 1 page of website(In one tab) is opened
var timeOutMinutes = 10;
var timeOutSeconds = timeOutMinutes * 60;
localStorage.setItem("SessionCounter", timeOutSeconds);
var popUpShown = false;
var logOutCalled = false;
$(document).ready(function () {
setInterval(TimerDecrement, 1000);
});
function TimerDecrement() {
if (timeOutSeconds > 0) {
if (parseInt(localStorage.getItem("SessionCounter"), 10) > 0) {
timeOutSeconds = parseInt(localStorage.getItem("SessionCounter"), 10);
}
timeOutSeconds--;
localStorage.setItem("SessionCounter", timeOutSeconds);
}
else {
if (!logOutCalled) {
logOutCalled = true;
LogOut();
}
else {
logOutCalled = true;
}
}
document.getElementById("seconds").innerHTML = timeOutSeconds;
document.getElementById("secondsIdle").innerHTML = timeOutSeconds;
if (timeOutSeconds < 500) {
//alert(history.length);
popUpShown = true;
$("#pnlPopup").dialog("open");
}
else {
if ($("#pnlPopup").dialog("isOpen")) {
popUpShown = false;
$("#pnlPopup").dialog("close");
}
}
}
But when I open multiple tabs of website timer jumps to decrease quickly.
How can I maintain the timer to decrement Uniformly even if website is opened in multiple tabs?
FIDDLE
The problem is that you are using the counter that is being decremented is common to all tabs, because it is kept in LocalStorage. So the solution really depends on what you intention is for the decrement counter.
If the intention is for each session (each tab) to have it's own separate counter, then you would be better served using a variable instead of LocalStorage -- or alternatively, use a unique session id for each counter in LocalStorage.
If the intention is to have all tabs share the same decrement counter, but for it to only be decremented once per second regardless of how many tabs are open, then perhaps you want to store the counter as well as the last decrement time.
EDIT: Here is a forked fiddle that might do what you need:
http://jsfiddle.net/y68m4zwr/8/
The gist of it is to add:
var lastUpdated = localStorage.getItem("SessionCounterUpdatedOn"),
now = new Date(), shouldCheck = false;
if (lastUpdated == null) {
localStorage.setItem("SessionCounterUpdatedOn", now);
} else if (now.getTime() - new Date(lastUpdated).getTime() >= 1000) {
// set this immediatedly so another tab checking while we are processing doesn't also process.
localStorage.setItem("SessionCounterUpdatedOn", now);
shouldCheck = true;
}
which checks for a last updated record for the counter and it if was updated less that second ago, it just updates the time left, otherwise performs the logic to decrement.
I'm having issues with my JavaScript code. I need to make code that does the following:
Click an image twice within 3 seconds to make the image disappear
Click it once to reappear
I've got it close to working...I'm just having issues with the date. I don't know how to keep the date from the first click. My code right now is just creating a new start date each click which is what I don't want.
Code thus far:
var imgNext = -1;
var start = new Date ( );
function disappear ()
{
var end = new Date ();
imgNext++;
if (imgNext == 2)
{
document.getElementById("myPicture").style.visibility="visible";
imgNext = -1;
}
if (imgNext == 1 && (end-start <3000))
{
document.getElementById("myPicture").style.visibility="hidden";
}
start = new Date ();
}
In the code the image changes even if the clicks are over 3 seconds apart because I'm creating a new START date every time the function is triggered. How do I resolve this?
Here is answer, with a working example: http://jsfiddle.net/yS5bs/2/
document.getElementById("disappear").onclick = function() {
var lastClick = this.attributes["click-time"],
click = new Date().getTime(),
timeout = parseInt(this.attributes["data-timeout"].value);
if(lastClick && (click - lastClick) < timeout && this.style.opacity == 1) {
this.style.opacity = 0;
this.attributes["click-time"].value = null;
return;
}
else {
this.attributes["click-time"] = click;
}
if(this.style.opacity == 0) {
this.style.opacity = 1;
this.attributes["click-time"] = null;
return;
}
};
basically I am assigning the onclick, and getting the click times, if within the set timeout (milliseconds) then it hides, otherwise, it shows again, as per spec