3

I need to flash an element off and on. This works but I don't really like the code. Is there a nice way of doing this?

setTimeout(function(){
  toggle();
  setTimeout(function(){
    toggle();
    setTimeout(function(){
      toggle();
      setTimeout(function(){
        toggle();
      }, 100);
    }, 100);
  }, 100);
}, 100);

I'm using jQuery too if that helps.

8 Answers 8

4
function toggle_multiple(n)
{
    var toggled = 0;
    function toggle_one_time()
    {
        toggle();
        toggled += 1;
        if (toggled <= n)
            setTimeout(toggle_one_time, 100);
    }
    toggle_one_time();
}

And just call toggle_multiple(4).

Sign up to request clarification or add additional context in comments.

2 Comments

toggled=0 probably should have a var to prevent an accidental global.
I'd recommend renaming it to toggle_multiple & pass in the amount as an argument. That way it's a more generic solution.
3

A recursive approach:

function multiTimeoutCall (callback, delay, times) {
    if (times > 0){
      setTimeout(function () {
        callback();
        multiTimeoutCall (callback, delay, times - 1);
      }, delay);
    }
}

Usage:

multiTimeoutCall (toggle, 100, 4);

Edit: Yet another approach, without filling the call stack:

function multiTimeoutCall (callback, delay, times) {
  setTimeout(function action() { // a named function expression
    callback();
    if (--times > 0) {
      setTimeout (action, delay); // start a new timer
    }
  }, delay);
}

I could used arguments.callee instead of a named function expression, but seems that it will be deprecated some day in ECMAScript 5...

Comments

2

Why not use setInterval?

var toggler = function() {
    if (++self.counter >= self.BLINK_AMOUNT * 2) {
        self.counter = 0;
        window.clearInterval(self.timer);
        return;
    }
    toggle();
};
toggler.BLINK_AMOUNT = 1;
toggler.counter = 0;
toggler.timer = window.setInterval(toggler, 100);

I can't remember whether or not IE properly implements the self variable in a timer callback - if it doesn't, use a uniquely named global variable instead.

2 Comments

self is the global (window) object in JavaScript. You are probably thinking of this. And no, this will not point to the toggler on any browser, but since you're just using a function rather than a full method, you can get that from arguments.callee.
Great idea! This is what you call 'thinking outside the box.'! :)
1

I would use a blinking effect. For jquery there's pulsate, hope that works for you.

Comments

1

Here's yet another version for simplicity:

for (var i= 0; i<4; i++)
    setTimeout(toggle, (i+1)*100);

For larger numbers an interval may be more appropriate, but if it's just four toggles multiple timeouts are fine.

1 Comment

if for some reason the browser slowed, or was busy, and couldnt execute one of the setTimeout, then all the timing is thrown off - you cannot guarantee that the toggle function is called (i+1)*100 millisecond apart using this loop.
1

Generalizing 'unknown's' idea of using setInterval,

function schedule(fn, max, delay)
{
    var counter = 0;
    var interval = setInterval(
        function()
        { 
            if(counter++ === max)
                clearInterval(interval);
            fn();
        }

       , delay);
}

Usage:

schedule(toggle, 4, 100);

Comments

0

If its just flashing that is required, why not use the jQuery animate ? I use the following to direct user attention to messages. But you can do this for any element -

$("#message_box").fadeOut(450).fadeIn(350);

If you want it multiple times, do this -

$("#message_box").fadeOut(450).fadeIn(350).fadeOut(450).fadeIn(350);

1 Comment

Actually just saw Toby's reply above. Its a more elegant way. Let me up his reply.
-2

You can do like this:

function toggleMany(cnt) {
   toggle();
   if (--cnt >= 0) window.setTimeout('toggleMany('+cnt+')', 100);
}

toggleMany(4);

4 Comments

remember that eval is evil! window.setTimeout(toggleMany, 100, cnt) is much neater, IMO anyway.
@nickf: Yes, but some browsers have problems with that. A string works everywhere.
-1. You should always pass a proper JS function to setTimeout and not the JS code as string.
Yes, I am aware that a long time back, setTimeout only used to accept JS code as first parameter. But support for function as the first argument has been added since IE5/Netscape4 (Verified from MS and Mozilla's documentation). Nowadays, there is absolutely no reason to pass JS code to setTimeout as I believe that all the current browsers support setTimeout correctly. And even if there was an issue with setTimeout, you should have mentioned the proper solution and posted your version as an alternate workaround if the code doesn't work in the browser the OP is targetting.

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.