1

I've tried to simplify a problem I'm having with the code below. Some of the code relies on jQuery, fyi.

Basically, I expect that when 'New Thing' is clicked, a single alert message will appear. However, if one starts the timer, clicking 'New Thing' results in an unexpected behavior where the number of alert messages that appear is equal to the time elapsed.

This problem is destroying me.

To be thorough, I've included a complete example. I realize it's a bit lengthy.

$(document).ready(function() {
    mainLoop();
});

var counter = 0;
var timerIsOn = 0;
var t;

function mainLoop() {
    handleInput();
    timer();
}

function timerHandle() {
    if (!timerIsOn){
        timerIsOn = 1;
        timer();
    }
}

function timer(){
    if (timerIsOn) {
    t = setTimeout(mainLoop, 1000);
    counter++;
    $("span").text(counter); // To display the elapsed time 
    }
}

// Just simple buttons
function handleInput(){    
    $("#timer").click(timerHandle); 
    $("#new").click(createThing);
}

function Thing() {
    this.talk();
}

Thing.prototype.talk = function() {
    alert("Hello!");
}

function createThing() {
    new Thing;
}

I really appreciate the help!

4
  • I set up a fiddle of your problem here : jsfiddle.net/jomanlk/PJhjV Commented Apr 4, 2011 at 7:30
  • Every time mainLoop is called it calls handleInput, which adds another click listener on the button, so when you click it more than once you get more and more timeouts running, but there is only one "t" to cancel the last one. Commented Apr 4, 2011 at 7:30
  • That makes lots of sense! For some reason I thought that event handlers could be overwritten. Thanks! Commented Apr 4, 2011 at 7:53
  • Don't forget to accept an answer! Do this by clicking the checkmark next to the answer which helped you the most. Commented Apr 4, 2011 at 12:08

3 Answers 3

1

This is because you add multiple eventhandlers to the click event of the buttons

function timer(){
    if (timerIsOn) {
      t = setTimeout(mainLoop, 1000);
      counter++;
      $("span").text(counter); // To display the elapsed time 
    } }

If the timeout fires, it will execute mainLoop. Which will call handleInput and handleInput connect an additional eventhandler to the click event.

function handleInput(){    
     $("#timer").click(timerHandle); 
     $("#new").click(createThing); }

Maining if the timer is running and has fired 3 times. Clicking on #new or #timer will call the appropiate function (timerHandle, createThing) 3 times.

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

1 Comment

Oh, boy! Didn't realize that multiple events could be bound to elements. Looking back, you'd lose a lot of functionality if elements could only retain a single event handler. Thanks
0

The problem is that you register the event handlers numerous times. Every time you call

$("#timer").click(timerHandle);

you register a new event handler. This means, that when the div is clicked, timerHandle will run for so many times as the number you have called the above. You can use unbind to avoid this:

$("#timer").unbind('click');
$("#timer").click(timerHandle);

1 Comment

Thanks! I decided to just move handleInput() to $(document).ready(). I originally thought that I'd have to specially check as to whether or not an event has been triggered. That's silly. When an event fires, it'll let you know regardless of what else is going on.
0

move:

handleInput();

to:

document ready function

2 Comments

Thanks -- this is what I ended up doing.
Ayk: in the future it is better to give an explanation why it is not working then a plain solution.

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.