Search code examples
javascripthtmltimer

I can stop the timer, when I click the pause button, but when I click play again, 2 timers are playing and it is buggy


I can stop the timer, when I click the pause button, but when I click play again, 2 timers are playing and it is buggy. It should resume the timer where it was paused.

let timerSelection = 'Work';
let startingMinutes = 25;
let startingSeconds = 0;
let timerRunning;
let stopTimer;
let playing = false;
let currentMinutes;
let currentSeconds;

//sets the correct timer duration
function setWork() {
    if (playing == false) {
        startingMinutes = 25;
        startingSeconds = 0;
        timerSelection = 'Work'
        document.querySelector("#minutes").innerHTML = '25';
        document.querySelector("#seconds").innerHTML = '00';
    } else {
        return;
    }
}
function setShortBreak() {
    if (playing == false) {
        startingMinutes = 5;
        startingSeconds = 0;
        timerSelection = 'ShortBreak'
        document.querySelector("#minutes").innerHTML = '05';
        document.querySelector("#seconds").innerHTML = '00';
    } else {
        return;
    }
}
function setLongBreak() {
    if (playing == false) {
        startingMinutes = 15;
        startingSeconds = 0;
        timerSelection = 'LongBreak'
        document.querySelector("#minutes").innerHTML = '15';
        document.querySelector("#seconds").innerHTML = '00';
    } else {
        return;
    }
}


//play-button turns into pause button, when it's clicked
function playVisibility() {
    document.getElementById("play").style.visibility = "visible";
    document.getElementById("pause").style.visibility = "hidden";
}




//starts the timer
function timer() {

    document.getElementById("play").style.visibility = "hidden";
    document.getElementById("pause").style.visibility = "visible";

    
    playing = true;
    
    let time = startingMinutes * 60;

    setInterval(updateCoundtdown, 1000);
    time--;

    function updateCoundtdown() {
        if (playing) {
            let minutes = Math.floor(time / 60);
            let seconds = time % 60;

            seconds = seconds < 10 ? '0' + seconds : seconds;
            minutes = minutes < 10 ? '0' + minutes : minutes;

            currentMinutes = minutes;
            currentSeconds = seconds;

            document.querySelector("#minutes").innerHTML = minutes;
            document.querySelector("#seconds").innerHTML = seconds;
            time--;
            console.log(minutes + ':' + seconds);
        } else {
            console.log('Currently:   ' + currentMinutes + ':' + currentSeconds)
            return;
        }
    }
}
body {
    background-color: rgb(32, 32, 32);
}

#play {
    visibility: visible;
    position: inherit;
    top: calc(50% - 40px);
    left: 10%;
    border-style: none;
    background-color: transparent;
    border-radius: 25px;
    height: 80px;
    width: 80px;
}
#play:hover {
    background-color: rgba(31, 31, 31, 0.527);
}

#pause {
    visibility: hidden;
    position: inherit;
    top: calc(50% - 40px);
    left: 10%;
    border-style: none;
    background-color: transparent;
    border-radius: 25px;
    height: 80px;
    width: 80px;
}
#pause:hover {
    background-color: rgba(31, 31, 31, 0.527);
}

.play_img {
    height: 50px;
}

.pause_img {
    height: 50px;
}

.controls {
    position: absolute;
    left: calc(50% - 50px);
    top: 25em;
    height: 100px;
    width: 100px;
    border-radius: 25px;
    border-style: none;
    background-color: #cccccc10;
}

#timer {
    position: absolute;
    left: calc(50% - 175px);
    top: 16em;
    height: 120px;
    width: 350px;
    border-radius: 25px;
    border-style: none;
    background-color: #cccccc10;
}

#minutes {
    position: inherit;
    left: 10px;
    top: 5%;
    color: rgb(16, 203, 131);
    font-size: 100px;
    font-family: 'Varela Round', sans-serif;
}

