0

I am doing some long polling (ajax) and I am looping the following portion of code.. There is code being executed above and below. This code is part of an internal messaging system. A certain portion of the page wil blink when a message arrives. If the user checks the message, it will remove the dash_notify from the JSON response, which needs to turn off the blinking. See below:

if (data.dash_notify == '1') {
    var x = '#dash_notif_blink';

    function blinking(x) {
        timer = setInterval(blink, 10);

        function blink() {
            x.fadeOut(400, function () {
                x.fadeIn(400);
            });
        }
    }

    console.log("initiate_dash");
    blinking($(x));
} else if (!data.dash_notify) {
    console.log("good");

    clearInterval(timer);
}

The following JSON response that gets sent to this code is:

{"current_date_time":"January 8, 2013 - 4:02 pm","dash_notify":"1"}

It understand the initial blink IF the above data gets passed. If the following gets passed:

{"current_date_time":"January 8, 2013 - 4:02 pm"}

Then it throws an error:

Uncaught ReferenceError: timer is not defined 

I cannot figure out how to fix the "else" portion working properly. If the code is initiated when the full dash_notify:1 response is sent, it works perfect. The button will blink, then if the user checks the message, it will no longer send dash_notify:1 and the button stops blinking. But if the code is initiated when dash_notify:1 is NOT set, it doesn't know what to do with the ClearInterval.

Basically I need the else portion fixed.

I have tried using different typeOf === undefined snippets, but it doesn't work.

Any help is appreciated.

Thank you!

EDIT:

This is currently working.. Timer is now defined above the statement

if(data.dash_notify == '1'){

                            var x = '#dash_notif_blink';

                        console.log("initiate_dash");
                        blinking($(x));

                        }else if (typeof timer != "undefined" && timer) { 
                            clearInterval(timer);
    }               
                    }

This is working, but sometimes it trys to kill the timer but it doesn't actually do it. This happens every so often.

greycode
  • 113
  • 5
  • 16

5 Answers5

3

Looks like it's not working because timer doesn't exist outside your inner blinking function. I'm making an assumption here that you don't have var timer; somewhere outside the blinking function, which is strongly likely given the error you're getting.

Why this is happening:

If I'm right, and you're not declaring timer anywhere else in your code, then var timer is being implicitly added to the beginning of the blinking function:

function blinking(x) {
    var timer;
    timer = setInterval(blink, 10);

    function blink() {
        x.fadeOut(400, function () {
            x.fadeIn(400);
        });
    }
}

That makes timer a local variable inside blinking. Since you never pass it out of the closure, it doesn't exist once you're outside that function. So either you need to pull timer into the outer context (option 1) or make it available from inside blinking (option 2).

What to do:

If you want access to timer outside of that closure, you'll have to do one of two things:

