VueJS : How to update value inside watcher without affecting the watcher - javascript

I made an online quiz application using Vue in which each question has its own duration. I'm using watcher for the countdown and show it on the webpage. The problem I'm facing is every time I updated the time to match the next question's time, the countdown will end much sooner. What can I do to update the time limit in the watcher without interrupting the current countdown?
watch: {
timerEnabled(value) {
if (value) {
setTimeout(() => {
this.timeLimit--;
}, 1000);
}
},
timeLimit: {
handler(value) {
if (value >= 0 && this.timerEnabled) {
setTimeout(() => {
this.timeLimit--;
}, 1000);
}
else{
// set the timer to the next question's time limit and move to the next question
}
}
}
}

I think you can try something like this:
data() {
return {
timer: null,
timerCounter: 0
}
},
methods: {
setTimer(state) { // true enabled, false disabled
if(state) {
this.timerCount = // seconds
this.timer = setTimeout(() => {
timerCounter--;
if(timerCounter <= 0) {
this.setTimer(false);
// go to next question
this.setTimer(true);
}
}, 1000);
} else {
clearTimeout(this.timer);
}
}
}
You only need to call setTimer(true) for start the timer for the first time, for example in the mounted() function or at click event of a button.
If you don't want that the timer restart after question change, remove this.setTimer(true);.

Related

start Interval again after clearing it

How can I restart Interval after clearing it? I want a button to be clickable once every 11 seconds I made it disabled while timer is > 0 after it's equal to 0 button isn't disabled so it's clickable I wrote this code it seems to work but after multiple call of a setInterval() function timer goes down too fast any soltuions>
data:{
sTimer:11,
sDisabled:true,
asd:null
},
methods:{
testing(){
this.sTimer--;
if(this.sTimer == 0){
clearInterval(this.asd);
this.sTimer= 11;
this.sDisabled = false;
}else{
this.sDisabled = true;
}
},
specialAttack(){
setInterval(() => this.testing(), 1000)
}
},
created(){
this.asd = setInterval(() => this.testing(), 1000);
}
<button class="specialAttack" :disabled="sDisabled" #click="specialAttack(); testing()">Special Attack {{ sTimer }}</button>
There are several mistakes you made here, so first of all to achieve such a thing you should use setTimeout instead of setInterval because interval generally will be repeated after a certain given time, so this may one of the possible reason for being called twice when you click your button as well. Then you need to create a generic function for this cause and then call it in document creation instead of creating two different intervals and calling them separately.
So with respecting these rules, your final code should be something like this:
HTML
<button class="specialAttack" :disabled="sDisabled" #click="specialAttack();">Special Attack {{ sTimer }}</button>
Javascript
data: () => {
return {
sTimer: 11,
sDisabled: false,
asd: null
};
},
methods: {
specialAttack() {
clearTimeout(this.asd); // Or as you suggest in comments you can disbale it here with replacing this: this.sDisabled = true
if (this.sTimer > 0) {
this.asd = setTimeout(() => {
this.sDisabled = true;
this.sTimer -= 1;
this.specialAttack();
}, 1000);
} else {
clearTimeout(this.asd);
this.sTimer = 11;
this.sDisabled = false;
}
}
},
created() {
this.specialAttack();
}
Here is a working demo:

clearInterval() not working in an if/else statement with recursive function

I am trying to build a countdown that switches between play time and work time. It starts with 10 seconds of work then when it reaches 0 seconds we clear the interval and set it to 'play' and call the function again...
var model = {
intervalID: 0,
status: 'work',
workSeconds: 10,
playSeconds: 10,
}
function startCountdown(){
if (model.status === 'work') {
model.countdown = model.workSeconds;
model.intervalID = setInterval(function(){
model.countdown--;
if (model.countdown > 0) {
console.log('work', model.countdown);
} else {
model.status = 'play';
clearInterval(model.indervalId);
startCountdown();
}
}, 1000);
} else if (model.status === 'play') {
model.countdown = model.playSeconds;
model.intervalID = setInterval(function(){
model.countdown--;
if (model.countdown > 0) {
console.log('play', model.countdown);
} else {
model.status = 'work';
clearInterval(model.indervalId);
startCountdown();
}
}, 1000);
}
}
startCountdown();
This function is supposed to console log a 10 second countdown for work, then when the countdown reaches 0 switch to a 10 seconds countdown of play, and keep doing that.
At the moment it looks like no intervals are being cleared and both intervals just keep setting each other in a feedback loop.
Why are the intervals not being cleared?
I think you have a typo. clearInterval(model.indervalId); should be clearInterval(model.intervalID);.
I'd use setTimeout for this too, but I guess you already know about that.