#seconds {
    position: inherit;
    left: 200px;
    top: 5%;
    color: rgb(16, 203, 131);
    font-size: 100px;
    font-family: 'Varela Round', sans-serif;
}

#doppelpunkt {
    position: inherit;
    left: 160px;
    top: 1%;
    color: rgb(16, 203, 131);
    font-size: 100px;
    font-family: 'Varela Round', sans-serif;
}

.header {
    position: absolute;
    left: calc(50% - 250px);
    top: 5em;
    height: 70px;
    width: 500px;
    border-radius: 25px;
    border-style: none;
    background-color: #cccccc10;
    margin: 0 auto;
}


#work {
    font-size: 20px;
    font-family: 'Varela Round', sans-serif;
    border-style: none;
    background-color: transparent;
    color: #cccccc;
    border-radius: 15px;
    top: calc(50% - 25px);
    width: 140px;
    height: 50px;
    position: inherit;
    left: calc(20% - 70px);
}


#work:focus {
    background-color: rgba(31, 31, 31, 0.527);
}
#work:hover {
    background-color: rgba(31, 31, 31, 0.527);
}


#short_break {
    font-size: 20px;
    font-family: 'Varela Round', sans-serif;
    border-style: none;
    background-color: transparent;
    color: #cccccc;
    border-radius: 15px;
    top: calc(50% - 25px);
    height: 50px;
    width: 140px;
    position: inherit;
    left: calc(50% - 70px);
}

#short_break:focus {
    background-color: rgba(31, 31, 31, 0.527);
}
#short_break:hover {
    background-color: rgba(31, 31, 31, 0.527);
}


#long_break {
    font-size: 20px;
    font-family: 'Varela Round', sans-serif;
    border-style: none;
    background-color: transparent;
    color: #cccccc;
    border-radius: 15px;
    top: calc(50% - 25px);
    height: 50px;
    width: 140px;
    position: inherit;
    left: calc(80% - 70px);
}

#long_break:focus {
    background-color: rgba(31, 31, 31, 0.527);
}
#long_break:hover {
    background-color: rgba(31, 31, 31, 0.527);
}


button:hover {
    cursor: pointer;
    background-color: rgba(31, 31, 31, 0.527);
}

::selection {
    background: transparent;
}




