1
votes

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!

3
I set up a fiddle of your problem here : jsfiddle.net/jomanlk/PJhjV - JohnP
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. - RobG
That makes lots of sense! For some reason I thought that event handlers could be overwritten. Thanks! - skiddler
Don't forget to accept an answer! Do this by clicking the checkmark next to the answer which helped you the most. - RvdK

3 Answers

1
votes

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.

0
votes

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);
0
votes

move:

handleInput();

to:

document ready function