how can I re-call this function? not experienced with ES6 - javascript

I don't know how to call counter() a second time after it runs on page load
I made a new "instance" of the counter, I think. And this does work but there must be a correct way. I need to call it in replay()
/**
* #fileoverview demo
*/
class ReVideo {
constructor() {
this.time = 5;
...
this.timer = document.getElementById("update");
this.counter = setInterval(() => this.countdown(), 1000);
this.fader = fader();
this.counter2 = "";
...
this.retry.addEventListener('click', () => this.replay());
...
}
countdown() {
this.time--;
if (this.time > -1) {
this.timer.innerHTML = "seconds remaining: " + this.time;
} else {
this.timer.innerHTML = "You Lose!";
this.watch.style.display = "block";
this.retry.style.display = "block";
clearInterval(this.counter);
clearInterval(this.counter2);
this.coins++;
this.coinCount.innerHTML = "Coins: " + this.coins;
}
this.notice.style.visibility = "visible";
this.notice.innerHTML = "Loaded";
}
...
replay() {
this.time = 5;
this.watch.style.display = "none";
this.notice.style.visibility = "hidden";
fader("Loaded");
this.retry.style.display = "none";
this.counter2 = setInterval(() => this.countdown(), 1000);
this.counter2;
}
...
}
new ReVideo();
It does not run if i say counter();

You could have a helper counter function to return the intervalID like:
counter () {
const interval = setInterval(() => this.countdown(), 1000);
return interval;
}
and in your constructor, you could assign the intervalID to some variable like:
this.interval = counter();
Then you can stop the counter by passing the variable holding the intervalID like clearInterval(this.interval);

Related

Do something when timer ends

I have a timer, I want to do something when textContent of div element === 0;
JavaScript:
function createTimer() {
const display = document.createElement('div');
display.classList.add('display');
display.id = 'display';
display.textContent = '5';
return display;
};
let intervalID;
function startTimer() {
resetTimer();
intervalID = setInterval(() => {
let displayTimer = document.getElementById('display');
let displayNumber = parseInt(displayTimer.textContent);
if (displayTimer.textContent !== '0') displayTimer.textContent = displayNumber - 1;
}, 1000);
};
function resetTimer() {
clearInterval(intervalID);
};
function someFunc() {
// here is a lot of code stuff and timer is working correctly
const timer = createTimer();
};
This is what i tried:
function someFunc() {
const timer = createTimer();
timer.addEventListener('input', () => {
if (timer.textContent === '0') {
console.log(true);
};
});
};
As far as I understood correctly, by creating input event on timer, I always get timer.textContent when it changes, right? I keep track of all the changes that's happening in this div element.
Nothing happens.
Keep track of your count as a number in JavaScript. This creates clarity in what the count is and how it can be manipulated.
Inside the setInterval callback, check if the count is 0. The interval is already there and will run every second, so it makes sense to check it in that place.
The example below is a modified version of your script with the suggested implementation. Since you're returning the display element from the createTimer function I've decided to reuse it in the startTimer function. That way you don't have to select the element from the DOM, as you already have a reference to the element.
As a bonus an extra argument which can be callback function to do something whenever the timer ends.
let count = 5;
let intervalID;
function createTimer() {
const display = document.createElement('div');
display.classList.add('display');
display.id = 'display';
display.textContent = '5';
return display;
};
function resetTimer() {
clearInterval(intervalID);
};
function startTimer(timer, onFinish) {
resetTimer();
intervalID = setInterval(() => {
if (count !== 0) {
count--;
}
if (count === 0) {
resetTimer();
if (typeof onFinish === 'function') {
onFinish();
}
}
timer.textContent = count;
}, 1000);
};
function someFunc() {
const timer = createTimer();
document.body.append(timer);
startTimer(timer, () => {
console.log('Done');
});
};
someFunc();
The input event fires when the value of an <input>, <select>, or <textarea> element has been changed by user. It does not fire when setting the textContent programmatically.
You can use the MutationObserver API to observe the node change.
const timer = createTimer();
new MutationObserver(() => {
let timer = document.getElementById('display');
if (timer.textContent === '0') {
console.log(true);
};
}).observe(timer, { childList: true });
You could implement the timer with the help of async/await code. It makes the code a lot more cleaner, by having your start and end code in the same function.
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
function createTimer(name) {
const element = document.createElement("div");
element.classList.add("timer");
document.body.appendChild(element);
element.textContent = name+": -";
return async function(seconds) {
for (let second = seconds; second >= 0; second--) {
element.textContent = name+": "+second;
if (second > 0) {
await wait(1000);
}
}
};
}
async function someFunc() {
const timer = createTimer("First timer");
console.log("first timer started", new Date());
await timer(10);
console.log("timer ended", new Date());
await wait(2500);
console.log("first timer started again", new Date());
await timer(5);
console.log("first timer ended again", new Date());
}
async function someOtherFunc() {
const timer = createTimer("Second timer");
console.log("second timer started", new Date());
await timer(20);
console.log("second timer ended", new Date());
}
someFunc();
someOtherFunc();
.timer {
text-align: center;
font-size: 2em;
font-family: sans-serif;
}