Need help stopping slideshow using jQuery

I've run into an issue with jQuery code that I'd like some help on. While the next and previous buttons work correctly, there appears to be an issue correctly stopping a slideshow. This is probably something we're completely overlooking, but I can't see what.
There is no JavaScript errors showing in the console. The interrupt method was being reached - at one point I had console.log calls in there to verify (cleaned up for presentation reasons).
http://jsfiddle.net/eLn83ep0/
Your help is much appreciated.
The below code is the functionality for prev/stop/start/next:
if ($(settings.next).size()) {
$(settings.next).bind('click.scrollface', function (e) {
methods.interrupt.call($this);
methods.next.call($this);
});
}
if ($(settings.pause).size()) {
$(settings.pause).bind('click.scrollface', function (e) {
methods.interrupt.call($this);
});
}
if ($(settings.play).size()) {
$(settings.play).bind('click.scrollface', function (e) {
methods.interrupt.call($this);
methods.start.call($this);
});
}
/*
* Setup up prev bindings
*/
if ($(settings.prev).size()) {
$(settings.prev).bind('click.scrollface', function (e) {
methods.interrupt.call($this);
methods.prev.call($this);
});
}
Here is the method for interrupt:
interrupt: function (time) {
return $(this).each(function () {
var data = $(this).data('scrollface');
console.log(data);
console.log('...');
if (!data) {
return false;
}
var $this = $(this),
period = 0;
/*
* Stop the timer, and wait a period of time before restarting it.
* Period defaults to the timer interval
*/
if (data.timer) {
if (typeof time !== "number") {
period = data.interval;
} else {
period = time;
}
methods.stop.call(this);
setTimeout(function resume_timer () {
clearInterval(data.timer);
data.timer = null;
methods.start.call($this);
}, period);
}
});
},
if ($(settings.pause).size()) {
$(settings.pause).bind('click.scrollface', function (e)
methods.stop.call($this);
});
}
if ($(settings.play).size()) {
$(settings.play).bind('click.scrollface', function (e) {
methods.start.call($this);
});
}
and delete the interrupt call in prev and next
//methods.interrupt.call(this);
because the interrupt method stopping the interval method and after timeout starting again, so most time you pause in this timeout but after this timeout the interrupt method starting the intervall again and dont care if you stoped it manually
see your updated fiddle working here http://jsfiddle.net/7ko4rdda/
Edit:
if you call interrupt with 0 for the buttons prev next click handler then you have the expected behavier that the period for the intervall starts new after next/prev click
if ($(settings.prev).size()) {
$(settings.prev).bind('click.scrollface', function (e) {
methods.interrupt.call($this,0);
methods.prev.call($this);
});
}
if ($(settings.next).size()) {
$(settings.next).bind('click.scrollface', function (e) {
methods.interrupt.call($this,0);
methods.next.call($this);
});
}
http://jsfiddle.net/7ko4rdda/1/

How to extend JavaScript countdown timer function with a new method?