@media (max-height: 520px) {
    .controls {
        top: 6.8em;
        left: calc(62.7% - 50px);
    }
    #timer {
        top: 8em;
        left: calc(46% - 175px)
    }
    .header {
        top: 1.5em;
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Varela+Round&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="style.css">
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="main.js"></script>

    <button id="timer">
        <div id="minutes">25</div> 
        <div id="seconds">00</div> 
        <div id="doppelpunkt"> : </div>
    </button>

    <header class="header">
        <button id="work" onclick="setWork()">Work</button>
        <button id="short_break" onclick="setShortBreak()">Short Break</button>
        <button id="long_break" onclick="setLongBreak()">Long Break</button>
    </header>
    <nav class="controls">
        <button id="play" onclick="timer();"><img class="play_img" src="play.png"></button>
        <button id="pause" onclick="playVisibility(); playing = false"><img class="pause_img" src="pause.png"></button>
    </nav>

</body>
</html>


Solution

  • Every time you run timer() (click the play button), setInterval(updateCoundtdown, 1000); gets called again and updateCoundtdown() keeps getting called multiple times per second.

    You need to clear the previous interval before you start a new one.

    let updateCoundtdownIntervalHandle = null;
    // ...
    function playVisibility() {
        // on pause clear the interval.
        if (updateCoundtdownIntervalHandle !== null) {
            clearInterval(updateCoundtdownIntervalHandle);
            updateCoundtdownIntervalHandle = null;
        }
        // ...
    }
    
    function timer() {
        // ...
        // if old interval is still running for some reason, clear it
        if (updateCoundtdownIntervalHandle !== null) {
            clearInterval(updateCoundtdownIntervalHandle);
        }
        updateCoundtdownIntervalHandle = setInterval(updateCoundtdown, 1000);
        // ...
    }
    

    let timerSelection = 'Work';
    let startingMinutes = 25;
    let startingSeconds = 0;
    let timerRunning;
    let stopTimer;
    let playing = false;
    let currentMinutes;
    let currentSeconds;
    let updateCoundtdownIntervalHandle = null;
    
    //sets the correct timer duration
    function setWork() {
        if (playing == false) {
            startingMinutes = 25;
            startingSeconds = 0;
            timerSelection = 'Work'
            document.querySelector("#minutes").innerHTML = '25';
            document.querySelector("#seconds").innerHTML = '00';
        } else {
            return;
        }
    }
    function setShortBreak() {
        if (playing == false) {
            startingMinutes = 5;
            startingSeconds = 0;
            timerSelection = 'ShortBreak'
            document.querySelector("#minutes").innerHTML = '05';
            document.querySelector("#seconds").innerHTML = '00';
        } else {
            return;
        }
    }
    function setLongBreak() {
        if (playing == false) {
            startingMinutes = 15;
            startingSeconds = 0;
            timerSelection = 'LongBreak'
            document.querySelector("#minutes").innerHTML = '15';
            document.querySelector("#seconds").innerHTML = '00';
        } else {
            return;
        }
    }
    
    
    //play-button turns into pause button, when it's clicked
    function playVisibility() {
        clearInterval(updateCoundtdownIntervalHandle);
        document.getElementById("play").style.visibility = "visible";
        document.getElementById("pause").style.visibility = "hidden";
    }
    
    
    
    
    //starts the timer
    function timer() {
    
        document.getElementById("play").style.visibility = "hidden";
        document.getElementById("pause").style.visibility = "visible";
    
        
        playing = true;
        
        let time = startingMinutes * 60;
        if (updateCoundtdownIntervalHandle !== null) {
            clearInterval(updateCoundtdownIntervalHandle);
        }
        updateCoundtdownIntervalHandle = setInterval(updateCoundtdown, 1000);
        time--;
    
        function updateCoundtdown() {
            if (playing) {
                let minutes = Math.floor(time / 60);
                let seconds = time % 60;
    
                seconds = seconds < 10 ? '0' + seconds : seconds;
                minutes = minutes < 10 ? '0' + minutes : minutes;
    
                currentMinutes = minutes;
                currentSeconds = seconds;
    
                document.querySelector("#minutes").innerHTML = minutes;
                document.querySelector("#seconds").innerHTML = seconds;
                time--;
                console.log(minutes + ':' + seconds);
            } else {
                console.log('Currently:   ' + currentMinutes + ':' + currentSeconds)
                return;
            }
        }
    }
    body {
        background-color: rgb(32, 32, 32);
    }
    
    #play {
        visibility: visible;
        position: inherit;
        top: calc(50% - 40px);
        left: 10%;
        border-style: none;
        background-color: transparent;
        border-radius: 25px;
        height: 80px;
        width: 80px;
    }
    #play:hover {
        background-color: rgba(31, 31, 31, 0.527);
    }
    
    #pause {
        visibility: hidden;
        position: inherit;
        top: calc(50% - 40px);
        left: 10%;
        border-style: none;
        background-color: transparent;
        border-radius: 25px;
        height: 80px;
        width: 80px;
    }
    #pause:hover {
        background-color: rgba(31, 31, 31, 0.527);
    }
    
    .play_img {
        height: 50px;
    }
    
    .pause_img {
        height: 50px;
    }
    
    .controls {
        position: absolute;
        left: calc(50% - 50px);
        top: 25em;
        height: 100px;
        width: 100px;
        border-radius: 25px;
        border-style: none;
        background-color: #cccccc10;
    }
    
    #timer {
        position: absolute;
        left: calc(50% - 175px);
        top: 16em;
        height: 120px;
        width: 350px;
        border-radius: 25px;
        border-style: none;
        background-color: #cccccc10;
    }
    
    #minutes {
        position: inherit;
        left: 10px;
        top: 5%;
        color: rgb(16, 203, 131);
        font-size: 100px;
        font-family: 'Varela Round', sans-serif;
    }
    
    #seconds {
        position: inherit;
        left: 200px;
        top: 5%;
        color: rgb(16, 203, 131);
        font-size: 100px;
        font-family: 'Varela Round', sans-serif;
    }
    
    #doppelpunkt {
        position: inherit;
        left: 160px;
        top: 1%;
        color: rgb(16, 203, 131);
        font-size: 100px;
        font-family: 'Varela Round', sans-serif;
    }
    
    .header {
        position: absolute;
        left: calc(50% - 250px);
        top: 5em;
        height: 70px;
        width: 500px;
        border-radius: 25px;
        border-style: none;
        background-color: #cccccc10;
        margin: 0 auto;
    }
    
    
    #work {
        font-size: 20px;
        font-family: 'Varela Round', sans-serif;
        border-style: none;
        background-color: transparent;
        color: #cccccc;
        border-radius: 15px;
        top: calc(50% - 25px);
        width: 140px;
        height: 50px;
        position: inherit;
        left: calc(20% - 70px);
    }
    
    
    #work:focus {
        background-color: rgba(31, 31, 31, 0.527);
    }
    #work:hover {
        background-color: rgba(31, 31, 31, 0.527);
    }
    
    
    #short_break {
        font-size: 20px;
        font-family: 'Varela Round', sans-serif;
        border-style: none;
        background-color: transparent;
        color: #cccccc;
        border-radius: 15px;
        top: calc(50% - 25px);
        height: 50px;
        width: 140px;
        position: inherit;
        left: calc(50% - 70px);
    }
    
    #short_break:focus {
        background-color: rgba(31, 31, 31, 0.527);
    }
    #short_break:hover {
        background-color: rgba(31, 31, 31, 0.527);
    }
    
    
    #long_break {
        font-size: 20px;
        font-family: 'Varela Round', sans-serif;
        border-style: none;
        background-color: transparent;
        color: #cccccc;
        border-radius: 15px;
        top: calc(50% - 25px);
        height: 50px;
        width: 140px;
        position: inherit;
        left: calc(80% - 70px);
    }
    
    #long_break:focus {
        background-color: rgba(31, 31, 31, 0.527);
    }
    #long_break:hover {
        background-color: rgba(31, 31, 31, 0.527);
    }
    
    
    button:hover {
        cursor: pointer;
        background-color: rgba(31, 31, 31, 0.527);
    }
    
    ::selection {
        background: transparent;
    }
    
    
    
    
    @media (max-height: 520px) {
        .controls {
            top: 6.8em;
            left: calc(62.7% - 50px);
        }
        #timer {
            top: 8em;
            left: calc(46% - 175px)
        }
        .header {
            top: 1.5em;
        }
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <link rel="preconnect" href="https://fonts.googleapis.com">
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
        <link href="https://fonts.googleapis.com/css2?family=Varela+Round&display=swap" rel="stylesheet">
        <link rel="stylesheet" href="style.css">
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script src="main.js"></script>
    
        <button id="timer">
            <div id="minutes">25</div> 
            <div id="seconds">00</div> 
            <div id="doppelpunkt"> : </div>
        </button>
    
        <header class="header">
            <button id="work" onclick="setWork()">Work</button>
            <button id="short_break" onclick="setShortBreak()">Short Break</button>
            <button id="long_break" onclick="setLongBreak()">Long Break</button>
        </header>
        <nav class="controls">
            <button id="play" onclick="timer();"><img class="play_img" src="play.png"></button>
            <button id="pause" onclick="playVisibility(); playing = false"><img class="pause_img" src="pause.png"></button>
        </nav>
    
    </body>
    </html>