Do not run two timers at the same time - javascript

I developed a button with two states (Start and Stop).
When I start on one of the lines, a time count is started. When executing the button on a different line (start to start counting on another line), I want to pause the line that was previously active and start the timer on that new line.
My problem is that I am not able to implement this.
When I try to stop the previous line and start only on the new line, the timers simply stop :(
Can someone help me?
Stackblitz
ts
startTimer(data) {
let self = this;
self.taskService.startTimer(data);
self.currentState = self.taskService.getCurrentState();
const pauseIds = [];
this.data.forEach(d => {
if (d.id !== data.key.id && d.idUser !== data.key.idUser
&& this.taskService.fetchDisplay() !== undefined
&& this.taskService.currentState === 'start')
pauseIds.push(d.id);
});
pauseIds.forEach(id => {
console.log (id)
this.taskService.pauseTimer(id);
});
}
pauseTimer(data) {
let self = this;
self.taskService.pauseTimer(data);
self.currentState = self.taskService.getCurrentState();
}
service
startTimer(data) {
this.time = 0;
this.currentRowIndex = data.rowIndex;
this.currentState = 'start';
this.interval = setInterval(() => {
if (this.time === 0) {
this.time++;
} else {
this.time++;
}
this.display = this.time;
return this.display;
}, 1000);
}
pauseTimer(data) {
this.currentRowIndex = data.rowIndex;
this.currentState = 'pause';
this.time = 0;
clearInterval(this.interval);
}
fetchDisplay() {
return this.display;
}
getCurrentState() {
return this.currentState;
}

As Ivan Mihaylov mentioned in the comments the logic really seems too convoluted.
Nevertheless the solution is rather simple.
You should start you timer after you pause all other possible started timers. Otherwise you timer state is pause after startTimer finishes so conditions in the template prevent active state from displaying.
You need to reset display as well as time in taskService.startTimer method. Otherwise displayed time at the start contains the last value of previous counter.
Here is a fixed StackBlitz example.

Related

What approach should I take to continuously skip to a function with conditions and no loops?

//Skip to 3rd paragraph for main point.
First I want to mention I am a beginner to programming. I have decided to start editing before I can create from scratch. So I found a script that can be used within an Internet Browser's Console (The inspect element thing) to perform many tasks. So at first the script was only the size of a paragraph but over the course of few days I have been adding and editing it (which I find really fun) to create a more custom script. I want to get to the point but without context it may be difficult to help me.
So basically the script I have come up with uses alot of "Functions" I am not 100% what anything is even after studying but I know enough about what they do. So I use the functions to define conditions and to perform different tasks. I keep many functions to keep everything organized and to find mistakes. However; the problem I am having now is the script is not working properly and I cant find my mistake.
MAIN POINT
I have many functions going down in order but I want the script to go back up to the first function after certain conditions occur. I want to do this without using loops if possible. The way I do it is by calling the function like
"NameOfFunction"();
Here is some of my code:
function roll() {
if (Dloss === false) {
if (loop === true) {
tbBet.value = start;
btRoll.click();
refreshIntervalId = setInterval(roll2, delay);
}
}
if (Dloss === true) {
if (loop === true) {
tbBet.value = start;
btRoll.click();
refreshIntervalId = setInterval(decision, delay);
}
}
}
function decision() {
if (Dloss === true) {
var thestring = document.getElementById('roll').value;
var thenumber = retnum(thestring);
if (thenumber < rollUnder) {
start = (start * remain).toFixed(2);
}
if (thenumber > rollUnder) {
start = (start * MultLoss).toFixed(2);
if (start > maxBetValue) {
loop = false;
}
btRoll.click();
clearInterval(refreshIntervalId);
roll();
}
btRoll.click();
clearInterval(refreshIntervalId);
roll3();
}
}
So you can see where I have roll(); within an if statement. I want it to loop back up to the start but it doesnt seem to work. I am sorry if this is something that is obvious. I am learning and after struggling for a while I have decided to post my question here. Thanks in advance for anyhelp.
---------Edit 1-----------
So what I want to do is call the function roll() over here:
btRoll.click();
clearInterval(refreshIntervalId);
roll();
So am I calling this correctly as from what I have researched this is the only way? Should I post the whole script here? (BTW sorry I am new to the site aswell still learning how to use)
When a function ends, it returns to where the function was called. If you want the code in your decision function to happen after every roll you need to explicitly call decision()
function roll() {
if (Dloss === false) {
if (loop === true) {
tbBet.value = start;
btRoll.click();
refreshIntervalId = setInterval(roll2, delay);
}
}
if (Dloss === true) {
if (loop === true) {
tbBet.value = start;
btRoll.click();
refreshIntervalId = setInterval(decision, delay);
}
}
decision() // <--- Like so
}
function decision() {
if (Dloss === true) {
var thestring = document.getElementById('roll').value;
var thenumber = retnum(thestring);
if (thenumber < rollUnder) {
start = (start * remain).toFixed(2);
}
if (thenumber > rollUnder) {
start = (start * MultLoss).toFixed(2);
if (start > maxBetValue) {
loop = false;
}
btRoll.click();
clearInterval(refreshIntervalId);
roll();
}
btRoll.click();
clearInterval(refreshIntervalId);
roll3();
}
}

JavaScript: I need a continuous loop that won't kill the browser or block the page

I have a carousel plugin I've created and I need a way to have it run a function that moves the image to the side and brings in the next image. I have this working with navigation arrows but I want to implement a way for it to do this on its own.
I'm having trouble finding information on this as Google is bloated with everyone's carousel libraries.
Basically, I just need something like:
window.setTimeout(() => {
// do something
}, 1000);
But it needs to run over and over unless a particular event is triggered. My first thought was a while loop but that would have been disastrous.
I don't have much to show but currently, this is the code:
let mouseIsOver = false;
inner.addEventListener('mouseenter', () => {
mouseIsOver = true;
console.log(mouseIsOver);
});
inner.addEventListener('mouseleave', () => {
mouseIsOver = false;
console.log(mouseIsOver);
});
You could use the setInterval method which repeatedly calls a function. And then call clearInterval to stop it.
let inner = document.getElementById('inner');
let pages = ['mediumspringgreen', 'coral', 'cyan', 'moccasin'];
let mouseIsOver = false;
let interval = start();
let i = 0;
function start() {
return setInterval(() => inner.style.background = pages[i++ % 4], 3000);
}
inner.addEventListener('mouseenter', () => {
mouseIsOver = true;
clearInterval(interval);
console.log('pause');
});
inner.addEventListener('mouseleave', () => {
mouseIsOver = false;
console.log('continue');
interval = start();
});
#inner { width: 100px; height: 100px; background: cyan }
.as-console-wrapper { max-height: 1.5em !important; }
<div id=inner></div>
Basically, I just need something like:
window.setTimeout(() => {
// do something
}, 1000);
But it needs to run over and over unless a particular event is
triggered.
Have you considered window.setInterval()?
The setInterval() method... repeatedly calls a function or executes a code snippet, with a fixed time delay between each call. It returns an interval ID which uniquely identifies the interval, so you can remove it later by calling clearInterval().
Considering your use case, here's one possible solution:
let mouseIsOver = false;
// start a timer that runs goToNextImage() every 1000 ms and
// stores its ID so it can be cancelled on mouseenter
let goToNextImageTimer = window.setInterval(goToNextImage, 1000);
inner.addEventListener('mouseenter', () => {
mouseIsOver = true;
console.log(mouseIsOver);
if (goToNextImageTimer !== null) {
// stop interval timer if running
window.clearInterval(goToNextImageTimer);
}
});
inner.addEventListener('mouseleave', () => {
mouseIsOver = false;
console.log(mouseIsOver);
if (goToNextImageTimer === null) {
// start interval timer if not running
goToNextImageTimer = window.setInterval(goToNextImage, 1000);
}
});
Need to look at requestAnimationFrame. https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame

Image player issue with jQuery

I've made a jQuery player for images Demo Link.
It changes the screens with provided intervals and draws touches on it. Now, I want to implement pouse, play functionality.
When I click on play button to stop screen playing, I call FlowPlaye.stop() method:
FlowPlayer.prototype.stop = function() {
$(".fp-pause").removeClass("fp-pause").addClass("fp-play");
clearInterval(this.screenIntervalId);
clearInterval(this.timeIntervalId);
clearInterval(this.touchIntervalId);
$('.fp-progress').stop();
this.isAnimated = false;
return false;
}
And at the second time FlowPlayer.play():
FlowPlayer.prototype.play = function() {
var fp = this; // Obj refers to the FlowPlayer itself such as "this"
fp.isAnimated = true;
console.log(typeof this.screenIndex)
console.log(this.screenIndex)
fp.screenIndex = typeof this.screenIndex == 'number' ? this.screenIndex : 0;
fp.render(fp.screens[fp.screenIndex]);
fp.initTimeline(fp.duration);
fp.screenIntervalId = setInterval(function() {
if (fp.screenIndex == fp.screens.length - 1) {
console.log("the end of screens");
clearInterval(fp.screenIntervalId)
return;
}
++fp.screenIndex;
fp.render(fp.screens[fp.screenIndex]);
}, fp.screens[fp.screenIndex].delay)
}
The problem is that when I do this, the screen playing intervals are messing (try to stop video at 20th second and restore). I need to save state of player, but I don't know how.
I think using 3 different timers is making this unnecessary difficult. If you refactor it into 1 unified timer, pausing (and other playback controls) would be quite easy.
Separate your keyframe events into separate functions:
function setImage(img) {...}
function showTouch(x, y) {...}
function hideTouch() {...}
On startup, convert your screens array to something like this:
var keyframes = [
{ time:0, func:setImage, args:['http://...']},
{ time:1000, func:showTouch, args:[10, 30]},
{ time:3000, func:hideTouch, args:[]},
...
];
Set up a single timer for playback:
var time = 0,
next = 0,
isPaused = false,
interval;
function timer() {
if (isPaused) {
return;
}
var nextKeyframe = keyframes[next];
time += 100;
if (time >= nextKeyframe.time) {
nextKeyframe.func.apply(this, nextKeyframe.args);
next += 1;
if (next === keyframes.length) {
clearInterval(interval);
}
}
}
Now, you have an easily controllable playback:
// play / replay - reset time and next, then start the timer
time = 0;
next = 0;
interval = setInterval(timer, 100);
// seek - just set a new time, and find the next keyframe
time = 1500;
for (next = 0; keyframes[next].time < time && next < keyframes.length; next++) {}
// pause - the timer stays on, but won't do anything
isPaused = true;
// stop
clearInterval(interval);
Note: The snippets are untested, may have some typos in them. I just wanted to demonstrate the process of making it cleaner / more controllable.

Jquery - looping with nested functions and setInterval()

Probably not the clearest title, but here goes - I need to display two independent countdowns on a page, accepting a user input for the starting value for each. When one reaches zero, the other starts and counts down to zero. Code for this is below, and working as expected.
I call the Timer1 function, which checks a variable for the starting value, if it exists, the count starts. When the count is zero, I clear the interval, reset the display to the starting value, and fire the second timer, if it has a value assigned:
function Timer1() {
var gDuration = goTime;
countdown = setInterval(function () {
if (gDuration >= 0) {
$("#durationValue").html(ToTime(gDuration));
gDuration--;
}
else {
clearInterval(countdown);
$("#durationValue").html(ToTime(goTime));
if (restTime != 0) {
Timer2();
}
}
}, 1000);
}
function Timer2() {
var rDuration = restTime;
countdown = setInterval(function () {
if (rDuration >= 0) {
$("#restValue").html(ToTime(rDuration));
rDuration--;
}
else {
clearInterval(countdown);
$("#restValue").html(ToTime(restTime));
}
}, 1000);
}
The next step is to allow that process to run for a set number of loops - I've tried wrapping setInterval in Timer1 in a for loop, which doesn't work. Any ideas how to better go about this?
for-loops don't work well with asynchronous stuff. Just make it a counter with an end condition as you have demonstrated with g/rDuration already.
With some callback abstractions, and heavy continuation-passing-style:
function timer(el, duration, interval, callback) {
var countdown = setInterval(function() {
if (duration-- >= 0) {
el.text(ToTime(duration));
} else {
clearInterval(countdown);
callback();
}
}, interval);
}
var goTime = …, restTime = …;
function t1(cb) {
timer($("#durationValue"), goTime, 1000, cb);
}
function t2(cb) {
timer($("#restValue"), restTimer, 1000, cb);
}
var loops = …;
(function loop(cb) {
t1(function(){
t2(function() {
if (loop-- >= 0)
loop(cb);
else
cb();
});
});
})(function() {
alert("finished!");
});
The easiest thing I can think of is to have your Timer functions have a parameter with the current iteration. Increment that value whenever one timer starts another time. And use that value to determine if it should indeed start the next timer.

Is there a way to check if a var is using setInterval()?

For instance, I am setting an interval like
timer = setInterval(fncName, 1000);
and if i go and do
clearInterval(timer);
it does clear the interval but is there a way to check that it cleared the interval? I've tried getting the value of it while it has an interval and when it doesn't but they both just seem to be numbers.
There is no direct way to do what you are looking for. Instead, you could set timer to false every time you call clearInterval:
// Start timer
var timer = setInterval(fncName, 1000);
// End timer
clearInterval(timer);
timer = false;
Now, timer will either be false or have a value at a given time, so you can simply check with
if (timer)
...
If you want to encapsulate this in a class:
function Interval(fn, time) {
var timer = false;
this.start = function () {
if (!this.isRunning())
timer = setInterval(fn, time);
};
this.stop = function () {
clearInterval(timer);
timer = false;
};
this.isRunning = function () {
return timer !== false;
};
}
var i = new Interval(fncName, 1000);
i.start();
if (i.isRunning())
// ...
i.stop();
The return values from setTimeout and setInterval are completely opaque values. You can't derive any meaning from them; the only use for them is to pass back to clearTimeout and clearInterval.
There is no function to test whether a value corresponds to an active timeout/interval, sorry! If you wanted a timer whose status you could check, you'd have to create your own wrapper functions that remembered what the set/clear state was.
I did this like below, My problem was solved. you should set the value like "false", when you clearTimeout the timer.
var timeer=false;
----
----
if(timeer==false)
{
starttimer();
}
-----
-----
function starttimer()
{
timeer_main=setInterval(activefunction, 1000);
timeer=true;
}
function pausetimer()
{
clearTimeout(timeer_main);
timeer=false;
}
Well you can do
var interval = setInterval(function() {}, 1000);
interval = clearInterval(interval);
if (typeof interval === 'undefined'){
...
}
but what are you actually trying to do? clearInterval function is an always success function and it will always return undefined even if you call it with a NaN value, no error checking in there.
You COULD override the setInterval method and add the capability to keep track of your intervals. Here is an untestet example to outline the idea. It will work on the current window only (if you have multiple, you could change this with the help of the prototype object) and this will only work if you override the functions BEFORE any functions that you care of keeping track about are registered:
var oldSetInterval = window.setInterval;
var oldClearInterval = window.clearInterval;
window.setInterval = function(func, time)
{
var id = oldSetInterval(func, time);
window.intervals.push(id);
return id;
}
window.intervals = [];
window.clearInterval = function(id)
{
for(int i = 0; i < window.setInterval.intervals; ++i)
if (window.setInterval.intervals[i] == id)
{
window.setInterval.intervals.splice(i, 1);
}
oldClearInterval(id);
}
window.isIntervalRegistered(id)
{
for(int i = 0; i < window.setInterval.intervals; ++i)
if (window.setInterval.intervals[i] == func)
return true;
return false;
}
var i = 0;
var refreshLoop = setInterval(function(){
i++;
}, 250);
if (isIntervalRegistered(refrshLoop)) alert('still registered');
else alert('not registered');
clearInterval(refreshLoop);
if (isIntervalRegistered(refrshLoop)) alert('still registered');
else alert('not registered');
The solution to this problem: Create a global counter that is incremented within your code performed by setInterval. Then before you recall setInterval, test if the counter is STILL incrementing. If so, your setInterval is still active. If not, you're good to go.

Categories