I can't call a class function inside another class function in Javascript

I want to call the function "displayTime" in "startTimer" but for some reason I get "Uncaught TypeError: this.displayTime is not a function" in the console.
let endTimer = "0";
let isRunning = false;
//! CLASS
class Timer {
constructor(endTimer, isRunning) {
this.endTimer = endTimer;
this.isRunning = isRunning;
}
startTimer() {
if (this.endTimer === "0") {
this.endTimer = new Date().getTime() + 1500000;
}
displayTime();
if (this.isRunning === true) {
this.pauseTimer();
this.isRunning
}
this.isRunning = true;
}
displayTime() {
let now = new Date().getTime();
let remainingTime = this.endTimer - now;
let minutes = Math.floor(remainingTime / 1000 / 60);
let seconds = Math.floor((remainingTime / 1000) % 60);
if (seconds < 10) {
seconds = "0" + seconds;
}
timer.innerHTML = `<h1>${minutes}:${seconds}</h1>`;
start.textContent = "STOP"
this.update = setInterval(this.displayTime, 100);
}
}
let newTimer = new Timer(endTimer, isRunning);
//! EVENT LISTENERS
start.addEventListener("click", newTimer.startTimer);
I think that I'm missing something obvious, but I don't understand what...
start.addEventListener("click", newTimer.startTimer.bind(newTimer));
Calling displayTime(); without the prepended keyword 'this' is the main issue (line 16 below) as mentioned by GenericUser and Heretic Monkey in the comments above.
You probably already know this but you'll want to define a pauseTimer() method/function as well.
let endTimer = "0";
let isRunning = false;
//! CLASS
class Timer {
constructor(endTimer, isRunning) {
this.endTimer = endTimer;
this.isRunning = isRunning;
}
}
Timer.prototype.startTimer = function() {
if (this.endTimer === "0") {
this.endTimer = new Date().getTime() + 1500000;
}
this.displayTime(); // this is the important line
if (this.isRunning === true) {
this.pauseTimer();
this.isRunning
}
this.isRunning = true;
}
Timer.prototype.displayTime = function() {
let now = new Date().getTime();
let remainingTime = this.endTimer - now;
let minutes = Math.floor(remainingTime / 1000 / 60);
let seconds = Math.floor((remainingTime / 1000) % 60);
if (seconds < 10) {
seconds = "0" + seconds;
}
//timer.innerHTML = `<h1>${minutes}:${seconds}</h1>`;
//start.textContent = "STOP"
this.update = setInterval(this.displayTime, 100);
}
Timer.prototype.pauseTimer = function() {
this.isRunning = false;
}
let newTimer = new Timer("0", true);
newTimer.startTimer();
//! EVENT LISTENERS
//start.addEventListener("click", newTimer.startTimer);
class Timer {
startTimer() {
// You forgot this keyword
this.displayTime();
}
displayTime() {
console.log('do something');
}
}
let newTimer = new Timer();
// addEventListener changes the context of this.
// Using an arrow function will keep 'this' keyword in tact inside startTimer method
start.addEventListener('click', () => newTimer.startTimer)

Javascript pause/resume toggle button

