0

Basically what I'm trying to accomplish is removing an event handler from a button element (with removeEventListener method) and replacing it with another on first click (with addEventListener method), and so when clicked from time to time again, it keeps switching back and forth from its original event handler function to its alternate.

Theoretically, the function counter() outputs all numbers up from 0 indefinitely in a paragraph element onclick until the user clicks the button element again (count ceases with function altFunc(). And to continue the count after ceasing it, the user simply clicks the button element again, and can stop and continue as many times as the user pleases.

What I've tried:

var a = 0;

var b = setInterval(execute_counter, 1000);

function add() {

    return a += 1;

}

function counter() {

    document.getElementsByTagName('BUTTON')[0].removeEventListener('click', counter);

    document.getElementsByTagName('BUTTON')[0].addEventListener('click', altFunc);

    setInterval(execute_counter, 1000);

    function execute_counter() {

        document.getElementsByTagName('P')[0].innerHTML = add();

    }

}

function altFunc() {

    document.getElementsByTagName('BUTTON')[0].removeEventListener('click', altFunc);

    document.getElementsByTagName('BUTTON')[0].addEventListener('click', counter);

    clearInterval(b);

}

//This was my first attempt.  Output is just an endless loop.

//Second attempt follows utilizing a switch statement belonging to function changeOver() containing the remove and add eventListener methods:

var a = 0;

var b = setInterval(execute_counter, 1000);

function add() {

    return a += 1;

}

function counter() {

    setInterval(execute_counter, 1000);

    function execute_counter() {

        document.getElementsByTagName('P')[0].innerHTML = add();

        changeOver();

    }

}

function changeOver() {

    switch(counter() || altFunc()) {

        case counter():

            document.getElementsByTagName('BUTTON')[0].removeEventListener('click', counter);

            document.getElementsByTagName('BUTTON')[0].addEventListener('click', altFunc);

            break;

        case altFunc():

            document.getElementsByTagName('BUTTON')[0].removeEventListener('click', altFunc);

            document.getElementsByTagName('BUTTON')[0].addEventListener('click', counter);

    }

}

function altFunc() {

    clearInterval(b);

}

//Second attempt's output also is an endless loop.

I think that the remove and add event listeners are working, I am not however understanding the logic behind all of it. I'd appreciate answers in helping me understand it as well as resolving this issue. Thank y'all.

...HTML:

<button type="button" onclick="counter()">counter/altFunc</button>

<p></p>
  • This seems really complicated. Can you describe simply what it is you want to achieve? Why would you track the state of something by swapping which function is called? Can't you just track the state with a variable, then in a single function do whatever is needed based on the state? If you describe more clearly what you're trying to achieve, we can give you a much better solution than swapping out event listeners. – ErikE Oct 13 '17 at 20:35
  • does that really produce endless loop? This wont even run. You are calling `execute_counter` which is only defined inside your `counter` function. – xGeo Oct 13 '17 at 21:17
  • It does run. The output of p is all numbers from zero and up. It will not stop despite my attempts. – Scott Miller Oct 16 '17 at 00:42

3 Answers3

0

Your add/remove event listener methods are correctly placed. But you have a few minor errors in your code that are causing it to not work properly. Check the working snippet below (I added comments):

var a = 0;
function add() {
  return a += 1;
}
function execute_counter() {
  document.getElementsByTagName('P')[0].innerHTML = add();
}

// This statement will start execute_counter, so the count will start and it will be printed.
var b = setInterval(execute_counter, 1000);

// Here you define both event listeners:
function counter() {
  document.getElementsByTagName('button')[0].removeEventListener('click', counter);
  document.getElementsByTagName('button')[0].addEventListener('click', altFunc);
  setInterval(execute_counter, 1000);
}

function altFunc() {
  document.getElementsByTagName('button')[0].removeEventListener('click', altFunc);
  document.getElementsByTagName('button')[0].addEventListener('click', counter);
  clearInterval(b);
}

// Here register the 1st event listener, for the 1st click (that will stop the count), instead
// of in the html element:
document.getElementsByTagName('button')[0].addEventListener('click', altFunc);
<button type="button">counter/altFunc</button>
<p></p>

Also, I'd use an id to identify the button element and use getElementById instead.

I recommend you also to read this answer to understand better on DOM events and listeners.

elbecita
  • 2,616
  • 19
  • 28
0

Is your goal to learn about event handlers, or to get your counter working? If you just want a working counter, I believe your approach is way more complicated then it needs to be. I've come up with a simpler one here: https://jsfiddle.net/66fubzpz/2 This uses a recursive function that calls itself when the counting variable is true. Clicking on the button will switch counting from true to false, or false to true.

var count = 0,
  counting = false;

function add() {
  if (counting) {
    count = count + 1;
    document.getElementById('result').innerHTML = count;
    setTimeout(add, 1000);
  }
}

document.getElementsByTagName('button')[0].addEventListener('click', function() {
  counting = !counting;
  add();
})
<p id="result">
  0
</p>
<button>toggle count</button>
Brian Glaz
  • 15,468
  • 4
  • 37
  • 55
  • Thanks for your input. One question though, why the comma instead of a semicolon after `var count = 0`? – Scott Miller Oct 17 '17 at 13:54
  • If you want, you can define more than one `var` at a time, by separating the names with a comma. This is the same as `var count = 0; var counting = false;` – Brian Glaz Oct 17 '17 at 13:58
  • this doesnt work actually. try clicking the button fast for multiple times. – xGeo Sep 18 '18 at 05:58
0

You are making things complicated. If you want a counter which is toggled by a button, there's no need to remove/add listeners. What you can do is to have a variable which you can check to know if the counter is running. clearInterval if it is running on button click and then update the value of running.

var btn = document.getElementById("btn");
var content = document.getElementById("content");
var a = 0;
var myInterval;
var running = false;

function add() {
  return a += 1;
}

function counter() {
  var btnTxt = btn.textContent || btn.innerText;
  if (running) {
    clearInterval(myInterval);
    btn.textContent = "Start";
    running = false;
  } else {
    myInterval = setInterval(updateContent, 1000);
    btn.textContent = "Stop";
    running = true;
  }
}

function updateContent() {
  content.innerHTML = add();

}
<button id="btn" type="button" onclick="counter()">Start</button>

<p id="content">Timer</p>
xGeo
  • 2,149
  • 2
  • 18
  • 39