Click event doesn't produce any result - javascript

total noob here.
I'm writing a countdown timer that starts clicking on a "Start" button. No matter what I do, the timer always starts at the load of the page. And I mean that, when using live server on VS Code, every time I give the page a save, the timer starts.
No error appears in the console.
Probably I'm missing something really basilar, but I would love some help!
const btnStart = document.querySelector('.start');
const startTimer = function() {
let time = 10;
const timer = setInterval(function() {
const min = String(Math.trunc(time/60));
const sec = String(time%60);
time --;
input.value = `${min.length <= 9 ? min.padStart(2, 0) : min}:${sec.length <= 9 ?sec.padStart (2, 0) : sec}`;
if(time == 0){
setTimeout(function(){clearInterval(timer);
startTimer();}, 1000)
}
}, 1000)
}
btnStart.addEventListener('click', startTimer);
Html elements part:
<div class="main-container">
<input type="text" class="input" placeholder="MM:SS">
<div class="buttons-container">
Start
<button class="start">START</button>
Stop
Reset
</div>
</div>

You new edit to the question answered the question.
You're using VSCode LiveShare. When you save, it doesn't actually reload the page, it just loads the changes.
Since you're recursively calling startTimer(); (it's calling itself inside a setTimeout), it will never stop since it's not a full reload.
The easiest way to fix this is to reload your page manually (Ctrl+r or Command+r)
The harder way you could solve this is to store timer as a global variable, and on load, if timer exists, run clearInterval(timer)

Related

Automate click on a specific button on a website (that only pops up after 30 minutes)

I am trying to automate the clicking of a specific button on a website that only appears after 30 minutes of being logged in to the website. I have already looked in to how to do this but my primary issue is that the button does not have an ID.
The other issue is that this button only appears on the page after roughly 30 minutes, I am experimenting with tampermonkey as a way of running this script in my browser, however I am unsure on how to script it.
I found somebody else with a similar issue - this was their solution
For Each btn In document.getElementsByTagName("button")
If btn.innerText = "Refresh Token Now" Then
btn.Click()
End If
however this does not seem to be working for me, I have also tried the following
For Each btn In document.getElementsByClassName("wb-button wb-button--secondary wb-button--small")
If btn.innerText = "Refresh Token Now" Then
btn.Click();
End If
If somebody could please assist/point me in the right direction I would greatly appreciate it! :)
Use setTimeout and do something after 30 minute being load, 1 sec = 1000
const halfhour = 1000 * 60 * 30;
setTimeout(() => {
console.log('Run after 30 minute');
document.querySelector('.refresh').click();
}, halfhour);
document.querySelectorAll('button').forEach(b => {
if (b.innerText.indexOf('Refresh') != -1) {
b.addEventListener('click', function() {
console.log('Refresh has been click');
});
}
});
<div>
<button class="close">Close</button>
<button class="refresh">Refresh</button>
</div>

Stop setInterval() after a Specific Class Becomes Visible [duplicate]