I am working on a little challenge with school. We have learned CSS, HTML, and Javascript. I am trying to create a timer that is always running in the background. Then I need a button that pauses said timer and changes into a resume button that will resume the timer. This is what I have come up with.
document.addEventListener("DOMContentLoaded", () => {
const counterElement = document.getElementById('counter')
let counterValue = 0
const pauseButton = document.getElementById('pause')
const resumeButton = document.getElementById('resume')
const submitButton = document.getElementById(`submit`)
const minusButton = document.getElementById(`minus`)
const plusButton = document.getElementById('plus')
const heartButton = document.getElementById('heart')
intervalId = setInterval(myCallback, 1000);
function myCallback() {
counterValue += 1;
counterElement.innerHTML = counterValue;
}
function resume() {
setInterval(myCallback, 1000);
pauseButton.style.display = '';
resumeButton.style.display = 'none';
}
function pause() {
clearInterval(intervalId);
pauseButton.style.display = 'none';
resumeButton.style.display = '';
}
pauseButton.addEventListener("click", (e) => {
pause()
})
resumeButton.addEventListener("click", (e) => {
resume()
})
It does not function properly. Only the first few clicks work.
function resume() {
intervalId = setInterval(myCallback, 1000);
pauseButton.style.display = '';
resumeButton.style.display = 'none';
}
Try this. The root issue is that you're not assigning your setInterval reference back to your intervalId variable. So when you call clearInterval(intervalId) later, your code is saying, "That's already been cleared..." and not doing anything.
In short, your current resume() function creates a NEW setInterval - it doesn't update the old one. And since there was no reference to the new setInterval, there was no way for your pause function to be able to find it and clear it.
When you call setTimeout in the resume function, you have to reassign the intervalId variable to store the new interval ID. If you don't do that, your pause function will keep cancelling the first interval, which is a no-op.
So do this instead:
document.addEventListener("DOMContentLoaded", () => {
const counterElement = document.getElementById('counter')
let counterValue = 0
const pauseButton = document.getElementById('pause')
const resumeButton = document.getElementById('resume')
//const submitButton = document.getElementById(`submit`)
//const minusButton = document.getElementById(`minus`)
//const plusButton = document.getElementById('plus')
//const heartButton = document.getElementById('heart')
//It's a good idea to declare your variables. Since you want to reassign it, you probably want `let`.
let intervalId = setInterval(myCallback, 1000);
function myCallback() {
counterValue += 1;
counterElement.innerHTML = counterValue;
}
function resume() {
//Assign the new interval ID to `intervalId`
intervalId = setInterval(myCallback, 1000);
pauseButton.style.display = '';
resumeButton.style.display = 'none';
}
function pause() {
clearInterval(intervalId);
pauseButton.style.display = 'none';
resumeButton.style.display = '';
}
pauseButton.addEventListener("click", (e) => {
pause()
})
resumeButton.addEventListener("click", (e) => {
resume()
})
})
<button id="pause" >Pause</button>
<button id="resume" style="display:none;" >Resume</button>
<div id="counter" >0</div>
When you create a new Interval in your resume() function, you need to store its return value again in your intervalId variable for the next time you call pause().

How to stop and reset my countdown timer?

I'm trying to make my countdown timer do the following 4 things
When 'start' is clicked, change button to 'stop'
When 'stop' is clicked, stop the timer
When timer is stopped, show 'start' button
When 'reset' is clicked, reset the timer
$(document).ready(function() {
var counter = 0;
var timeleft = 5;
function nf(num) {
var s = '0' + num;
return s.slice(-2);
}
function convertSeconds(s) {
var min = Math.floor(s / 60);
var sec = s % 60;
return nf(min, 2) + ' ' + nf(sec, 2);
}
function setup() {
var timer = document.getElementById("timer");
timer.innerHTML = (convertSeconds(timeleft - counter));
var interval = setInterval(timeIt, 1000);
function timeIt() {
counter++;
timer.innerHTML = (convertSeconds(timeleft - counter));
if (counter == timeleft) {
clearInterval(interval);
}
}
}
$("#timer-button").click(function() {
setup();
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I recently needed something like this too. I ended up writing an ES6 class for that.
In my solution, I used Events to notify other components about the timer. Here is a fiddle in which I met your needs, but I left my EventManager() calls to show what I actually did.
The used EventManager is this one. The timer counts in 100ms steps by default, but you can adjust this by calling startTimer() with the interval of choice.
class Timer {
constructor(maxTime, startValue = 0) {
// Actual timer value 1/10s (100ms)
this.value = startValue;
// Maximum time of the timer in s
this.maxTime = maxTime * 10;
this.timerRunning = false;
}
/**
* Starts the timer. Increments the timer value every 100ms.
* #param {number} interval in ms
*/
startTimer(interval = 100) {
if (!this.timerRunning) {
let parent = this;
this.timerPointer = setInterval(function() {
if (parent.value < parent.maxTime) {
parent.value++;
//EventManager.fire('timerUpdated');
$("span").text(parent.value / 10 + "/" + parent.maxTime / 10);
} else {
parent.stopTimer();
//EventManager.fire('timeExceeded');
$("button").text("Start");
this.resetTimer();
$("span").text("Countdown over");
}
}, interval);
this.timerRunning = true;
}
}
// Stops the Timer.
stopTimer() {
clearInterval(this.timerPointer);
this.timerRunning = false;
}
// Resets the timer and stops it.
resetTimer() {
this.stopTimer();
this.value = 0;
$("span").text("0/" + this.maxTime/10);
//EventManager.fire('timerUpdated');
}
// Resets the timer and starts from the beginning.
restartTimer() {
this.resetTimer();
this.startTimer();
}
}
let timer = new Timer(6);
$("#start-stop").click(function() {
if (timer.timerRunning) {
timer.stopTimer();
$("#start-stop").text("Start");
} else {
timer.startTimer();
$("#start-stop").text("Stop");
}
});
$("#reset").click(function() {
timer.resetTimer();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="start-stop">
Start
</button>
<button id="reset">
Reset
</button>
<span>Timer: </span>
const div = document.querySelector('div');
const btn = document.querySelector('#timerBtn');
const resetbtn = document.querySelector('#reset');
let startFlag = 0;
let count = 0;
let intervalId;
const ms = 1000;
div.textContent = count;
btn.addEventListener('click', function() {
startFlag = startFlag + 1;
if(startFlag%2 !== 0) { // Start button clicked;
btn.textContent = 'Stop';
startTimer();
} else {
btn.textContent = 'Start';
stopTimer();
}
});
resetbtn.addEventListener('click', function() {
count = 0;
div.textContent = count;
});
function startTimer() {
intervalId = setInterval(() => {
count = count + 1;
div.textContent = count;
}, 1000);
}
function stopTimer() {
clearInterval(intervalId);
}
<div></div>
<button id="timerBtn">Start</button>
<button id="reset">Reset</button>

Cardio app: clear timer for interval located in function scope

Here is Cardio app on CodePen.
http://codepen.io/Mahmoud-Zakaria/pen/vxWzxW?editors=1010
When I want to stop the cardio by stop btn and clear its interval which its refernce in function scope, It doesn't stop/clear.
(function() {
//States
let i = 5;
let play = true;
//DOM
let cardioSec = document.getElementById('cardio-sec');
let cardioStart = document.getElementById('cardio-start');
let cardioStop = document.getElementById('cardio-stop');
//Render
function render(el) {
el.innerHTML = i
};
//Audio
let audio = new Audio("https://raw.githubusercontent.com/mahmoudZakaria90/myCodePenStuff/master/audio/Bepp-beep.mp3");
//Setup
function setInterVals(times, callback) {
i = times;
let timer = setInterval(function() {
console.log(i) //RENDER
render(cardioSec)
i--;
if (i < 1) {
clearInterval(timer);
audio.play();
callback();
}
}, 1000)
return timer;
}
function start() {
setInterVals(5, cardio);
}
function cardio() {
setInterVals(30, rest);
}
function rest() {
setInterVals(15, cardio);
}
function stopCardio() {
clearInterval(setInterVals())
}
cardioStart.onclick = start
cardioStop.onclick = stopCardio
})();
Done:
http://codepen.io/anon/pen/gmdLMr?editors=1010
The "timer" variable was out of the scope, by declaring it as global, you wont have problems ^^

Categories

Resources