Home > OS >  Counter with clearInterval, not restarting after button click
Counter with clearInterval, not restarting after button click

Time:01-27

There is a word-translation card page which includes:

  1. A 3-second countdown that runs immediately after the page loads and when you move to a new word after press the 'Correct' button.
  2. Word and his translate which appears after 'Excellent' button pressed. This button stops and hide the counter.
  3. Button 'Show answer' which appears if 'Excellent' didn't pressed in 3 sec.
  4. Buttons 'Wrong' and 'Correct' which appears if 'Excellent' or 'Show answer' buttons are pressed.

The problem is how the countdown works (unstable). Sometimes it doesn't restart after clicking "Correct". I tried manage countdown in separate function, but this approach provides much more issues. So now there is a timer that is called globally and a timer that is called when you click on the "Correct" button.I think the problem is near timerId. I will be glad to any comments and ideas on the code.

<div >
    <div >
        <h2 id="primary-word"></h2>
        <h2 id="secondary-word"></h2>
    </div>

    <div >
        <p id="timer-count">3</p>
        <button id="btn-excellent" onClick="excellent()">Excellent!</button>
        <button id="btn-show-answer" onClick="showAnswerF()">Show Answer</button>
        <button id="btn-wrong">Wrong</button>
        <button id="btn-correct" onClick="correctF()">Correct</button>
    </div>
</div>
let currentWord = 0
let timerCount = 3
let fetched_data = {}

async function getDeck () {
    let response = await fetch('/api/deck_words/2/', {
        method: 'get',
        headers: {
            'X-Requested-With': 'XMLHttpRequest',
            'Content-Type': 'application/json'
            }
        }
    )
    let data = await response.json()
    let primaryElement = document.getElementById('primary-word')
    primaryElement.innerText = await data[currentWord]['primary_word']
    let secondaryElement = document.getElementById('secondary-word')
    secondaryElement.innerText = await data[currentWord]['secondary_word']
    return data
}

fetched_data = getDeck()

const getData = async () => {
    return await getDeck()
}

data = getData();

function countDecrease() {
    timerCount --
    if (timerCount > 0) {
        document.getElementById("timer-count").innerHTML = timerCount
    } else {
         hideExcellent()
    }
}

function hideExcellent() {
    showElement(true,'btn-excellent')
    showElement(true,'timer-count')
    showElement(false,'btn-show-answer')
}

let timerId = setInterval(() => countDecrease(), 1000)

setTimeout(() => {
    clearInterval(timerId)
}, 3000)

function showElement(showProperty, elementClass) {
    showProperty = !showProperty
    let element = document.getElementById(elementClass)
    element.style.display = (showProperty  === true) ? "inline-block" : "none";
}

function showAnswerF() {
    showElement(true,'btn-show-answer')
    showElement(false,'secondary-word')
    showElement(false,'btn-wrong')
    showElement(false,'btn-correct')
}

function excellent() {
    showElement(true,'timer-count')
    showElement(true,'btn-excellent')
    showElement(false,'btn-wrong')
    showElement(false,'btn-correct')
    showElement(false,'secondary-word')
    clearInterval(timerId)
    timerCount = 3
}

function correctF() {
    currentWord  
    const changeWords = () => {
        fetched_data.then((data) => {
        document.getElementById('primary-word').innerText = data[currentWord]['primary_word']
        document.getElementById('secondary-word').innerText = data[currentWord]['secondary_word']
        document.getElementById("timer-count").innerText = '3'

        timerCount = 3

        timerId = setInterval(() => countDecrease(), 1000)

        setTimeout(() => {
            clearInterval(timerId)
        }, 3000)
      })
    }
    changeWords()

    let countElement = document.getElementById('timer-count')
    countElement.style.display = "block"
    showElement(false,'btn-excellent')
    showElement(true,'btn-wrong')
    showElement(true,'btn-correct')
    showElement(true,'secondary-word')
}

CodePudding user response:

Here's a countdown. The first count is after 1 second.

let count = 3;

new Array(count).fill(true).forEach((_,i) => { 
  setTimeout(() => console.log('countdown',count - i),(i 1) * 1000)
})

CodePudding user response:

I think this would be better handled with an async function, maybe like so.

const timerCount = document.querySelector("#timer-count")
const reset = document.querySelector("button")

function delay(ms) {
    return new Promise(res => setTimeout(res, ms))
}

async function countDown() {
    for (let i = 3; i >= 0; --i) {
        timerCount.textContent = i
        await delay(1000)
    }
    timerCount.textContent = ""
}

(async function() {
    await countDown()
    reset.addEventListener("click", async function click() {
        await countDown()
        reset.addEventListener("click", click, { once: true })
    }, { once: true })
})()
<p id="timer-count"></p>
<button>Reset</button>

  • Related