This question already has answers here:
Stop setInterval call in JavaScript
(7 answers)
Closed 1 year ago.
Currently what I'm trying to do is have a function that looks for if the #discountbox element is visible then clone that #discountbox element and place it after .pricebox. Right now what's happening is that it is placing it after .pricebox and cloning it indefinitely.
How can I get the setInterval to stop after it finds #discountbox and clones it once?
HTML
<div id="discountbox" class="discount-summary">
You get $5 Off
</div>
<div id="modal">
<span class="price-box">
$20.50
</span>
</div>
Javascript
jQuery(document).ready(addDiscountsummary);
function addDiscountsummary () {
if($('#discountbox').is(':visible')){ //if the container is visible on the page
$("#discountbox").clone().insertAfter("#modal span.price-box"); //insert add to cart button after view contents buttons
} else {
setInterval(addDiscountsummary, 1000); //check every 1000 ms
}
}
you're looking for clearInterval() or as mentioned, a better solution would be to use setTimeout and clearTimeout instead
jQuery(document).ready(addDiscountsummary);
function addDiscountsummary () {
if($('#discountbox').is(':visible')){ //if the container is visible on the page
$("#discountbox").clone().insertAfter("#modal span.price-box");
clearTimeout(window.nextTimeout);
} else {
window.nextTimeout = setTimeout(addDiscountsummary, 1000); //check every 1000 ms
}
}
After it finds the button
Call clearInterval() method to stop your interval.
Try adding:
var testData = !!document.getElementById("discountbox");
if(testData=="true"){clearInterval(addDiscountsummary)}
else{};
To your code.
This checks if the element exists in the code and returns true if the element exists:
var testData = !!document.getElementById("discountbox");
This stops the loop testData returns true.
if(testData=="true"){clearInterval(addDiscountsummary)}
clearInterval(intervalID) will do the trick.
When your doc loads, set the interval. Make sure the ID (which I am calling interval) is first created outside of any function, available to the rest of the page. When your item is found, clearInterval(interval)
let interval
jQuery(document).ready(function() {
interval = setInterval(addDiscountsummary, 1000);
});
function addDiscountsummary() {
if ($('#discountbox').is(':visible')) {
$("#discountbox").clone().insertAfter("#modal span.price-box");
clearInterval(interval)
}

jquery - add multiple timers associated to HTML divs

I have the following DIV containing multiple cards elements:
Each of those cards have the following HTML structure:
<div class="user-w">
<div class="avatar with-status status-green">
<img alt="" src="img/avatar1.jpg">
</div>
<div class="user-info">
<div class="user-date">
12 min
</div>
<div class="user-name">
John Mayers
</div>
<div class="last-message">
What is going on, are we...
</div>
</div>
</div>
Those cards are loaded dynamically using ajax. What I need is to attach to each <div class="user-w"> a stopwatch so I can change for example background color when elapsed time is 4 min or make it hidden when elapsed time reaches 6 min.
I was thinking on using SetInterval multiple times for I think this is not possible.
Each DIV card element should be totally independant in terms of timing from the others.
Any clue on how to do it correctly?
When you build the card from the ajax object, set a data element to store the timestamp on the card. Use setInterval to trigger a function that loops through all of the cards and checks their timestamps against the current time and updates the date on the ui, changes the bgcolor, or removes the element altogether.
In general, shy away from the "attach everywhere" syndrome. Think in lists, and simple processors. You will thank yourself down the road, as will your users for more efficient code, and your maintenance programmer.
Accordingly, one thought process might be to setup an array of the elements in question, and use a single setInterval. Something like:
...
var cardList = [];
function processCards ( ) {
var i, cardEl, cardStartTime, now;
now = Date.now();
i = -1;
while ( ++i < cardList.length ) {
cardEl = cardList[ i ][ 0 ];
cardStartTime = cardList[ i ][ 1 ];
if ( cardStartTime + 6 min < now ) {
// do 6 minute thing
}
else if ( cardStartTime + 4 min < now ) {
// ...
}
}
}
$.get('/your/new/cards/call')
.done(function(...){
...
var now = Date.now();
for ( i in returnedCards ) {
cardElement = however_you_create_your_element;
attach cardElement to the DOM
// save reference to element and time created for later processing
cardList.push([cardElement, now]);
}
});
setInterval(processCards, 2*60*1000); // or whatever granularity you want.
One advantage of this approach over multiple setTimeout calls for each card is the simplicity of having a single processing function, rather than N copies lying around. It's easier to reason about and manage, and reduces the likelihood of errors if an element disappears before it's associated setTimeout function executes.
One way to do this is, after your AJAX call completes and the DOM has been updated, you can use jQuery to select your cards and for each card you can:
Get the time value and parse it to convert it to milliseconds - you can write a simple helper function for this or use something like momentjs based on how complex your requirement is
Use setTimeout with the parsed value and do any style updates/hiding as needed
Sample Code:
$('.user-w').each(function(i, el){
var $el = $(el);
var val = $el.find('div.user-date').html();
val = parseTime(val) // Assuming a function to parse time from string to milliseconds is there
setTimeout(function(){
// Do any updates here on $el (this user card)
}, val);
/*setTimeout(function(){
// Do something else when val ms is close to completion
// here on $el (this user card)
}, 0.9 * val);*/
})
If you want multiple things to happen (change bg color and then, later, hide element, for example) you can set multiple setTimeouts to happen with different time values derived from val
you want to add a function with setTimeout() for ajax success: parameter.
Ex(with jquery):-
$.ajax({
// your ajax process
success:function(){
setTimeout(function(){
$('.card-w').not('.anotherclassname').addClass('someclassname-'+i);
$('someclassname-'+i).addClass('.anotherclassname').fadeOut();
},6000);
}
})
The accepted answer can give you a lot of trouble if the ajax part
however_you_create_your_element;
attach cardElement to the DOM
Is replacing or adding elements. Ajax and processCards share cardlist and your ajax may remove items from DOM but leave them in cardlist.
You failed to mention if you replace the card list in your ajax or append new cards but the following solution would work either way.
To adjust to updating every minute and showing minutes you can change the following 2 lines:
const repeat = 1000;//repeat every second
const message = timePassed=>`${Math.round(timePassed/1000)} seconds`
to:
const repeat = 60000;//repeat every minute
const message = timePassed=>`${Math.round(timePassed/60000)} min`
(function(){//assuming cardContainer is available
const container = document.querySelector("#cardContainer");
const repeat = 1000;//repeat every second
const message = timePassed=>`${Math.round(timePassed/1000)} seconds`
const updateCards = function(){
Array.from(container.querySelectorAll(".user-w .user-date"))
.map(
(element)=>{
var started = element.getAttribute("x-started");
if(started===null){
started = Date.now()-
parseInt(element.innerText.trim().replace(/[^0-9]/g,""),10)*60000;
element.setAttribute("x-started",started);
}
return [
element,
Date.now()-parseInt(started,10)
];
}
).forEach(
([element,timePassed])=>
element.innerText = message(timePassed)
);
}
setInterval(updateCards,repeat);
}());
<div id="cardContainer">
<div class="user-w">
<div class="avatar with-status status-green">
<img alt="" src="img/avatar1.jpg">
</div>
<div class="user-info">
<div class="user-date">
12 min
</div>
<div class="user-name">
John Mayers
</div>
<div class="last-message">
What is going on, are we...
</div>
</div>
</div>
</div>

JavaScript button manipulation according to Time

I'm developing an app and what i want is when the user clicks any button, this button will be hidden and only shows up after 24 hours. Here's what i've done so far.
<div class="buttons">
<p><button onclick="hide();" type="button" name="button" id="button-he">Validar</button></p>
<p><button onclick="hide();" type="button" name="button" id="button-hse">Validar</button></p>
<p><button onclick="hide();" type="button" name="button" id="button-hre">Validar</button></p>
</div>
<script>
function intervalo(){
var but = document.getElementByTagName("button");
but.style.visibility='hidden';
}
</script>
One way to do this is creating a cookie on the button click, that will last for 24 hours, and then check if the button should be clickable. Limitations of this approach will be if the user clears the cookies, the button will then again become clickable.
Take a look at this w3schools example:
https://www.w3schools.com/js/tryit.asp?filename=tryjs_cookie_username
if you want to make sure that the user cant click the button again within 24 hours, you neeed to save this click event server side.
You can use setTimeout( YOUR_FUNCTION, TIME_TO_WAIT )
The setTimeout() method of the WindowOrWorkerGlobalScope mixin (and
successor to window.setTimeout) sets a timer which executes a function
or specified piece of code once after the timer expires.
The time, in milliseconds (thousandths of a second), the timer should
wait before the specified function or code is executed. If this
parameter is omitted, a value of 0 is used, meaning execute
"immediately"
The method takes time in milliseconds so, you need convert your time to milliseconds.
For 24hr you need to pass 24*60*60*1000 as a parameter.
SNIPPET
function hide(but) {
but.style.visibility = 'hidden';
setTimeout(function(btn) {
but.style.visibility = 'visible';
}.bind(this, but), 1000); // Show after 1 second.
// change 1000 to time you want 24*60*60*1000
}
<div class="buttons">
<p><button onclick="hide(this);" type="button" name="button" id="button-he">Validar</button></p>
<p><button onclick="hide(this);" type="button" name="button" id="button-hse">Validar</button></p>
<p><button onclick="hide(this);" type="button" name="button" id="button-hre">Validar</button></p>
</div>
The method will forget the timer if user refreshes the page.
If you want it to be persistent then you can store the timestamp when user clicks the button into localstorage and check if that time exceeded 24hrs on load of page.
Check this fiddle for Implementation
buttons = ["button-he", "button-hse", "button-hre"];
timer = 24 * 60 * 60 * 10000;
function init () {
buttons.forEach(function(val) {
var start = localStorage.getItem(val + '-timer');
var end = new Date().getTime();
var but = document.getElementById(val);
if (start && (end - start < timer)) {
but.style.visibility = 'hidden';
setTimeout(function(btn) {
but.style.visibility = 'visible';
}.bind(this, but), end-start);
}
})
}
init();
window.hide = function(but) {
localStorage.setItem(but.id + '-timer', new Date().getTime());
but.style.visibility = 'hidden';
setTimeout(function(btn) {
but.style.visibility = 'visible';
}.bind(this, but), 24 * 60 * 60 * 10000); // Show after 1 second.
// change 1000 to time you want 24*60*60*1000
}
Although, I suggest also check at the server side for this logic.
For that just pass the time-stamp when user clicks the button to the server and store it and check for time lapse.

How to create a persistent random countdown?

Basically, I need a counter that will go backwards from 100-1 slowly as users enter our website. We are only giving out "100" free coupon but want to give the appearance that users are quickly grabbing them in order to create urgency and have the prospect give us their email. I am using Unbounce to host our mobile landing page.
I came across a similar post to mine but the code generated numbers randomly in the millions. Here is the link for further help: https://stackoverflow.com/a/17964971
Quick example:
Be the first to know when we launch! We are only giving out 100 coupons and there are only (x) amount left.
Click here to get yours!
Count down at a random rate between 5 seconds and 1 second, save the current to the browser so if the user revisits the page the number doesn't reset
(Demo)
var i = 100;
var counter = document.getElementById('counter');
if(localStorage.counter) {
i = localStorage.counter;
}
function countDown() {
if(i > 0) {
i--;
console.log(i);
counter.innerText = i;
localStorage.counter = i;
var timeout = Math.floor(Math.random() * (5000 - 1000)) + 1000;
setTimeout(function(){
countDown();
}, timeout);
} else {
document.getElementById('counter-wrp').innerText = 'Oh no, you missed out! All of the coupons are gone.'
}
}
countDown();
<span id="counter-wrp">Be the first to know when we launch! We are only giving
out 100 coupons and there are only <span id="counter" style="color: red;"></span> left</span>
I create this jsFiddle for you using your example
My method utilizes localStorage, which is perfect for this type of function. You can read more about local storage here w3schools. You need to this save the count.
You will notice that to initialize the counter you need additional options
var counter = new Counter({
start: 123456789,
up: '#btnUp',
down: '#btnDn',
storageKey: 'count'
});
up: and down: are just jQuery selectors for the buttons I added with id's btnUp and btnDn. storagekey: can be whatever string you'd like to set to retrieve our count out of localstorage.
here are my buttons
<div class="buttons">
<button id="btnUp" type="button">+</button>
<button id="btnDn" type="button">-</button>
</div>
I hope this helps

Categories

Resources