How to get play button to work on Javascript timer

Codepen

I am trying to simply get my play button to function but I don’t know how. I got my pause button to work by adding clearInterval(timer) so I’m guessing I do the opposite of this?

I have tried adding countDown to to playTimer function and tick to the addEventListener but those don’t work. I am also trying to do this without completely rewriting my Javascript code

var startButton = document.getElementById("start");
var startSound = document.getElementById("audio"); 
var timerSound = document.getElementById("timer");
var counter = document.getElementById("counter");
var pausePlay = document.getElementsByClassName("pausePlay");
var pauseButton = document.getElementById("pause");
var playButton = document.getElementById('play');
var middleButtons = document.getElementsByClassName("middleButtons");
var fiveMin = document.getElementById("fiveMin");
var end = document.getElementById("endSess");
var redo = document.getElementById("redo");


function playAudio(){
    startSound.play();
}

// Start button will disappear after click and countDown method will begin
function startTimer(){
    startButton.style.display="none"; 
    counter.style.display = "";
    for (var i = 0; i < pausePlay.length; i++) {
        pausePlay[i].style.display = "block";
      }

    
    countDown(10);
}
// function play(){
   
// }

function countDown(minutes){
    var seconds = 60;
    var mins = minutes;
    function tick(){

        var current_minutes = mins - 1;
        seconds --;

        counter.innerHTML = current_minutes.toString() + ":" + (seconds < 10 ? "0" : "") + String(seconds);
        if(seconds > 0){
            timer = setTimeout(tick, 1);
        } else {
            if(mins > 1){
                countDown(mins - 1);
            }
            else if (mins && seconds === 0 ){
               timerSound.play();
               for (var i = 0; i < pausePlay.length; i++){
                pausePlay[i].style.display = "none";
                }
                options();
            }
        }
    }    
    tick();
  }
// Pause timer
  function pauseTimer(){
    clearInterval(timer);
   
  }
// Continue timer
function playTimer(){
    countDown();
}
 

// Display buttons after timer is finished  
  function options(){
    for(var i = 0; i < middleButtons.length; i++){
        middleButtons[i].style.display = "block";
    }
  }
// Add five minutes to Counter as countdown
  function fiveBreak (){
    for(var i = 0; i < middleButtons.length; i++){
        middleButtons[i].style.display = "none";
    
    }
    for (var i = 0; i < pausePlay.length; i++) {
        pausePlay[i].style.display = "block";
      }
      countDown(5);
  }
// Restart counter to another 25 minutes
  function restartTimer(){
    for (var i = 0; i < pausePlay.length; i++) {
        pausePlay[i].style.display = "block";
      }

      for(var i = 0; i < middleButtons.length; i++){
        middleButtons[i].style.display = "none";
    
    }
    countDown(25);
}

// Start from the beginning with the start timer
  function endSess(){
    for(var i = 0; i < middleButtons.length; i++){
        middleButtons[i].style.display = "none";
        counter.style.display = "none";
    }
     startButton.style.display = "";
  }




startButton.addEventListener('click', startTimer, playAudio);
pauseButton.addEventListener('click', pauseTimer, playAudio );
playButton.addEventListener('click', playTimer, playAudio );
fiveMin.addEventListener('click', fiveBreak );
end.addEventListener('click', endSess);
redo.addEventListener('click', restartTimer);

There are so many scope issues with this project. Far too many globals.

I know you don’t want to redo your javascript,. but I highly recommend you do.

var startButton = document.getElementById("start");
var should never be used.

timer = setTimeout(tick, 1);
timer variable is now global. never do this.

Your play button doesn’t work because of several issues,. but the most obvious one is