1: Declare timer outside of blinking:

 var timer = null;
 if (data.dash_notify == '1') {
    var x = '#dash_notif_blink';

    function blinking(x) {
        //etc...

2: Make it the return value of blinking:

var t;

if (data.dash_notify == '1') {
    var x = '#dash_notif_blink';

    function blinking(x) {
        var timer = setInterval(blink, 10); //note the var keyword for best practice

        function blink() {
            x.fadeOut(400, function () {
                x.fadeIn(400);
            });
        }

        return timer;
    }

    console.log("initiate_dash");
    t = blinking($(x));

} else if (!data.dash_notify) {
    console.log("good");    
    clearInterval(t);
}

Either one of these will work, and is more or less the same in terms of polluting the outer namespace. I prefer Option 2, because I feel like it's easier to work with a local variable until you need to return it.


Edit:

Your comment said the loop runs infinitely, which means you're creating a brand new interval and reassigning the timer variable every time. This is a separate problem from the one I described above. The old interval is still out there, timer just doesn't point to it anymore. So how can clearInterval(timer) clear out all those intervals? It can't, it can only clear the most recent one.

Basically, you've got a whole bunch of timers all trying to make the thing blink at once.

How you deal with this depends on what you're trying to do. The simplest thing would be to keep no more than one interval running at once, which means you have to clear timer every time.

//same as option 1 above except for `clearInterval(timer)` at the 
//beginning of `blinking`
var timer = null;

if (data.dash_notify == '1') {
    var x = '#dash_notif_blink';

    function blinking(x) {
        clearInterval(timer); 
        timer = setInterval(blink, 10);

If you need multiple timers running, you'll have to keep track of them all in an array or something:

var timers = [];
//...
   function blinking(x) {
        timers.push(setInterval(blink, 10));
//...
} else if (!data.dash_notify) {
   timers.forEach(function(timer) {
       clearInterval(timer);
   });
}
Justin Morgan - On strike
  • 30,035
  • 12
  • 80
  • 104
  • this doesn't seem to work either! It's almost like it cannot find the timer. It still blinks, and I logged right after the else if, so I know it is trying to clear t. – greycode Jan 08 '13 at 22:15
  • so I am putting in console.log(timer); and I am seeing that a random numbers gets returned from timer function.. shouldn't it have a name? – greycode Jan 08 '13 at 22:22
  • 1
    I removed my quickly typed answer and upvoted this one :) See my comment on the OP question regarding the timer/animation – Mark Schultheiss Jan 08 '13 at 22:29
  • @JustinMorgan Does it help that another page loads in an iframe then the user clicks the button? It seems to have trouble when the iframe loads inside of the parent window with the blinking button. – greycode Jan 08 '13 at 22:38
  • @JustinMorgan I don't need multiple timers. basically I am polling the DB if a message has come through. It will start blinking a button to check a message. If the user dismissed the message either within the app or somewhere else, it write to the database saying it was read. I want the blinking to stop. Anyway I can get this to work properly would do. Someone else said that my blink animation may be screwing with the whole thing too. So the edit - Not sure if that's what I need. A single timer to blink a single button when a message comes through, then stop when its "dismissed" on the db. – greycode Jan 09 '13 at 17:47
  • @JustinMorgan "Cannot call method "forEach" of undefined. I added a few missing brackets also – greycode Jan 09 '13 at 20:34
  • @greycode - Please don't edit the brackets in. I left them out because it's not meant as a stand-alone block, you have to merge it into your code. If you compare it to your code, you'll see that I was just presenting a small snippet. – Justin Morgan - On strike Jan 09 '13 at 21:19
  • @greycode - Also, `forEach` is in the last code block, I meant the one above it. I think you should open a new question for this; as I said in my answer, it's a separate issue from your original one. If you do, let me know and I'll answer it. – Justin Morgan - On strike Jan 09 '13 at 21:25
0

Not sure what you did wrong with your typeof check since you did not actually show the whole code, but it should look something like this:

if (typeof timer != "undefined" && timer) { 
    clearInterval(timer);
}
epascarello
  • 204,599
  • 20
  • 195
  • 236
0

Basically define your variable timer before you enter your checking procedure (loop?):

var timer;

... some code ...

if ( data.dash_notify && data.dash_notify == '1') {
    ...
} else if (!data.dash_notify) {
    clearInterval(timer);
}

You can call clearInterval( whatever ) without any consequences. Even if whatever is null, undefined, string and so on. Just make sure timer exist.

Passing an invalid ID to clearTimeout does not have any effect (and doesn't throw an exception). (MDN)

oleq
  • 15,697
  • 1
  • 38
  • 65
0

You're getting that error because timer is only declared/initialized in the blinking function. In the place where you call clearInterval(timer), timer doesn't exist.

Justin Morgan - On strike
  • 30,035
  • 12
  • 80
  • 104
Eudis Duran
  • 742
  • 3
  • 16
0

This is now working beautifully. *Thank you to everyone who helped!*

if(data.dash_notify === '1' && t === null ){

                    var x = '#dash_notif_blink';

                    function blinking(x) {
                        var timer = setInterval(blink, 10); //note the var keyword for best practice

                        function blink() {
                            x.fadeOut(400, function () {
                                x.fadeIn(400);
                            });
                        }
                        return timer;
                    }

                    console.log('initiate_dash_alert');

                    // Data is passed. Parse to see if dash alert should be called. Secondary protection for
                    // multiple timer creation.
                    if(t){return;}else{t = blinking($(x));}




                }else if (!data.dash_notify){    
                    clearInterval(t);
                    console.log('clear_dash_alert');
                    t = null;
                }else{
                    console.log(t);
                    console.log('no_push_events');

                }                   
greycode
  • 113
  • 5
  • 16