I have the following countdown timer function:
jQuery.fn.countDown = function(settings,to) {
settings = jQuery.extend({
startFontSize: "46px",
endFontSize: "18px",
duration: 1000,
endNumber: 0,
callBack: function() { }
},
settings);
return this.each(function() {
//where do we start?
if(!to && to != settings.endNumber) { to = settings.startNumber; }
//set the countdown to the starting number
jQuery(this).text(to).css("fontSize",settings.startFontSize);
//loopage
jQuery(this).animate({fontSize: settings.endFontSize},
settings.duration,
"",
function() {
if(to > settings.endNumber + 1) {
jQuery(this).css("fontSize",
settings.startFontSize).text(to - 1).countDown(settings, to - 1);
} else {
settings.callBack(this);
}
});
});
};
To start a countdown on my page, I initialize it like so:
(This will make it count down from 5 to 0, shown in element #countdown)
jQuery("#countdown").countDown({
startNumber: 5,
callBack: function(me) { }
});
Now I sometimes need to cancel a running countdown and start a new one.
For example, stop the countdown at 3 and initialize again to start over.
Can somebody tell me how I can extend this code to do that?
(the original timer script was taken from http://davidwalsh.name/jquery-countdown-plugin)
V.
Given that you have some access to the settings, and you execute your timer as such:
var settings = {
startNumber: 5,
callBack: function(me) {}
};
jQuery("#countdown").countDown(settings);
You can stop and restart your timer like this:
function stopAndRestart() {
jQuery("#countdown").stop().countDown(settings);
}
.stop() stops the animation on a given element (which happens to, terribly, be the method of timing here)

How to auto refresh HTML only if there has been no activity on a page?

I have a website which I would like to auto refresh ONLY if user is not using it for a specific time (ie.180 sec).Is there a way to auto refresh HTML only if there has been no activity on a page?
Thank you!
Two approaches:
1. Use a once-a-second timer and a "timeout" value.
You probably want to wrap this up in an object:
var activityHandler = (function() {
var timerHandle = 0,
timeout;
flagActivity();
function start() {
stop();
flagActivity();
timerHandle = setInterval(tick, 1000);
}
function stop() {
if (timerHandle != 0) {
clearInterval(timerHandle);
timerHandle = 0;
}
}
function flagActivity() {
timeout = new Date() + 180000;
}
function tick() {
if (new Date() > timeout) {
stop();
location.reload();
}
}
return {
start: start,
stop: stop,
flagActivity: flagActivity
};
})();
Then start it on page load:
activityHandler.start();
And ping it every time you see "activity":
activityHandler.flagActivity();
So for instance, you might do this:
if (document.addEventListener) {
document.addEventListener('mousemove', activityHandler.flagActivity, false);
}
else if (document.attachEvent) {
document.attachEvent('onmousemove', activityHandler.flagActivity);
}
else {
document.onmousemove = activityHandler.flagActivity;
}
2. Use a timer you reset every time there's "activity".
This is less ongoing work (we don't have something happening every second), but more work when you flag that activity has happened.
Set up a timer to do the refresh:
var handle = setTimeout(function() {
location.reload();
}, 180000);
...and then cancel and reschedule any time you see whatever you consider to be "activity":
clearTimeout(handle);
handle = setTimeout(...);
You can wrap this up in a function:
var inactivityTimerReset = (function() {
var handle = 0;
function reset() {
if (handle != 0) {
clearTimeout(handle);
}
handle = setTimeout(tick, 180000);
}
function tick() {
location.reload();
}
return reset;
})();
// Kick start
inactivityTimerReset();
// ...and anywhere you see what you consider to be activity, call it
// again
inactivityTimerReset();
Then, again, ping it on every activity. But this is a lot more work than I'd put in a mousemove handler, hence solution #1 above.
var docTimeOut;
function bodyTimeOut()
{
docTimeOut=setTimeout(function(){location.reload();},18000);
}
function resetTimeOut()
{
clearTimeout(docTimeOut);
bodyTimeOut();
}
document.onload = bodyTimeOut;
document.body.onmouseover= resetTimeOut;
you could declare a variable pageActive or something, set it to false, and whenever user does something set it to true.
Then, set a function to execute periodically as frequently as you want with setinterval() that checks this variable, if it's true set it to false to start again, if is false then refresh page.
You can use onblur and onfocus on body element to see if there is a kind of activity on your page.

Categories

Resources