function countDown(minutes){
    var seconds = 60;
    var mins = minutes;

and you’re doing:
countDown();

Since you’re not passing any arguments: countDown(minutes) is effectively doing:
var mins = minutes = null;
Which explains why you have NaN displaying.

So how would you recommend I redo my javascript?

First thing I would do is select all your HTML visit

https://www.freeformatter.com/html-formatter.html

paste yours in and copy the beautified version back into your project. It helps people who are reading your code to find bugs quicker.

So that takes care of your HTML.

Next I would incapsulate all your expressions.

Since you’re using es5 style of functions, why not make something like:

function initApp(){

}

initApp();

As a foundation.

Since the first button I see on your page is a start button that’s is where I would start.

function initApp(){
   const $startButton = document.getElementById("start");
   $startButton.addEventListener('click', handleClickStartButton);
}

function handleClickStartButton(){
   
}

The next two buttons I see upon clicking start are a pause & play button

function initApp(){
   const $startButton = document.getElementById("start");
   $startButton.addEventListener('click', handleClickStartButton);
}

function handleClickStartButton(){
   const $pauseButton = document.getElementById("pause");
   const $playButton = document.getElementById('play');

   $pauseButton.addEventListener('click', handleClickPauseButton);
   $playButton.addEventListener('click', handleClickPlayButton);
}

granted you dont have to name it the same way I do., but as you view the code it’s easier to follow.

Your functions shouldn’t get so big as your countdown function. Keep them small and simple.

So besides those things do I keep the code mostly the same? Should I still put in most of the functions I already had?

I would make it like a chain of functions with the root of it beginning in one function.

I wouldn’t declare a variable until it was used.

If you follow the pattern I laid out your code will be much easier to debug.

I’m not going to type up the whole thing, but you want to group things together as they occur.

You’re currently declaring everything at once which would be a nightmare in a large project.

Some of the things you did well was make smaller functions. Plus some of your functions were named well so I really didnt have to read the logic, because they were named well. ie (restartTimer) tells me it restarts your timer. So when the timer restart of your application doesnt work it’s easy to know that the one function I’ll need to fix is restartTimer.

A function like endSess means absolutely nothing to me. If you find your function starting to get too big,. break it up into smaller pieces.

Your countdown function is too big… and the nested if statements are unnecessary.

Keep in mind., my suggestions are a stylistic approach. So it’s really the programmers choice. But the globals definitely have to go!

Nice catch there @camperextraordinaire . I wasn’t aware of that function in codepen’s editor.

The countdown function was some code I copied from GitHub because I didn’t know how to make a timer. Is there a better way to make a timer? Also I’ve never really worked with ES6 that much so I don’t know a whole lot about it

Here is a basic example of one.

function countDown(startTime){
    const timer = setInterval(function(){
        startTime -= 1;
        console.log(startTime);
        if (startTime === 0){
            clearInterval(timer);
        }
    }, 1000);
}

countDown(10);

Do you understand how this works?

A little bit… you pass the startTime argument and you can set that to whatever you want - like 10. Then you set const timer to the built in setInterval function. The setInterval function gets the startTimer argument and then counts down by one by 1000 milliseconds?. If the startTime is set to 0 then it runs the clearInterval function, which I assume pauses my timer?

So I’ve been getting a better understanding on how to reorganize my code. And so far I can say that it has been very well worth it. It is much more simple.
However there are still some things I need help on. Right now I am simply trying to get my countDown function to alert something when I click the startButton and display the pause/play buttons

const $startButton = document.getElementById("start");
// Start button
var startTimer = () => {
    $startButton.addEventListener('click', handleClickStartButton, playAudio, countDown);
    
};

// Plays audio for start, pause, and play buttons 
 var playAudio = () => {
  const $startSound = document.getElementById("audio");
  const $pauseButton = document.getElementById("pause");
  const $playButton = document.getElementById("play");
  $startSound.play();
  $pauseButton.play();
  $playButton.play();
    };
// What happens after start button is clicked 
var handleClickStartButton = () => {
    $startButton.style.display = "none";
    
    const $pausePlay = document.getElementsByClassName("pausePlay");
    const $pauseButton = document.getElementById("pause");
    const $playButton = document.getElementById('play');
    for (var i = 0; i < pausePlay.length; i++) {
        $pausePlay[i].style.display = "block";
    }
    $pauseButton.addEventListener('click', handleClickPauseButton);
    $playButton.addEventListener('click', handleClickPlayButton);
 };
 
 function handleClickPauseButton(){
    
 };

 var countDown = () => {
    alert("timer has started");
 };


startTimer();

Place the functions you want to run inside of handleClickStartButton. Right now you listing them in wrong spot.

target.addEventListener( *type* , *listener[* , *options* ]);

options Optional

An options object that specifies characteristics about the event listener. The available options are:

  • capture : A Boolean indicating that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree.
  • once : A Boolean indicating that the listener should be invoked at most once after being added. If true , the listener would be automatically removed when invoked.
  • passive : A Boolean which, if true , indicates that the function specified by listener will never call preventDefault() . If a passive listener does call preventDefault() , the user agent will do nothing other than generate a console warning. See Improving scrolling performance with passive listeners to learn more.
  • mozSystemGroup : A Boolean indicating that the listener should be added to the system group. Available only in code running in XBL or in the chrome of the Firefox browser.

Doesn’t list allowing multiple functions to be listed.

So I’m on to my countDown function now. I’m able to count down the minutes, but I’m not quite sure about the logic on how to get the seconds to work within the counter div. Here is my countDown function

var countDown = (startTime) => {
    const counter = document.getElementById("counter");
    const seconds = 60;
    const timer = setInterval(function(){
        startTime -= 1;
        seconds --;
        
        counter.innerHTML = startTime.toString() + ":" + (seconds < 10 ? "0" : "") + String(seconds);
        if(startTime === 0){
            clearInterval(timer);
        }
    }, 1);
};

If you broke it down into smaller pieces you might find it easier to do.

Also,. keep in mind setInterval and setTimeout are not exact. They’re async calls so they’re not guaranteed to run the times that you give them. You’re just guaranteed to not run their functions before that time.

If you know how to do minutes then I’m confused as to why you can do seconds.

Nevertheless I’ll demonstrate how to break the problem into smaller pieces.

https://jsfiddle.net/sroxm8ez/4/

<div id="timer">
  <span id="minutes"></span>
  <span id="seperator">:</span>
  <span id="seconds"></span>
</div>

const countDown = ({minutes, seconds}) => {
  if (!minutes && seconds === '00'){
  	const $timer = document.getElementById('timer');
  	$timer.classList.add('red');
  	return;
  }
  
  const myTimer = setTimeout(() => {
   	if (seconds === '00'){
  		minutes = minutes - 1;
    	seconds = 60;
  	}
    seconds = seconds - 1;
    if (seconds < 10){
    	seconds = '0' + seconds;
    }
    document.getElementById('minutes').innerHTML = minutes;
    document.getElementById('seconds').innerHTML = seconds;

  	countDown({minutes, seconds});
  }, 1000);
};

const initApp = () => {
  countDown({
    minutes: 1,
    seconds: 10
  });
};

initApp();

So I am now back to where I initially started in trying to get the pause and play buttons to work. But once again I don’t really know how to get it to function. I’ve asked on Stack and have tried many ways to do this, but nothing works. This is my code so far and Codepen

// Countdown function. After timer hits 0, the 'counter turns red, and gong sounds through timerSound(), and options() runs
const countDown = ({minutes, seconds}) => {
    if (!minutes && seconds === '00'){
        const timer = document.getElementById('counter');
        
        options();
        timerSound();
        return;
}
// Sets timer. Subtracts the minutes set by 1
const myTimer = setTimeout(() => {
    if (seconds === '00'){
       minutes = minutes - 1;
     seconds = 60;
   }
// Subtracts the seconds
 seconds = seconds - 1;
 if (seconds < 10){
     seconds = '0' + seconds;
 }
 document.getElementById('minutes').innerHTML = minutes + " :";
 document.getElementById('seconds').innerHTML = seconds;

   countDown({minutes, seconds});
}, 1000);
};

//  Pause button
 const handleClickPauseButton = () => {
    clearInterval();
    const $pauseButton = document.getElementById("pause");
    $pauseButton.disabled = true;
    const $playButton = document.getElementById('play');
    $playButton.disabled = false;
    
   
 };
// Play button 
 const handleClickPlayButton = () => {
    
    const $pauseButton = document.getElementById("pause");
    $pauseButton.disabled = false;
    const $playButton = document.getElementById("play");
    $playButton.disabled = true;
 };

Whenever I tried to change setTimeout to setInterval that only slowed down my timer. And whenever I tried to do something like this

myTimer = setInterval (function, time);

clearInterval (myTimer)

That didn’t really do anything. So I’m at the point where I’m really not sure what else to do. I just need these last two things to work and I’m done with this project