3

I'm trying to add extra time to a setTimeout() that was started via a separate .on('click') function.

Please follow my code description to understand what is happening

// my control opacity jQuery object
var $controlOpacity = $('#control-opacity');

// when the child button is clicked it reveals my input range slider
$controlOpacity.on('click','BUTTON', function() {

    // this toggles a open class to reveal my input range slider
    $controlOpacity.toggleClass('open');

    // begin the 5 second set timeout function 
    setTimeout(function(){

        // removes the open class to hide my input range slider
        $controlOpacity.removeClass('open');

    }, 5000);

});

// my input range slider inside my control opacity div
$('INPUT', $controlOpacity).change(function() {

    // how can I add another 5 seconds to setTimeout function via this function?

});

So when my input change function fires, I want to be able to add another 5 seconds to the setTimeout function which is currently running via the .on('click') function

I'm sure there is an obvious way to do this but what is the cleanest jQuery solution to achieve this?

Thanks

2 Answers 2

3

You can't change the timeout of an ongoing setTimeout - instead, you'll have to explicitly clearTimeout on the existing timeout, then call setTimeout again with the new duration. For this, you'll need a persistent variable that notes when the next timeout (if any) is due to trigger, and 0 otherwise - when the second listener triggers, check the difference between that variable and Date.now() to figure out how long the new timeout needs to last:

const removeFn = () => {
  $controlOpacity.removeClass('open');
  triggerAt = 0;
};
let timeout;
let triggerAt = 0;

$controlOpacity.on('click','BUTTON', function() {
  $controlOpacity.toggleClass('open');
  timeout = setTimeout(removeFn, 5000);
  // Set triggerAt so we can determine how long the timeout has left later
  triggerAt = Date.now() + 5000;
});

$('INPUT', $controlOpacity).change(function() {
  // Clear the existing timeout, if it exists
  clearTimeout(timeout);
  // If no timeout is running, return early
  if (!triggerAt) return;
  // Figure out how much time was remaining on the existing timeout
  const remaining = triggerAt - Date.now();
  // Set the new timeout for 5000 ms plus however long the old timeout had left
  timeout = setTimeout(removeFn, remaining + 5000);
  triggerAt += 5000;
});

ES5 version:

var removeFn = function() {
  $controlOpacity.removeClass('open');
  triggerAt = 0;
};
var timeout;
var triggerAt = 0;

$controlOpacity.on('click','BUTTON', function() {
  $controlOpacity.toggleClass('open');
  timeout = setTimeout(removeFn, 5000);
  // Set triggerAt so we can determine how long the timeout has left later
  triggerAt = Date.now() + 5000;
});

$('INPUT', $controlOpacity).change(function() {
  // Clear the existing timeout, if it exists
  clearTimeout(timeout);
  // If no timeout is running, return early
  if (!triggerAt) return;
  // Figure out how much time was remaining on the existing timeout
  var remaining = triggerAt - Date.now();
  // Set the new timeout for 5000 ms plus however long the old timeout had left
  timeout = setTimeout(removeFn, remaining + 5000);
  triggerAt += 5000;
});

As your question asks, this extends the existing timeout by 5000 ms - an alternative, which simply clears the existing timeout and sets a new timeout for 5000 ms in the future, will take less code, since you'll only have to keep track of whether the timeout is ongoing, and not how much time it has left:

const removeFn = () => {
  $controlOpacity.removeClass('open');
  running = false;
};
let timeout;
let running = false;

$controlOpacity.on('click','BUTTON', function() {
  $controlOpacity.toggleClass('open');
  timeout = setTimeout(removeFn, 5000);
  running = true;
});
$('INPUT', $controlOpacity).change(function() {
  clearTimeout(timeout);
  if (!running) return;
  timeout = setTimeout(removeFn, 5000);
});

ES5 version:

var removeFn = function() {
  $controlOpacity.removeClass('open');
  running = false;
};
var timeout;
var running = false;

$controlOpacity.on('click','BUTTON', function() {
  $controlOpacity.toggleClass('open');
  timeout = setTimeout(removeFn, 5000);
  running = true;
});
$('INPUT', $controlOpacity).change(function() {
  clearTimeout(timeout);
  if (!running) return;
  timeout = setTimeout(removeFn, 5000);
});

If it's impossible to trigger the change event when the open class is not there, then it gets even easier, since there won't be any need to check whether the timeout is running or not:

const removeFn = () => {
  $controlOpacity.removeClass('open');
};
let timeout;
$controlOpacity.on('click','BUTTON', function() {
  $controlOpacity.toggleClass('open');
  timeout = setTimeout(removeFn, 5000);
});
$('INPUT', $controlOpacity).change(function() {
  clearTimeout(timeout);
  timeout = setTimeout(removeFn, 5000);
});

ES5 version:

var removeFn = function() {
  $controlOpacity.removeClass('open');
};
var timeout;
$controlOpacity.on('click','BUTTON', function() {
  $controlOpacity.toggleClass('open');
  timeout = setTimeout(removeFn, 5000);
});
$('INPUT', $controlOpacity).change(function() {
  clearTimeout(timeout);
  timeout = setTimeout(removeFn, 5000);
});
Sign up to request clarification or add additional context in comments.

7 Comments

Don't suppose you could comment your script so I can understand better, I don't normally use const or let. I would love to know exactly what is going on. Thanks
const and let are basically the same thing as var, except more readable - they have fewer gotchas. A const can't be reassigned, and both const and let variables have block scope rather than (unintuitive) function scope, and aren't hoisted. Best to use const by default, or let when you can't use const. (preferably, never use var)
I'm getting compilling errors with this const removeFn = () => {
What exactly is the error? I'm sure the syntax is correct on any browser that isn't super obsolete (like IE). To support newer syntax for users using obsolete browsers, you can transpile code with Babel first, but that's just a wild guess
I'll transpile the answer to ES5, but I would highly recommend using a modern development environment so as not to cripple yourself - it makes things a whole lot easier when coding. ES6+ is wonderful.
|
1

Similar answer to CertainPerformance, but I'd consider making a function that handles the clearing and setting of the timer for you. Essentially, the point is the same — you can't add time to a timer. You have to clear the timer and restart a new timer.

// my control opacity jQuery object
var $controlOpacity = $('#control-opacity');
var removeOpacityTimer;

function removeOpacity() {
    clearTimeout(removeOpacityTimer);

    // begin the 5 second set timeout function 
    removeOpacityTimer = setTimeout(function(){

        // removes the open class to hide my input range slider
        $controlOpacity.removeClass('open');

    }, 5000);
}

// when the child button is clicked it reveals my input range slider
$controlOpacity.on('click','BUTTON', function() {

    // this toggles a open class to reveal my input range slider
    $controlOpacity.toggleClass('open');

    removeOpacity();
});

// my input range slider inside my control opacity div
$('INPUT', $controlOpacity).change(function() {

    // how can I add another 5 seconds to setTimeout function via this function?
    removeOpacity();
});

4 Comments

Thanks man, this seems easier to understand from my js level of understanding
CertainPerformance's answer more accurately answers your question. However, you probably don't want what you asked for. You should probably keep resetting the timer back to 5 seconds instead of adding time to it.
Yes you do make a valid point but he has given my an reset solution too
Thanks for answer dude and your time but I went with other dudes final solution. Though yours works perfectly great too. +1 Thanks again

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.